2013-08-29 48 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; 
    }