简体   繁体   中英

hasManyThrough laravel relation

I have three table below.

+-----------------+   +---------------------+   +-------------+ 
|    products     |   |  product_countries  |   |  countries  |
+-----------------+   +---------------------+   +-------------+ 
|   id            |   |  id                 |   |   id        |
|   name          |   |  product_id         |   |   name      |
|   description   |   |  country_code       |   |   code      |
+-----------------+   |  other columns      |   +-------------+
                      +---------------------+

hasManyThrough in Country::class model to get all products.

public function products()
{
    return $this->hasManyThrough(
        'App\Product',
        'App\ProductCountry',
        'product_id', // Foreign key on feeds table...
        'id', // Foreign key on articles table...
        'code', // Local key on users table...
        'country_code' // Local key on feeds table...
    );
}

I want products which are related to countries or one country:

$user = \App\Models\Country::find(1);
dd($user->products);

The relation you're describing best suits a many to many, which is usually written in Laravel as a belongsToMany on both sides.

class Product extends Model
{
    public function countries()
    {
        return $this->belongsToMany(Country::class);
    }
}

class Country extends Model
{
    public function products()
    {
        return $this->belongsToMany(Product::class);
    }
}

If you stick to Laravel's naming conventions:

  • Rename product_countries to country_product .
  • In country_product use country_id instead of country_code .

...you should be able to access the relations in the way you expect:

$country = \App\Models\Country::find(1);
dd($country->products);

$countries = \App\Models\Country::with('products')->where(...)->get();
foreach ($countries as $country) {
    dd($country->products);
}

If you don't want to stick to the conventions, you are able to customise how you define the relationships. See Laravel's documentation for further details.


In your case, to specify your relations using your custom table name and the custom field names you can do this:

// In your Product model
return $this->belongsToMany(Country::class, 'product_countries', 'country_code', 'product_id');

// In your Country model
return $this->belongsToMany(Product::class, 'product_countries', 'product_id', 'country_code');

Many-to-many is the correct model relationship. You need to add your custom table name in the second argument if not Eloquent will automatically create for you in alphabetical order (like country_product ). You don't need to create ProductCountry Model because it is only a Pivot table.

You didn't post your migration file, (just by guessing), the recommended is using country_id but if you use the country_code / product_id as foreign keys you need to add it also in the arguments as well as in your migration file like this (also check the official documentation )

 $table->foreign('product_id')->references('id')->on('products');
 $table->foreign('country_code')->references('code')->on('countries');

Try this one...

In your Product model

class Product extends Model
{
   public function countries()
   {
      return $this->belongsToMany('App\Country','product_countries','product_id','country_code');
   }
}

In your Country model

class Country extends Model
{
   public function products()
   {
      return $this->belongsToMany('App\Product','product_countries','country_code','product_id');
   }
}

In your controller

use App\Country;

$products = Country::find(1)->products()->get(); //finding by id or

$products = Country::where('country_code',$value)->with('products')->get(); //finding by code

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM