Laravel:如何向关联函数传递参数?

22

有没有办法在关系函数中传递参数?

我目前有以下代码:

public function achievements()
{
     return $this->belongsToMany('Achievable', 'user_achievements')->withPivot('value', 'unlocked_at')->orderBy('pivot_unlocked_at', 'desc');
}

问题在于,在某些情况下,它不会获取unlocked_at列并返回错误。

我已经尝试过类似以下的操作:

public function achievements($orderBy = true)
{
$result = $this->belongsToMany (...)
if($orderBy) return $result->orderBy(...)
return $result;
}

并称之为:

$member->achievements(false)->(...)

但这样不起作用。有没有办法将参数传递给该函数或以任何方式检查是否正在使用pivot_unlocked_at


11
你所说的做法应该没问题。但请注意,如果你将关系函数作为方法调用而非属性调用,它们的行为会有所不同。如果你将它们作为属性调用,你会得到一个结果集(Collection),但如果你将它们作为方法调用,你会得到一个查询构建器(query builder)。如果你想向它们传递参数,你必须以方法调用的方式调用它们,所以请确保在你的调用代码中加上 ->get()$member->achievements(true)->get()->(...) 相当于 $member->achievements->(...) - alexrussell
4个回答

14

我所做的就是向我的模型添加了一个新属性,然后将我的条件添加到该属性中,就这样简单地完成了。

Class Foo extends Eloquent {
    protected $strSlug;

    public function Relations(){
         return $this->belongsTo('Relation','relation_id')->whereSlug($this->strSlug);
    }
 }

 Class FooController extends BaseController {
     private $objFoo;


     public function __construct(Foo $foo){
         $this->objFoo = $foo
     }

     public function getPage($strSlug){
        $this->objFoo->strSlug = $strSlug;
        $arrData = Foo::with('Relations')->get();
        //some other stuff,page render,etc....
     }
 }

9
你可以简单地创建一个范围,然后在需要时将其添加到构建器实例中。
示例:
User.php
public function achievements()
{
    return $this->hasMany(Achievement::class);
}

Achievement.php

public function scopeOrdered(Builder $builder)
{
    return $builder->orderBy(conditions);
}

然后使用:

//returns unordered collection
$user->achievements()->get();

//returns ordered collection
$user->achievements()->ordered()->get();

你可以在Eloquent文档中了解更多有关作用域的信息。

我可以在ordered()函数中传递参数吗? - Emtiaz Zahid
可以的。 public function scopeOrdered(Builder $builder, string $orderBy) { return $builder->orderBy($orderBy); } - SlyDave

1
你可以更简单、更安全地操作:
当你使用带括号的关系函数时,Laravel 仅会返回查询结果,你需要添加 get() 或 first() 来检索结果。
public function achievements($orderBy = true)
{
if($orderBy) 
    $this->belongsToMany(...)->orderBy(...)->get();
else
    return $this->belongsToMany(...)->get();
}

然后你可以像这样调用它:

$member->achievements(false);

适用于最新版本的Laravel。

5
在进行这个操作时,请注意此方法不再像一个关系一样。您无法将其与其他条件连接在一起。我建议为该方法使用不同的名称,以便清楚地表明这一点,例如 getAchievements() - Jason

-1

我在 Laravel 5.3 上无法使用其他解决方案,只能用另一种方法解决这个问题。具体如下:

实例化一个模型:

$foo = new Foo();

设置新属性:

$foo->setAttribute('orderBy',true);

然后在查询数据时使用 setModel 方法。

Foo::setModel($foo)->where(...)

这将允许您从关系方法中访问属性

public function achievements()
{
if($this->orderBy) 
    $this->belongsToMany(...)->orderBy(...)->get();
else
    return $this->belongsToMany(...)->get();
}

那里有问题。你不能在使用->with函数时使用它,否则会得到Null。因此,它只能用于单个模型,而不能用于批处理。因此,将会有多个查询而不是少数查询。 - AidOnline01
@AidOnline01 只是因为它在你的情况下没有起作用,并不意味着它是错误的。这对我的使用非常有效,我相信它可以解决 OP 的问题。它并不应该被你的负评所抹杀,因为它可以帮助其他人;-) - Andrew
正如我之前所说,这不是一个关系函数,而是一个属性函数,因此最好将其命名为getAchievementsAttribute。您不能使用with函数查询它,因此Model::with('achievements')->get()将失败。话虽如此,我认为这并没有回答作者的问题。 - AidOnline01

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接