I have been trying to create my own chainable method in laravel' eloquent but I'm missing something and not sure what. This may sound a little bit nuts but have a look at my function below to get a better idea of what I'm trying to say.
class Post extends Eloquent{
public static function custom_wh($data){
return static::where_in('categories_id', $data, 'AND');
}
}
//this works fine
$posts = Post::custom_wh(array(1, 2, 3))->get();
//but this says custom_wh is not defined in the query class
$posts = Post::where_in('tags', array(2, 3, 4), 'AND')->custom_wh(array(1, 2, 3))->get();
if I understand correctly then my method is not eligible to chain after another method? So I guess my question is how can I create a chainable method in my model?
P.S I have looked into the laravel's query builder class where I have seen that the chainable methods returns the instance of that object but I couldn't find a way to return the object other than the way I've done in the code above. Any kind of suggestion or advice is highly appreciated. Thanks in advance.
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With