creating a chainable method in laravel
You can do that in Laravel with the "query scopes". You can find the doc here.
You just have to write a function with the prefix scope
and you will be able to chain this method like the other query builder ones :
class Post extends Eloquent {
public function scopeWhereCategories($query, $categories)
{
return $query->whereIn('categories_id', $categories, 'AND');
}
}
$posts = Post::whereCategories([1, 2, 3])->get();
$posts = Post::orderBy('date')->whereCategories([1, 2, 3])->take(5)->get();
OK... This may warp your brain a bit but stick with me. The actual method defined is _where(). So how does both Post::where and $post->where end up calling the _where() method? The answer is 'magic'. :D
PHP has these things called 'magic methods' which enable some very dynamic behaviour. In this case Laravel is using __callStatic() and __call() to handle calls to undefined methods. This enabled the same method to be called statically and non-statically.
public static function __callStatic($method, $parameters)
{
// Create a new instance of the called class, in this case it is Post
$model = get_called_class();
// Call the requested method on the newly created object
return call_user_func_array(array(new $model, $method), $parameters);
}
So basically Post::where() is just shorthand for $post = new Post; $post->where()
From here the request goes to __call() in which there is an array of underscored method names. If the requested method is in the list of underscored names, then $this->_method() is called and returned.
But this is still not the whole story. Drew is correct in that 'where_in' returns a Query object. Most of the ORM chaining methods you are familiar with are actually part of the ORM Query object. Here is the whole process.
- Post::where( ... )
- Post::__callStatic( 'where', ... )
- $post->__call( 'where', ... )
- $query->_call( 'where', ... )
- $query->_where( ... )
The class you want to extend is the Query that is used by Model. There is no way add another method name to the list of underscored methods defined in __call(). You will have to copy __call() in it's entirety into your Query definition in order to enable your new method to have that behaviour.
I have accomplished this in my projects be pointing Eloquent ( the alias for the Laravel model ) to my extended version, enabling all my models to use the extended Query methods.
// application/libraries/mylib/query.php
namespace MyLib;
class Model extends \Laravel\Model {
// Tell \MyLib\Model to use \MyLib\Query instead of Laravels Query
protected function query()
{
return new \MyLib\Query($this);
}
}
// application/libraries/mylib/query.php
namespace MyLib;
class Query extends \Laravel\Database\Eloquent\Query {
function _my_method() { ... }
function __call() { ... }
}
// application/config/application.php
'aliases' => array(
...
'Eloquent' => 'MyLib\\Model',
...
)
http://php.net/manual/en/language.oop5.magic.php https://github.com/laravel/laravel/blob/master/laravel/database/eloquent/model.php#L734 https://github.com/laravel/laravel/blob/master/laravel/database/eloquent/query.php#L274