6

我一直在尝试在 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 的查询构建器类,在其中我看到可链接的方法返回该对象的实例,但除了我在上面的代码中完成的方式之外,我找不到返回对象的方法。任何形式的建议或建议都将受到高度赞赏。提前致谢。

4

5 回答 5

13

你可以在 Laravel 中使用“查询范围”来做到这一点。你可以在这里找到文档。

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

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();
于 2014-01-14T09:53:58.983 回答
12

好的...这可能会使您的大脑有些扭曲,但请坚持下去。实际定义的方法是_where()。那么 Post::where 和 $post->where 最终是如何调用 _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; 的简写。$post->where()

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

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

  • 发布::哪里(...)
  • Post::__callStatic('where', ... )
  • $post->__call('where', ... )
  • $query->_call('where', ... )
  • $query->_where( ... )

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

我在我的项目中实现了这一点,将 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

于 2013-03-03T05:29:00.767 回答
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();

除非你想改变查询类

于 2013-02-25T23:56:35.940 回答
0

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

于 2013-02-28T04:48:51.227 回答
0

实际上,您可以轻松扩展 eloquent builder 并运行:

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

您在我的回答中有说明:Laravel 自定义模型方法

另外,不要为此使用范围,除非您现在确切地在做什么,这在我的回答中也得到了澄清。

于 2018-08-07T06:52:22.347 回答