web-dev-qa-db-ja.com

スルーLaravel Eloquent

3つのテーブルgaragescarssecuritiesがあります。

証券は1台の車を安全に保つものであり、複数の証券を保有することもできますが、1つの証券で1台の車を安全に保つことができます。ガレージは車があり、証券もあります。

私が欲しいのは、すべての証券をリストし、彼がいるガレージの名前を知ることです。問題は、securitiesにはガレージのIDを含む列がなく、安全に保管している車のIDのみがあり、車にはガレージのIDがあるということです。

Laravel EloquentにはhasManyThroughというメソッドがありますが、securitiesにはgarageからcarsのみがあります。

表は次のとおりです。

ガレージテーブル:

-----------------------------------
|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
                        ...
26
yayuj

オブジェクトを正しく関連付けていないようです。それを分解しましょう:

Garageに多くのCarがある場合、CarGarageに属します。この考えを念頭に置いて進めましょう。

  • Garageには多くのCarがあります
  • Carには多くのSecurityがあります
  • SecurityCarに属します
  • GarageにはSecurityを介して多くのCarがあります

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関係をロードします。その後、もう1ステップ進み、Garageモデルの下にロードされたすべてのCarオブジェクトにすべてのSecurity関係をロードします。

次の構文を使用してそれらにアクセスできます。

_$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()などのすべての凝ったメソッドを使用できます。

33
Gufran

最近、同様の問題に遭遇し、次のようなことができました。

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();
    }
}

これにより、証券には1つのガレージ関係があり、次のようなことができます。

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

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

これは元の問い合わせに関連しています。

hasOneThroughはLaravel 5.8で利用可能になります

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

6
danrichards