能否修改由artisan migrate命令创建的模板?

14
我已创建了一个迁移的基类。目前,我运行artisan migrate命令,它会创建一个扩展Migrations文件的新迁移,但是我想包含我的BaseMigration并从那里进行扩展。我一直在手动进行这些更改,但我觉得我在不必要地重复自己。
有没有关于如何让新的迁移自动扩展和加载我的基本迁移的建议?

1
如果有人感兴趣,我做了一个解决 L5+ 问题的包 https://github.com/Kyslik/artisan-stubs - Kyslik
1
值得注意的是,Laravel 7以更加直接的方式解决了这个问题。请参见下面的答案 https://dev59.com/FGEh5IYBdhLWcg3w_Xr5#61772765 - Toby Allen
5个回答

14

在 Laravel 5 中可以以相当合理的方式实现。

继承 MigrationCreator 并重写 getStubPath(),只需从原始类中复制该函数(它将使用您子类的__DIR__)。

<?php

namespace App\Database;

use Illuminate\Database\Migrations\MigrationCreator;

class AppMigrationCreator extends MigrationCreator
{
    public function getStubPath()
    {
        return __DIR__.'/stubs';
    }
}

编写一个服务提供者以使用你自己的子类覆盖 migration.creator(它必须是一个延迟服务提供者,因为你不能用急切的绑定来覆盖延迟的绑定):

<?php

namespace App\Database;

use Illuminate\Support\ServiceProvider;

class AppMigrationServiceProvider extends ServiceProvider
{
    protected $defer = true;

    public function register()
    {
        $this->app->singleton('migration.creator', function ($app) {
            return new AppMigrationCreator($app['files']);
        });
    }

    public function provides()
    {
        return ['migration.creator'];
    }
}
将您的服务提供者添加到config/app.php默认提供者之后。

最后,将vendor/laravel/framework/src/Illuminate/Database/Migrations/stubs复制到您的MigrationCreator子类旁边(在本示例中,它将变为app/Database/stubs),并根据需要编辑模板。

保留DummyClassDummyTable名称,因为它们将使用str_replace()替换为实际的迁移文件。


这可以用相当合乎逻辑的方式完成。虽然我不知道是否会称其为“非常容易” :) - Blizz
请注意,类名AppMigrationServiceProvider非常重要,因为Laravel似乎无法处理我的自定义MigrationServiceProvider。是的,即使它的命名空间肯定不同于内置的命名空间... - mpyw
3
getStubPath()已更改为stubPath() - zrkb
您可能需要执行php artisan config:cache命令以更新您的app.providers缓存。 - Boris D. Teoharov

14

自Laravel 7起,您可以使用php artisan stub:publish命令发布存根文件

发布的存根文件将位于应用程序根目录下的stubs目录中。当您使用Artisan的make命令生成相应的类时,对这些存根文件所做的任何更改都将反映出来。


7

我不认为你可以这样做,因为Laravel从vendor/laravel/framework/src/Illuminate/Database/Migrations/stubs文件夹中获取迁移,并且你不能更改它,但你有一些选择:

1) 创建自己的artisan命令migrate:makemyown

2) 使用 Jeffrey Way's Laravel Generators。他们让你通过以下方式创建迁移:

php artisan generate:migration create_posts_table --fields="title:string, description:text"

如果你只是需要一些字段来开始,而不需要更具体的东西,那么它可以很好地工作。
3)编辑Laravel stubs,但问题是一旦你更新composer,它们可能会被Composer覆盖。

我强烈推荐Jeffrey Way的Laravel Generators。上面的链接已经失效,你应该使用他的版本5生成器,可以在这里找到。 - Eugene van der Merwe
@Antonio “文件夹,你无法更改它”这句话在Option #3中已经解释了如何更改,因此之前的句子增加了不必要的歧义。我可能会将Number 3与警告合并到介绍段落中,并说明在运行“composer update”后将丢失更改。这对读者来说会更清晰明了。顺便说一下,感谢您的答案! - Chad

2

我认为现在还没有办法覆盖这个(现在),但我认为你可以创建自定义命令,使用Laravel的逻辑。这是为Laravel 5创建的。

首先,您需要创建生成器命令 app/Console/Commands/Generator.php

<?php namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Filesystem\Filesystem;
use Symfony\Component\Console\Input\InputArgument;

class Generator extends Command
{

  /**
   * Command name
   *
   * @var string
   */
  protected $name = 'generate';

  /**
   * Command description
   *
   * @var string
   */
  protected $description = 'Custom object generator';

  /**
   * An array with all available generator classes
   *
   * @var array
   */
  protected $types = ['request', 'model', 'middleware'];

  /**
   * Execute command
   *
   * @return mixed
   */
  public function handle()
  {
      $type = $this->argument('type');
      if (!in_array($type, $this->types)) {
          return $this->error('Type must be one of: '.implode(', ', $this->types));
      }

      // Create new instance
      $generatorClass = 'App\Console\Commands\Generators\\'.ucfirst($type);
      $generator = new $generatorClass(new Filesystem());

      // Each generator has "fire" method
      $this->comment($generator->setClassName($this->argument('name'))->fire());
  }

  /**
   * @return array
   */
  public function getArguments()
  {
      return [
          ['type', InputArgument::REQUIRED, 'Type of class to generate: '.implode(', ', $this->types)],
          ['name', InputArgument::REQUIRED, 'Name of class to generate'],
      ];
  }

}

然后,您需要为所有Generators类创建一个抽象类app/Console/Commands/Generators/Generator.php

<?php namespace App\Console\Commands\Generators;

use Illuminate\Console\GeneratorCommand;

abstract class Generator extends GeneratorCommand
{
  // Directory name with whole application (by default app)
  const APP_PATH = 'app';

  /*
   * Name and description of command wont be used
   * Generators Commands are not loaded via Kernel
   * Name and description property has been put just to avoid Exception thrown by Symfony Command class
   */
  protected $name = 'fake';
  protected $description = 'fake';

  /**
   * Class name to generate
   *
   * @var string
   */
  protected $className;

  /**
   * Returns class name to generate
   *
   * @return string
   */
  protected function getNameInput()
  {
      return $this->className;
  }

  /**
   * Returns path under which class should be generated
   *
   * @param string $name
   * @return string
   */
  protected function getPath($name)
  {
      $name = str_replace($this->getAppNamespace(), '', $name);

      return self::APP_PATH.'/'.str_replace('\\', '/', $name).'.php';
  }

  /**
   * Sets class name to generate
   *
   * @param string $name
   * @return $this
   */
  public function setClassName($name)
  {
      $this->className = $name;
      return $this;
  }

  /**
   * Execute command
   *
   * @return string
   */
  public function fire()
  {
      $name = $this->parseName($this->getNameInput());

      if ($this->files->exists($path = $this->getPath($name)))
      {
          return $this->type.' already exists!';
      }

      $this->makeDirectory($path);

      $this->files->put($path, $this->buildClass($name));

      return $this->type.' '.$this->className.' created successfully.';
  }

}

最后,您可以创建第一个生成器类!app/Console/Commands/Generators/Request.php

<?php namespace App\Console\Commands\Generators;

class Request extends Generator
{

  /**
   * Class type to generate
   *
   * @var string
   */
  protected $type = 'Request';

  /**
   * Returns default namespace for objects being generated
   *
   * @param string $rootNamespace
   * @return string
   */
  protected function getDefaultNamespace($rootNamespace)
  {
      return $rootNamespace.'\Http\Requests';
  }

  /**
   * Returns path to custom stub
   *
   * @return string
   */
  public function getStub()
  {
      return base_path('resources').'/stubs/request.stub';
  }

}

不要忘记将生成命令添加到内核app/Console/Kernel.php中:
<?php namespace App\Console;

use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;

class Kernel extends ConsoleKernel {

  /**
   * The Artisan commands provided by your application.
   *
   * @var array
   */
  protected $commands = [
    ...
    'App\Console\Commands\Generator',
    ...
  ];

将您的存根放在 resources/stubs 目录下。让我们为请求生成器创建第一个存根 resources/stubs/request.stub:
<?php namespace {{namespace}};

class {{class}} extends Request
{

  /**
   * @return bool
   */
  public function authorize()
  {
    // CUSTOM LOGIC

    return false;
  }

  /**
   * @return array
   */
  public function rules()
  {
    $rules = [];

    // CUSTOM LOGIC

    return $rules;
  }

}

然后使用 php artisan generate request MyRequest 命令调用。

你可以创建自定义的模型(Model)、中间件(Middleware)、控制器(Controller)等生成器,非常简单 - 你只需要在 app/Commands/Console/Generators 下创建新的生成器类 - 参考 Request.php 生成器,了解它的工作原理!


-4

对于 Laravel 5,您需要编辑以下其中一个 .stub 文件:

vendor/laravel/framework/src/Illuminate/Database/Migrations/stubs

你完全可以编辑这些文件,没有任何理由不能这样做。

vendor/laravel/framework/src/中搜索.stub文件,以找到Artisan使用的所有其他桩(模板)。


8
这是一种不好的做法,你应该尽量避免编辑你没有所有权的库。例如,如果有一个新版本的Laravel,你想要升级到它,那么你实际上不能这样做,否则会丢失你所做的更改。 - Subash
你应该重写文件,而不是更新来自供应商的原始文件,因为它会被 Laravel 的更新所覆盖。你不想在 Laravel 更新时每次更新 .stub 文件。 - Player1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接