【问题标题】:Has one through Laravel Eloquent有一个通过 Laravel Eloquent
【发布时间】:2014-12-14 05:07:31
【问题描述】:

我有三张桌子garagescarssecurities

证券是保护一辆车安全的证券,您可以拥有多个安全性,但一个安全性只能保护一辆车的安全。车库是汽车所在的地方,证券也是。

我想要列出所有证券并知道他所在的车库的名称。问题是securities没有包含车库id的列,只有他保护的汽车的id,但汽车有车库的id。

Laravel Eloquent 有一个名为 hasManyThrough 的方法,但 securities 只有一个 garagecars

这是表格:

车库桌:

-----------------------------------
|garage_id|garage_name|garage_size|
-----------------------------------
|        1|   Garage 1|        200|
-----------------------------------
|        2|   Garage 2|        400|
-----------------------------------

汽车表:

---------------------------
|car_id|car_name|garage_id|
---------------------------
|     1|   Car 1|        1|
---------------------------
|     2|   Car 2|        1|
---------------------------
|     3|   Car 3|        2|
---------------------------

证券表:

----------------------------------
|security_id|security_name|car_id|
----------------------------------
|          1|  Security 1|      1|
----------------------------------
|          2|  Security 2|      1|
----------------------------------
|          3|  Security 3|      2|
----------------------------------
|          4|  Security 4|      3|
----------------------------------

输出必须是:

Security 1 is on Garage 1
Security 2 is on Garage 1
Security 3 is on Garage 1
Security 4 is on Garage 2

我有模型:

代码是列出车库,但我想做类似但列出证券(只是为了让您了解结构如何)。

$garages = Garages::with(['cars', 'securities'])->get();

$garages->transform(function($garages) {
    return array(
        'garage_name'      => $garage->garage_name,
        'count_cars'       => $garage->cars->count(),
        'count_securities' => $garage->securities->count(),
   );
});

class Garages extends Eloquent
{
    public function cars()
    {
        return $this->hasMany('cars');
    }

    public function securities()
    {
        return $this->hasMany('securities');
    }
}

class Cars extends Eloquent
{
}

class Securities extends Eloquent
{
}

再次强调一下:我希望车库的名称与保安所保护的汽车相关。

只是为了让它更容易理解,如果我这样做:

$securities = Securities::with(['cars'])->get();

class Securities extends Eloquent
{
    public function cars()
    {
        return $this->hasOne('cars');
    }
}

我只会从cars 表中获得garage_id 作为关系。我真正想要的是车库的名字。

[relations:protected] => Array
    (
        [cars] => Cars Object
            (
                ...
                [attributes:protected] => Array
                    (
                        ...
                        [car_name] => Car 1
                        [garage_id] => 1
                        ...

【问题讨论】:

标签: php laravel laravel-4 eloquent laravel-5


【解决方案1】:

您似乎没有正确关联对象。让我们分解一下:

如果Garage 有很多Car,那么Car 属于Garage,让我们继续考虑这个想法。

  • Garage 有很多 Car
  • Car 有很多 Security
  • Security 属于Car
  • Garage 有很多 SecurityCar

在 Eloquent 中,您可以直接将这些关系加入其中,考虑到您在上面发布的架构,它应该可以工作。

class Garage extends Eloquent
{
    public function cars()
    {
        return $this->hasMany('cars');
    }

    public function securities()
    {
        return $this->hasManyThrough('Security', 'Car');
    }
}

class Car extends Eloquent
{
    public function securities()
    {
        return $this->hasMany('Security');
    }

    // ADDED IN SECOND EDIT

    public function garage()
    {
        return $this->belongsTo('Garage');
    }       
}

class Security extends Eloquent
{
    public function car()
    {
        return $this->belongsTo('Car');
    }
}

应该就是这样。

编辑:您可以从任何模型访问所有这些关系,只要您可以使用这些关系的组合从一个模型绘制到另一个模型的路径。看看这个例子:

$security = Security::with('car.garage')->first();

将首先检索Security 记录并在其上加载Car 关系,然后再向前一步并在Car 模型下加载的每个Car 对象上加载所有Garage 关系。

您可以使用以下语法访问它们:

$security->car->garage->id

// Other examples
$garage = Garage::with('cars.securities')->first();

foreach($garage->cars as $car)
{
    foreach($cars->securities as $security)
    {
        echo "Car {$car->id} has {$security->id} assigned to it";
    }
}

此外,请注意关系对象是Collection 的一个实例,因此您可以使用所有花哨的方法,例如->each()->count()->map()

【讨论】:

  • 我不明白我现在要如何检索车库的名称。因为如果我这样做:$securities = Securities::with(['cars'])->get(); 仍然只返回用户的 ID。
  • 您可以使用点运算符嵌套关系,如下所示:Security::with('car', 'car.garage')
  • @MrAlmighty 我编辑了答案以添加更多信息。再过一遍。
  • 太棒了。非常感谢你。我不知道嵌套关系是可能的。
  • 是的,这很好用 OneThing->haveOtherThing->haveAnotherThing OneThing::where('rules')->with('OtherThing.AnotherThing')->first();
【解决方案2】:

我最近遇到了类似的问题,并且能够做这样的事情:

class Cars extends Eloquent
{
    public function garage()
    {
        return $this->hasOne('Garages');
    }
}

class Securities extends Eloquent
{
    public function car()
    {
        return $this->hasOne('Cars');
    }

    public function garage()
    {
        return $this->car->garage();
    }
}

这使您与证券有一个车库关系,您可以执行以下操作:

$securities = Securities::with('garage')->get();

foreach($securities as $security)
{
    echo $security->security_name . ' is on ' . $security->garage->garage_name;
}

【讨论】:

  • +1:虽然Gufran's answer更加详尽和概括,但这个答案实际上回答了这个问题:如何创建从SecuritiesGarages的hasOne模型关系。
【解决方案3】:

这与您最初的询问有关。

hasOneThrough 将在 Laravel 5.8 中可用

https://github.com/laravel/framework/pull/26057/files

【讨论】:

【解决方案4】:

你可以使用hasOneThrough,集成在 Laravel => 5.8 上。

public function garage()
{
    return $this->hasOneThrough(
        Garage::class,
        Car::class,
        'car_id',
        'id',
        null,
        'garage_id'
    );
}

不要使用类似的解决方案

return $this->car->garage();

因为它使用预先加载,并且您在每次迭代时调用数据库。这些类型的解决方案没有经过优化。

【讨论】:

    猜你喜欢
    • 2016-07-13
    • 1970-01-01
    • 2014-09-30
    • 2015-02-11
    • 2015-08-21
    • 2015-02-11
    • 2014-07-19
    • 2021-12-31
    • 2018-02-10
    相关资源
    最近更新 更多