2013-08-29 44 views
17

我創建使用條件/約束模型博弈的關係如下:如何訪問模型hasMany與哪裏的條件關係?

class Game extends Eloquent { 
    // many more stuff here 

    // relation without any constraints ...works fine 
    public function videos() { 
     return $this->hasMany('Video'); 
    } 

    // results in a "problem", se examples below 
    public function available_videos() { 
     return $this->hasMany('Video')->where('available','=', 1); 
    } 
} 

當以某種方式使用它是這樣的:

$game = Game::with('available_videos')->find(1); 
$game->available_videos->count(); 

一切工作正常,因爲角色是結果採集。

我的問題:

當我嘗試不預先加載,因爲它說「調用一個成員函數count()在非訪問它

$game = Game::find(1); 
$game->available_videos->count(); 

引發異常對象「。

使用

$game = Game::find(1); 
$game->load('available_videos'); 
$game->available_videos->count(); 

工作正常,但似乎相當複雜的我,因爲我並不需要加載相關的模型,如果我沒有我的關係中使用的條件。

我錯過了什麼嗎?我怎樣才能確保,available_videos可以在不使用急切加載的情況下訪問?

任何有興趣,我也張貼了這個問題上http://forums.laravel.io/viewtopic.php?id=10470

+0

在laravel中實現基於角色的用戶管理的最佳方式是使用sentry包。所以試試吧。 – harishannam

+0

正如我在上面的描述中所說的,模型名稱只是一個例子,我的問題與用戶管理無關。我將編輯我的問題併發布我的真實例子。 – Remluben

回答

6

萬一別人遇到了同樣的問題。

請注意,這種關係需要camelcase。所以在我的情況下,available_videos()應該已經可以通過Videos()。

您可以輕鬆地找到調查Laravel來源:

// Illuminate\Database\Eloquent\Model.php 
... 
/** 
* Get an attribute from the model. 
* 
* @param string $key 
* @return mixed 
*/ 
public function getAttribute($key) 
{ 
    $inAttributes = array_key_exists($key, $this->attributes); 

    // If the key references an attribute, we can just go ahead and return the 
    // plain attribute value from the model. This allows every attribute to 
    // be dynamically accessed through the _get method without accessors. 
    if ($inAttributes || $this->hasGetMutator($key)) 
    { 
     return $this->getAttributeValue($key); 
    } 

    // If the key already exists in the relationships array, it just means the 
    // relationship has already been loaded, so we'll just return it out of 
    // here because there is no need to query within the relations twice. 
    if (array_key_exists($key, $this->relations)) 
    { 
     return $this->relations[$key]; 
    } 

    // If the "attribute" exists as a method on the model, we will just assume 
    // it is a relationship and will load and return results from the query 
    // and hydrate the relationship's value on the "relationships" array. 
    $camelKey = camel_case($key); 

    if (method_exists($this, $camelKey)) 
    { 
     return $this->getRelationshipFromMethod($key, $camelKey); 
    } 
} 

這也解釋了爲什麼我的代碼工作,每當我加載之前使用load()方法中的數據。

無論如何,我的例子現在工作完好,$ model-> availableVideos總是返回一個Collection。

+0

不,這不是理由。您應該始終使用帶有下劃線'_的函數名稱,因爲在MVC中,應始終使用'/ controller/function_name'的URL結構。如果您沒有爲該功能設置正確的路由,您將在URL中獲得駱駝式的功能名稱,這不適合搜索引擎優化。 – Vineet

+3

@Vineet對不起,沒有。 MVC與URL結構無關。 routes.php文件定義了從url到控制器的映射。 – Greg

0

有您創建了「角色」的典範。 即使在爲角色創建模型之後,檢查問題是否存在。

+0

感謝您的建議,但我創建了相關模型。正如你可以在我編輯的問題中看到的:在我看來,它與其他模型沒有任何關係,因爲$ game-> videos可以工作,但$ game-> available_videos不是 – Remluben

35

我認爲這是正確的做法:

class Game extends Eloquent { 
    // many more stuff here 

    // relation without any constraints ...works fine 
    public function videos() { 
     return $this->hasMany('Video'); 
    } 

    // results in a "problem", se examples below 
    public function available_videos() { 
     return $this->videos()->where('available','=', 1); 
    } 
} 

然後,你就必須

$game = Game::find(1); 
var_dump($game->available_videos()->get()); 
+0

感謝你的回覆,你的例子完美的工作,但是當我調用$ game-> available_videos() - > get()時會執行此操作。關鍵是,我想使用$ game-> available_videos,因爲我也可以使用$ game->視頻而不會遇到麻煩。據我所知,Eloquent應該加載相關的模型,如果不是之前加載的,或者我錯了? – Remluben

+0

更新函數名稱爲'availableVideos'。如果您只需要視頻來返回可用的視頻,您可以這樣做:'返回$ this-> hasMany('Video') - > where('available','=',1);' –

5

//較低的V4版本的一些

public function videos() { 
    $instance =$this->hasMany('Video'); 
    $instance->getQuery()->where('available','=', 1); 
    return $instance 
} 

// V5

public function videos() { 
    $instance =$this->hasMany('Video'); 
    $instance->where('available','=', 1); 
    return $instance 
} 
+0

好主意,但它是一樣的事情,因爲關係在你的查詢生成器上調用該方法 – peter

+0

是的,現在不需要調用getQuery。需要更低版本 –

+0

對於v5你可以這樣做:'return $ this-> hasMany('Video') - > where('available','=',1);'使它更清潔 –

0

如果你想在關係表上應用條件,你也可以使用其他的解決方案。這個解決方案是從我的最後。

public static function getAllAvailableVideos() { 
     $result = self::with(['videos' => function($q) { 
         $q->select('id', 'name'); 
         $q->where('available', '=', 1); 
        }])      
       ->get(); 
     return $result; 
    }