6

私はlaravelの雄弁な方法で独自のチェーン可能なメソッドを作成しようとしていますが、何かが足りず、何がわからないのです。これは少しおかしなことに聞こえるかもしれませんが、私が言おうとしていることをよりよく理解するために、以下の私の関数を見てください。

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

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() が呼び出されて返されます。

しかし、これはまだすべてではありません。「where_in」が Query オブジェクトを返すという点で Drew は正しいです。よく知っている ORM チェーン メソッドのほとんどは、実際には ORM Query オブジェクトの一部です。これがプロセス全体です。

  • Post::where( ... )
  • Post::__callStatic( 'where', ... )
  • $post->__call( '場所', ... )
  • $query->_call( 'where', ... )
  • $query->_where( ... )

拡張するクラスは、モデルで使用されるクエリです。__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

于 2013-03-03T05:29:00.767 に答える
0

「静的」の代わりに「自己」を使用してみましたか? 私の知る限り、自己と属性/メソッドを使用し、サブクラスを使用し、参照しているメソッドがメインクラスの属性/メソッドをオーバーライドしない場合、この場合はメソッド「where_in」が返されます' クエリ クラスの。そして、カスタム メソッドを連鎖させることができます。

于 2013-02-28T04:48:51.227 に答える
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 に答える