在laravel中创建一个可链接的方法

时间:2013-02-25 15:48:52

标签: php laravel eloquent

我一直试图在laravel'eloquent创建我自己的可链接方法,但我错过了一些东西,不知道是什么。这可能听起来有点疯狂,但看看下面我的功能,以便更好地了解我想说的内容。

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();

如果我理解正确,那么我的方法不符合另一种方法的链接?所以我想我的问题是如何在我的模型中创建一个可链接的方法?

PS我已经查看了laravel的查询构建器类,其中我看到可链接的方法返回该对象的实例但我找不到返回对象的方法,而不是我在代码中完成的方式以上。任何建议或建议都非常感谢。提前谢谢。

5 个答案:

答案 0 :(得分:12)

自从您提出问题以来,Laravel提供了一种新方法,称为“查询范围”。您可以找到文档here

您只需编写一个前缀为scope的函数,您就可以像其他查询构建器一样链接此方法:

class Post extends Eloquent {

    public function scopeWhereCategories($query, $categories)
    {
        return $query->whereIn('categories_id', $categories, 'AND');
    }

}

$posts = Post::whereCategories(array(1, 2, 3))->get();
$posts = Post::orderBy('date')->whereCategories(array(1, 2, 3))->take(5)->get();

答案 1 :(得分:11)

好的......这可能会使你的大脑稍微弯曲,但坚持下去。定义的实际方法是_where()。那么Post :: where和$ post->如何最终调用_where()方法呢?答案是'魔术'。 :d

PHP有一些称为“魔术方法”的东西,可以实现一些非常动态的行为。在这种情况下,Laravel使用__callStatic()和__call()来处理对未定义方法的调用。这使得可以静态和非静态地调用相同的方法。

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);
}

所以基本上Post :: where()只是$ post = new Post的简写; $后化合物其中()

从这里请求转到__call(),其中有一个强调的方法名称数组。如果请求的方法位于下划线名称列表中,则调用并返回$ this-> _method()。

但这仍然不是全部。 Drew是正确的,因为'where_in'返回一个Query对象。您熟悉的大多数ORM链接方法实际上是ORM Query对象的一部分。这是整个过程。

  • Post :: where(...)
  • 发布:: __ callStatic('where',...)
  • $ post-> __ call('where',...)
  • $ query-> _call('where',...)
  • $ query-> _where(...)

要扩展的类是Model使用的Query。无法将另一个方法名称添加到__call()中定义的下划线方法列表中。您必须将__call()全部复制到您的查询定义中,以便使您的新方法具有该行为。

我在我的项目中完成了这项工作,将Eloquent(Laravel模型的别名)指向我的扩展版本,使我的所有模型都能使用扩展的Query方法。

// 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

答案 2 :(得分:0)

不确定我是否准确但这是我想出的快速...

Post :: where_in()没有返回Eloquent模型,它返回Query类型的对象。

为了简单地编写自定义函数,我会避免使用函数

$posts = Post::where_in('tags', array(2, 3, 4))->where_in('categories_ids', array(1,2,3))->get();

从我的头顶

你可以试试像

这样的东西
class Post extends Eloquent {
    public static function custom_wh($data=array()) {
        return static::where_in('categories_id', $data);
        // return type of query not eloquent
    }
}

$posts = Post::custom_wh(array(1,2,3))->where_in('tags', array(2, 3, 4))->get();

除非您想要更改查询类

答案 3 :(得分:0)

你尝试过使用'self'而不是'static'吗?据我所知,如果你使用self和属性/方法,你的子类和你引用的方法不会覆盖主类属性/方法,它将返回,在这种情况下,方法'where_in '查询类。然后,您将能够链接自定义方法。

答案 4 :(得分:0)

实际上,您可以轻松扩展雄辩的生成器,然后运行:

$posts = Post::custom_wh(array(1, 2, 3))->get();

您在这里的回答中有指示:Laravel Custom Model Methods

此外,请勿使用范围,除非您现在正是在做什么,这在我的回答中也得到了澄清。