Home » Php » php – Laravel Datatable ManyToMany relationship with multiple tables

php – Laravel Datatable ManyToMany relationship with multiple tables

Posted by: admin July 12, 2020 Leave a comment

Questions:

Offer.php #model

use App\OfferCategory;
use App\OfferCountries;
use App\OfferCreative;
use App\OfferTools;
use App\OfferTraffic;

class Offer extends Model {
public function offer_countries() {
    return $this->belongsToMany(OfferCountries::class);
}

public function offer_categories() {
    return $this->belongsToMany(OfferCategory::class);
}

public function offer_creatives() {
    return $this->hasMany(OfferCreative::class);
}

public function offer_tools() {
    return $this->hasMany(OfferTools::class);
}

public function offer_traffic() {
    return $this->hasMany(OfferTraffic::class);
}

public function platforms() {
    return $this->hasMany(Platform::class);
}

}

OfferController.php

 public function getMediaData() {
//        $model = Offer::with('offer_traffic');
//        return DataTables::eloquent($model)
//                        ->addColumn('traffic', function (Offer $user) {
//                            return $user->offer_traffic->map(function($post) {
//                                        return str_limit($post->allowed_traffic, 30, '...');
//                                    })->implode('<br>');
//                        })
//                        ->toJson();

        return datatables(DB::table('offers'))->toJson();
    }

I want to use all relation table given in offer.php and image in data table. I have tried with commented code in the controller but not able to get please help me to know where I’m doing wrong.

OfferCountries.php #model

use App\Offer;

class OfferCountries extends Model {

   function offers() {
         return $this->belongsToMany(Offer::class);
    }
}

Database schema

How to&Answers:

Here is how i would do,

In Offer.php

 class Offer extends Model {
    public function offer_countries() {
        return $this->hasMany(OfferOfferCountries::class,'offer_id','id');
    }

    public function offer_categories() {
        return $this->hasMany(OfferOfferCategories::class,'offer_id','id');
    }

    public function offer_creatives() {
        return $this->hasMany(OfferCreative::class,'offer_id','id');
    }

    public function offer_tools() {
        return $this->hasMany(OfferTools::class,'offer_id','id');
    }

    public function offer_traffic() {
        return $this->hasMany(OfferTraffic::class,'offer_id','id');
    }

    public function platforms() {
        return $this->hasMany(Platform::class,'offer_id','id');
    }
  }

In OfferOfferCountries.php

class OfferOfferCountries extends Model {
   public function countryDetail(){
     return $this->belongsTo(OfferCountries::class,'offercountry_id','id');
   }
}

In OfferOfferCategory.php

class OfferOfferCategory extends Model {
   public function categoryDetail(){
     return $this->belongsTo(OfferCategory::class,'offercategory_id','id');
   }
}

Now in the controller

public function getMediaData() {
        $data = Offer::with('offer_countries.countryDetail','offer_categories.categoryDetail','offer_creatives','offer_tools','offer_traffic','platforms')->get();

echo '<pre>';
print_r($data);

}

This should give you an array of objects of everything. You can use pivot table but I like this way.

Answer:

I suppose Laravel can’t handle your relations automatically because of non-standard relation fields in your DB (offer_id in many cases instead of default primary key)

To fix this you must manually provide field names on top of which relations must be built.

Offer.php

class Offer extends Model
{
    public function offer_countries()
    {
        // Here we provide parent key field name (offer_id) because we don't want to use the primary key for that
        return $this->belongsToMany(OfferCountries::class, null, null, null, 'offer_id');
    }

    public function offer_categories()
    {
        return $this->belongsToMany(OfferCategory::class, null, null, null, 'offer_id');
    }

    public function offer_tools()
    {
        // Map foreign key to local one 
        return $this->hasMany(OfferTools::class, 'offer_id', 'offer_id');
    }

    public function offer_traffic()
    {
        return $this->hasMany(OfferTraffic::class, 'offer_id', 'offer_id');
    }

    //...
}

And the last model is OfferCountries and offers relation. We must provide relatedKey argument to tell Eloquent in which field to look for foreign key:

OfferCountries.php

class OfferCountries extends Model
{
    function offers()
    {
        return $this->belongsToMany(Offer::class, null, null, null, null, 'offer_id');
    }
}

Related documentation:

https://laravel.com/docs/5.8/eloquent-relationships#one-to-many

https://laravel.com/docs/5.8/eloquent-relationships#many-to-many

Answer:

You didn’t follow standard naming convention therefore you have to explicitly pass those related keys and table names.

Offer.php

use App\OfferCategory;
use App\OfferCountries;
use App\OfferCreative;
use App\OfferTools;
use App\OfferTraffic;

class Offer extends Model {
 public function offer_countries() {
     return $this->belongsToMany(OfferCountries::class, 'offer_offer_countires', 'offer_id', 'offer_countries_id');
 }

 public function offer_categories() {
     return $this->belongsToMany(OfferCategory::class, 'offer_offer_categories', 'offer_id', 'offer_category_id');
 }

 public function offer_creatives() {
     return $this->hasMany(OfferCreative::class, 'offer_id');
 }

 public function offer_tools() {
     return $this->hasMany(OfferTools::class, 'offer_id');
 }

 public function offer_traffic() {
     return $this->hasMany(OfferTraffic::class, 'offer_id');
 }

 public function platforms() {
     return $this->hasMany(Platform::class, 'offer_id');
 }
}

OfferCountries.php

use App\Offer;

class OfferCountries extends Model {

   function offers() {
         return $this->belongsToMany(Offer::class, 'offer_offer_countires', 'offer_countries_id', 'offer_id');
    }
}