How to replace the Laravel Builder class

2019-02-05 09:19发布

I want to replace the Laravels builder class with my own that's extending from it. I thought it would be as simple as matter of App::bind but it seems that does not work. Where should I place the binding and what is the proper way to do that in Laravel?

This is what I have tried:

my Builder:

    use Illuminate\Database\Eloquent\Builder as BaseBuilder;
    class Builder  extends  BaseBuilder
    {

        /**
         * Find a model by its primary key.
         *
         * @param  mixed  $id
         * @param  array  $columns
         * @return \Illuminate\Database\Eloquent\Model|static|null
         */
        public function find($id, $columns = array('*'))
        {
            Event::fire('before.find', array($this));
            $result = parent::find($id, $columns);
            Event::fire('after.find', array($this));
            return $result;
        }
    }

And next I tried to register the binding in bootstrap/start.php file like this :

$app->bind('Illuminate\\Database\\Eloquent\\Builder', 'MyNameSpace\\Database\\Eloquent\\Builder');
return $app;

3条回答
地球回转人心会变
2楼-- · 2019-02-05 09:22

Both of the answers are correct in some way. You have to decide what your goal is.

Change Eloquent Builder

For example, if you want to add a new method only for eloquent models (eg. something like scopes, but maybe a little more advanced so it’s not possible in a scope)

Create a new Class extending the Eloquent Builder, for Example CustomEloquentBuilder.

use Illuminate\Database\Eloquent\Builder;


class CustomEloquentBuilder extends Builder 
{

    public function myMethod()
    {
        // some method things
    }

}

Create a Custom Model and overwrite the method newEloquentBuilder

use Namespace\Of\CustomEloquentBuilder;
use Illuminate\Database\Eloquent\Model;


class CustomModel extends Model
{

    public function newEloquentBuilder($query)
    {
        return new CustomEloquentBuilder($query);
    }

}

Change Database Query Builder

For example to modify the where-clause for all database accesses

Create a new Class extending the Database Builder, for Example CustomQueryBuilder.

use Illuminate\Database\Query\Builder;


class CustomQueryBuilder extends Builder 
{

    public function myMethod()
    {
        // some method things
    }

}

Create a Custom Model and overwrite the method newBaseQueryBuilder

use Namespace\Of\CustomQueryBuilder;
use Illuminate\Database\Eloquent\Model;


class CustomModel extends Model
{

    protected function newBaseQueryBuilder()
    {
        $connection = $this->getConnection();

        return new CustomQueryBuilder(
            $connection, $connection->getQueryGrammar(), $connection->getPostProcessor()
        );
    }

}

Laravel Version: 5.5 / this code is untestet

查看更多
不美不萌又怎样
3楼-- · 2019-02-05 09:26

The answer above doesn't exactly work for laravel > 5 so I done some digging and I found this!

https://github.com/laravel/framework/blob/5.2/src/Illuminate/Database/Eloquent/Model.php#L1868

use this instead!

protected function newBaseQueryBuilder()
{
    $conn = $this->getConnection();
    $grammar = $conn->getQueryGrammar();
    return new QueryBuilder($conn, $grammar, $conn->getPostProcessor());
}
查看更多
姐就是有狂的资本
4楼-- · 2019-02-05 09:43

Illuminate\Database\Eloquent\Builder class is an internal class and as such it is not dependency injected into the Illuminate\Database\Eloquent\Model class, but kind of hard coded there.

To do what you want to do, I would extend the Illuminate\Database\Eloquent\Model to MyNamespace\Database\Eloquent\Model class and override newEloquentBuilder function.

public function newEloquentBuilder($query)
{
   return new MyNamespace\Database\Eloquent\Builder($query);
}

Then alias MyNamespace\Database\Eloquent\Model to Eloquent at the aliases in app/config/app.php

查看更多
登录 后发表回答