扩展蓝图类?

mpe*_*pen 18 php laravel laravel-4

我想覆盖timestamps()Blueprint类中找到的函数.我怎样才能做到这一点?

例如,

public function up() {
    Schema::create('users', function (Blueprint $table) {
        $table->increments('id');
        $table->string('username')->unique();
        $table->string('password');
        $table->string('email');
        $table->string('name');
        $table->timestamps(); // <-- I want this to call my method instead of the one found in the base Blueprint class
    });
}
Run Code Online (Sandbox Code Playgroud)

Mar*_*der 15

有一个新blueprintResolver函数,它接受一个回调函数,然后返回Blueprint实例.

因此,像这样创建自定义Blueprint类:

class CustomBlueprint extends Illuminate\Database\Schema\Blueprint{

    public function timestamps() {
        //Your custom timestamp code. Any output is not shown on the console so don't expect anything
    }
}
Run Code Online (Sandbox Code Playgroud)

然后调用blueprintResolver返回CustomBlueprint实例的函数.

public function up()
{
    $schema = DB::connection()->getSchemaBuilder();

    $schema->blueprintResolver(function($table, $callback) {
        return new CustomBlueprint($table, $callback);
    });

    $schema->create('users', function($table) {
        //Call your custom functions
    });
}
Run Code Online (Sandbox Code Playgroud)

我不确定是否创建一个新的模式实例 DB::connection()->getSchemaBuilder();是最先进的,但它的工作原理.

您可以另外覆盖Schema外观并默认添加自定义蓝图.

  • 有没有办法在应用程序范围内执行此操作,因此您不必在每次迁移中设置自定义蓝图? (3认同)

Rea*_*ues 7

我同样想以“自动”的方式解决这个问题,因此从 @WesleySmith 的答案中获得灵感来实现一个解决方案,Schema该解决方案涉及覆盖返回自定义Blueprint类的基础外观。

然而,从 Laravel 9 开始,该protected static function getFacadeAccessor()方法现在预计仅返回一个字符串,表示服务容器中的查找键。此更改记录在Laravel 9 升级指南中(搜索“getFacadeAccessor”),这里是对进行此更改的框架的相关提交。升级指南是这样说的:

getFacadeAccessor 方法必须始终返回容器绑定键。在 Laravel 的早期版本中,此方法可以返回一个对象实例;但是,此行为不再受支持。如果您编写了自己的外观,则应确保此方法返回容器绑定字符串。

对于SchemaFacade,此容器绑定键是字符串db.schema(如此处所示尽管Laravel 文档的Facade 类参考中尚未记录它)。

因此,我的Schema类省去了自定义getFacadeAccessor方法并依赖父类返回密钥db.schema,并提供使用静态方法创建自定义模式生成器的逻辑customizedSchemaBuilder

class Schema extends BaseSchema
{
    /**
     * Get a schema builder instance for a connection.
     *
     * @param string|null $name
     *
     * @return Builder
     */
    public static function connection($name): Builder
    {
        return static::customizedSchemaBuilder($name);
    }

    /**
     * Retrieves an instance of the schema `Builder` with a customized `Blueprint` class.
     *
     * @param string|null $name
     *
     * @return Builder
     */
    public static function customizedSchemaBuilder(string|null $name = null): Builder
    {
        /** @var Builder $builder */
        $builder = static::$app['db']->connection($name)->getSchemaBuilder();
        $builder->blueprintResolver(static fn($table, $callback) => new CustomBlueprint($table, $callback));
        return $builder;
    }
}
Run Code Online (Sandbox Code Playgroud)

解析之前的自定义生成器的逻辑getFacadeAccessor应该包含在您的AppServiceProvider方法中register

/**
 * @return void
 */
public function register()
{
    $this->app->bind('db.schema', fn() => Schema::customizedSchemaBuilder());
}
Run Code Online (Sandbox Code Playgroud)

您现在应该能够使用 Laravel 9 在迁移中使用自定义的Schema外观和类。Blueprint


Del*_*D0D 6

Marcel Gwerder 的回答救了我一命。就像一些用户在那里评论的那样,我想知道这是否可以更自动地完成。我的目标同样是覆盖该timestamps方法。经过一番修补后,这就是我最终得到的对我有用的东西:

我在以下位置创建了一个文件app/Classes/Database/Blueprint.php

<?php

namespace App\Classes\Database;


use Illuminate\Support\Facades\DB;
use Illuminate\Database\Schema\Blueprint as BaseBlueprint;

class Blueprint extends BaseBlueprint
{
    /**
     * Add automatic creation and update timestamps to the table.
     *
     * @param  int  $precision
     */
    public function timestamps($precision = 0): void
    {
        $this->timestamp('created_at', $precision)->default(DB::raw('CURRENT_TIMESTAMP'));
        $this->timestamp('updated_at', $precision)->default(DB::raw('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'));
    }
}
Run Code Online (Sandbox Code Playgroud)

我创建了一个文件app/Facades/Schema.php

<?php

namespace App\Facades;

use App\Classes\Database\Blueprint;
use Illuminate\Database\Schema\Builder;
use Illuminate\Support\Facades\Schema as BaseSchema;

class Schema extends BaseSchema
{
    /**
     * Get a schema builder instance for a connection.
     *
     * @param  string|null  $name
     * @return Builder
     */
    public static function connection($name): Builder
    {
        /** @var \Illuminate\Database\Schema\Builder $builder */
        $builder = static::$app['db']->connection($name)->getSchemaBuilder();
        $builder->blueprintResolver(static function($table, $callback) {
            return new Blueprint($table, $callback);
        });
        return $builder;
    }

    /**
     * Get a schema builder instance for the default connection.
     *
     * @return Builder
     */
    protected static function getFacadeAccessor(): Builder
    {
        /** @var \Illuminate\Database\Schema\Builder $builder */
        $builder = static::$app['db']->connection()->getSchemaBuilder();
        $builder->blueprintResolver(static function($table, $callback) {
            return new Blueprint($table, $callback);
        });
        return $builder;
    }
}
Run Code Online (Sandbox Code Playgroud)

在里面config/app.php我更新了 Schema 的别名,如下所示:

'aliases' => [
    'Schema' => App\Facades\Schema::class,
],
Run Code Online (Sandbox Code Playgroud)

现在,在我的迁移中,如下所示,当我调用 时timestamps(),它会调用我覆盖的方法。

<?php

use App\Classes\Database\Blueprint;
use \Illuminate\Database\Migrations\Migration;

class TimestampTest extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     * @throws \Throwable
     */
    public function up(): void
    {
        Schema::connection('mysql')->create('some_table', static function (Blueprint $table) {
            $table->string('some_column')->nullable();
            $table->timestamps();
        });

    }

    // ....
}
Run Code Online (Sandbox Code Playgroud)