Extending Blueprint for SQLite in Laravel 5

2019-08-06 13:41发布

问题:

I have a custom Blueprint class, In order to use it I followed the steps in this gist.

Basically, it says I need to extend a MySqlConnection and use a MySqlBuilder that Laravel conviniently has in the Schema folder.

It worked great for MySQL! The problem is I'm using SQLite for testing, and I need the Bluepint there too, the issue is there is no base SqliteConnection nor SqliteBuilder...

Of course, I get the following Exception:

Argument 1 passed to CreateUsersTable::{closure}() 
must be an instance of MyBlueprint
instance of Illuminate\Database\Schema\Blueprint given

Do I have to write those missing classes myself? Hope not


By the way, this question has been asked here for Laravel 4 but I don't want to bind my Blueprint by hand on every migration...

回答1:

Alrighty, my statement about SQLiteConnection missing was wrong, it does exists and apparantly there's no need for a SQLiteBuilder so MySqlBuilder must be a special exception.

I extended the SQLiteConnection as follows:

use Illuminate\Database\SQLiteConnection as ParentSQLiteConnection;

class SQLiteConnection extends ParentSQLiteConnection
{
    public function getSchemaBuilder() {

        $builder = parent::getSchemaBuilder();

        $builder->blueprintResolver(function($table, $callback){

            return new MyBlueprint($table, $callback);
        });

        return $builder;
    }
}

And then in the service registration:

class MyServiceProvider extends ServiceProvider {

    public function register()
    {
        $this->app->bind('db.connection.sqlite', 'SQLiteConnection');
    }
}

I ommited some parts for brevity, mainly namespaces and where to place the service, but all of that can be deduced or looked up from the gist posted on my question as an example.

Hope this help lost souls find their way in the future.



回答2:

No you don't need to rewrite those classes, you just need to extend Blueprint. Your CreateUsersTable method is also expecting MyBlueprint and getting an instance of Blueprint.

You will need to also extend and rewrite the Schema facade or, just substitute it with your own service provider & binding that extends the default laravel class returned by "Schema"..

E.g see: vendor\laravel\framework\src\Illuminate\Support\Facades\Schema.php Create your own, you will need to replace the getFacadeAccessor to return your version of the object it currently returns. Your version should extend the current version to save on writing every method.

Your version will also need overriden versions of the create etc so that instead of returning Illuminate\Database\Schema\Blueprint it returns an instance of MyBlueprint... MyBlueprint will extend Illuminate\Database\Schema\Blueprint so that you can inherit all of its functionality, and you will then override the methods that should be different.

Now in your app/config/app.php switch out the line:

'Schema'            => 'Illuminate\Support\Facades\Schema',

And instead point the Schema facade to your version.