【问题标题】:creating a chainable method in laravel在 laravel 中创建可链接的方法
【发布时间】:2013-02-25 15:48:52
【问题描述】:

我一直在尝试在 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();

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

P.S 我查看了 laravel 的查询构建器类,在那里我看到可链接的方法返回该对象的实例,但除了我在代码中完成的方式之外,我找不到返回对象的方法多于。任何形式的建议或建议都将受到高度赞赏。提前致谢。

【问题讨论】:

    标签: php laravel eloquent


    【解决方案1】:

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

    您只需编写一个前缀为 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();
    

    【讨论】:

    • 喜欢这个功能并且已经在使用它 :D 我知道当我发布我的问题时这并不存在,但我选择它作为其他像我这样的谷歌用户的正确答案。谢谢。
    • @Alexandre Butynski 第三个参数用于什么? ('categories_id', $categories, 'AND');
    • @DaniyalNasir,我不知道!这只是最初问题的副本。无论如何,它似乎没什么用,因为它是这个参数的默认值......
    • @AlexandreButynski 哦,好吧,但它确实需要 where 运算符作为第三个参数,对吗? 我是 Laravel 新手
    【解决方案2】:

    好的...这可能会让你的大脑有点扭曲,但请坚持下去。实际定义的方法是_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 查询对象的一部分。这是整个过程。

    • 发布::where( ... )
    • 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

    【讨论】:

    • 这解释了很多。老实说,我没有在 php 中研究太多关于 OO 的知识,并且我开始使用框架,因为我认为我会在学习过程中学习 OO,所以是的,这很容易掌握,但是让我用你的技术来尝试一下.如果我在此过程中有任何进一步的问题,我会及时通知您。非常感谢您的帮助。
    【解决方案3】:

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

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

    除非你想改变查询类

    【讨论】:

    • 嗯,这就是我所做的,它可以工作,但问题是 custom_wh 函数不可链接所以假设我有一个巨大的查询需要做几个连接,where 子句所以我想把它们包装起来单独的功能并在需要时将它们链接起来,然后问题就出现了。我试图将它们放入函数中的另一个原因是 ORM 不应该是我的模型,对吧?而且我也试图让我的代码“干燥”。
    【解决方案4】:

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

    【讨论】:

      【解决方案5】:

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

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

      您在我的回答中有说明:Laravel Custom Model Methods

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-01-31
        • 1970-01-01
        • 1970-01-01
        • 2019-12-07
        • 2016-07-01
        • 2015-06-09
        • 2021-01-15
        • 1970-01-01
        相关资源
        最近更新 更多