Get Many Through and reverse in Laravel 9 - laravel

I am building an app that has multiple vendors selling products. I need to isolate the customers who have placed an order with that particular vendor.
I have 3 models; Vendor, Customer, Order.
Vendor 'hasMany' Orders.
Order 'belongsTo' Vendor
Order 'belongsTo' Customer
Customer 'hasMany' Orders
class Vendor extends Model
{
/**
* #return HasMany
*/
public function orders(): HasMany
{
return $this->hasMany(Order::class);
}
}
class Order extends Model
{
/**
* #return BelongsTo
*/
public function customer() : BelongsTo
{
return $this->belongsTo(Customer::class);
}
/**
* #return BelongsTo
*/
public function vendor() : BelongsTo
{
return $this->belongsTo(Vendor::class);
}
}
class Customer extends Model
{
/**
* #return HasMany
*/
public function orders(): HasMany
{
return $this->hasMany(Order::class);
}
}
I would like to get all of the orders for a vendor, something like:
class Vendor extends Model
{
/**
* #return HasManyThrough
*/
public function customers(): HasManyThrough
{
return $this->hasManyThrough(Customer::class, Order::class);
}
}
What is the best way to do this?
I have tried hasManyThrough, however as the relationships are not one directional, it doesn't appear to work.
Edit: Here's the relevant migrations:
Vendor
Schema::create('vendors', function (Blueprint $table) {
$table->id();
$table->string('name')->nullable();
$table->string('logo')->nullable();
$table->string('business_type', 32);
$table->string('address', 128)->nullable();
$table->string('postcode', 16);
$table->bigInteger('town_id')->unsigned()->index();
$table->string('website', 128)->nullable();
$table->string('telephone', 64)->nullable();
$table->tinyInteger('approved')->default(0);
$table->timestamps();
});
Customer
Schema::create('customers', function (Blueprint $table) {
$table->id();
$table->string('email')->unique();
$table->string('first_name');
$table->string('last_name');
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->boolean('is_active');
$table->string('country');
$table->timestamps();
});
Order
Schema::create('orders', function (Blueprint $table) {
$table->id();
$table->string('status')->index();
$table->bigInteger('customer_id')->unsigned()->nullable()->index();
$table->bigInteger('vendor_id')->unsigned()->index()->nullable();
$table->string('reference')->nullable()->unique()->index();
$table->decimal('sub_total')->default(0);
$table->decimal('discount_total')->default(0);
$table->decimal('shipping_total')->default(0);
$table->decimal('tax_total')->default(0);
$table->decimal('grand_total')->default(0);
$table->timestamps();
});

I would like to get all of the orders for a vendor
Then you need to fix your Vendor model as follow (same for Customer model)
class Vendor extends Model
{
public function orders()
{
return $this->hasMany(Order::class);
}
}
If your order belongs to more relationships than now, you should consider Polymorphic Relationships

Related

What eloquent relations to use?

I'm building my first Laravel application and I'm confused about the relations because there are so many relationships.
A user can have multiple players(characters).
Players can play on multiple servers.
Each server has 2 stores(block store, perk store).
Each block store uses a different currency on a different server.
The perk store uses the same currency on all servers but some
products can be bought with server-specific currency.
Players also have a bank and a wallet that contains each currency
that they own.
Each server can have teams(guilds, factions, kingdoms) depending on the game type.
class CreateWalletTable extends Migration
{
public function up()
{
Schema::create('wallets', function (Blueprint $table) {
$table->id();
$table->integer('player_id');
$table->integer('currency_id');
$table->decimal('amount');
$table->timestamps();
$table->foreign('player_id')->references('id')->on('players');
$table->foreign('currency_id')->references('id')->on('currencies');
});
}
}
class Wallet extends Model
{
public function player(): \Illuminate\Database\Eloquent\Relations\BelongsTo
{
return $this->belongsTo(Player::class);
}
public function currency(): \Illuminate\Database\Eloquent\Relations\hasOne
{
return $this->hasOne(Currency::class);
}
}
class CreateCurrenciesTable extends Migration
{
public function up()
{
Schema::create('currencies', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('plural');
$table->string('symbol');
$table->integer('decimals');
$table->boolean('tradable');
$table->timestamps();
});
}
}
class Currency extends Model
{
public function wallet(): \Illuminate\Database\Eloquent\Relations\HasMany
{
return $this->hasMany(Wallet::class);
}
}

(Laravel) Polymorphic relation through pivot table

Let's say, I have an Event model, which has more participants of various models (Player, Coach, Admin) through polymorphic relation and a pivot table (EventParticipant), which also contains a boolean column participate. I want to get participants through $event->participants which retrieves a collection of players, coaches, and admins through a polymorphic relation.
I have something similar created with standard non-polymorphic relation in trainings, like this:
class Training extends Model
{
/**
* Training has more players.
*/
public function players() {
return $this->belongsToMany('App\Player', 'training_player')
->using('App\TrainingPlayer')
->withPivot('participate');
}
}
class TrainingPlayer extends Pivot
{
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'participate' => 'boolean'
];
}
How could this be modified in the case of events, where participants() can be either Player, Coach, or Admin model? (Maybe something with MorphPivot class but I can't imagine how.)
(Instead of player_id (in TrainingPlayer class) which refers to id of the Player model, there are two columns role and rollable_id (in EventParticipant class) which refers to id of the Player, Coach, or Admin model, respectively)
class Event extends Model
{
/**
* Event has more participants (players, coaches, or admins).
*/
public function participants() {
//
}
}
class EventParticipant extends MorphPivot
{
//
}
Any help would be appreciate. :) Thx
I have been looking for something similar and came up with a solution. As per Jonas comment, you can't have different Models in 1 related set but you can have 1 for each model using 1 pivot table.
You can now query this with \App\Team::find(1)->with(['managers', 'users'])->get();
Schema::create('associations', function (Blueprint $table) {
$table->id();
$table->string('association_type');
$table->integer('association_id');
$table->integer('team_id');
$table->integer('meta')->nullable();
$table->timestamps();
});
Schema::create('managers', function (Blueprint $table) {
$table->id();
$table->timestamps();
});
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->timestamps();
});
Schema::create('teams', function (Blueprint $table) {
$table->id();
$table->timestamps();
});
class Manager extends Model
{
public function teams()
{
return $this->belongsToMany('\App\Team', 'associations')->using('App\Association');
}
}
class Team extends Model
{
public function managers()
{
return $this->morphedByMany('App\Manager', 'association')->using('App\Association');
}
public function users()
{
return $this->morphedByMany('App\User', 'association')->using('App\Association');
}
}
class User extends Authenticatable
{
public function teams()
{
return $this->belongsToMany('\App\Team', 'associations')->using('App\Association');
}
}
// App/Association
use Illuminate\Database\Eloquent\Relations\MorphPivot;
class Association extends MorphPivot
{
protected $table = 'associations'; // not sure if this is needed
}

Laravel Relations, Models and Migrations

I have a problem with my relations in laravel:
I have two tables, Languages and Customers.The customer just can have 1 language. These are my migrations and Models:
Migrations:
Schema::create('tbl_customers', function (Blueprint $table){
$table->increments('id');
$table->string('first_name',255);
$table->string('last_name',255);
$table->date('date_of_birth');
$table->string('email',255);
$table->string('phone_number',255);
$table->string('phone_number2',255);
$table->string('password', 255);
$table->unsignedInteger('dealer_id');
$table->string('picture_profile',255);
$table->string('occupation',255);;
//Foreign key
$table->unsignedInteger('language_id');
$table->string('about_me',255);
});
Schema::create('tbl_languages', function (Blueprint $table){
$table->increments('id');
$table->string('language',255);
});
This is the foreign Key:
Schema::table('tbl_customers', function (Blueprint $table){
$table->foreign('language_id')->references('id')
->on('tbl_languages')->onDelete('cascade');
});
These are my Models.
Customer:
class Customer extends Model{
protected $table='tbl_customers';
protected $primaryKey="id";
protected $fillable=['address_id','first_name','last_name','gender_id','date_of_birth','email','phone_number','phone_number2',
'dealer_id','picture_profile','occupation','time_zone_id','language_id','about_me'];
protected $hidden=['password'];
public $timestamps = false;
public function language(){
return $this->hasMany(Language::class);
}}
Language
class Language extends Model{
protected $table='tbl_languages';
protected $primaryKey="id";
protected $fillable=['language'];
public $timestamps=false;
public function customers(){
return $this->belongsToMany(Customer::class);
}}
So, If I make a query I have the next error:
error
why? If the migrations have the standard that Laravel says
If I change the Customer model like this:
public function language(){
return $this->hasMany(Language::class,'id','language_id');
}
It works good, but Languages no.
I wish you guys can help me.
add this to your Customer model:
public function language(){
return $this->belongsTo('App\Language');
}
and this to your Language model:
public function customers(){
return $this->hasMany('App\Customer');
}

How to use relationship in laravel?

I use work with relationship in laravel 5.6.
I create product table with migration:
Schema::create('products', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('slug');
$table->text('description');
$table->string('tags');
$table->string('original_price');
$table->integer('view_order')->default(0);
$table->unsignedInteger('admin_id');
$table->foreign('admin_id')->references('id')->on('admins');
$table->boolean('status');
$table->timestamps();
});
And i create category table with migration:
Schema::create('categories', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->boolean('status');
$table->timestamps();
});
And create product_categories table with migration:
Schema::create('product_categories', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('product_id');
$table->foreign('product_id')->references('id')->on('products');
$table->unsignedInteger('category_id');
$table->foreign('category_id')->references('id')->on('categories');
$table->timestamps();
});
Now, I use Bootstrap Multiselect for categories in one product.
In category model:
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function products()
{
return $this->belongsToMany(Product::class);
}
In Product model:
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function categories()
{
return $this->belongsToMany(Category::class);
}
How to add category_id and product_id in product_categories table with relationship?
Check the documantation related to Many to many Relationships.
Your pivot table doesn't follow Laravel's convention, either update your table name or update your relationships to address this issue.
The convention is the alphabetical order of the two models, thus your pivot table should be named: category_product
If you do not want to update the table name, update your relationships.
public function categories()
{
return $this->belongsToMany(Product::class, 'product_categories')
}
public function products()
{
return $this->belongsToMany(Category::class, 'product_categories')
}
Now to "save an entry to the pivot table" -or in other words: to create the relationship between the two models- you may use attach or sync method.
$product->categories()->attach($category);
$product->categories()->attach([$categoryId1, $categoryId2]);
sync is different.
The sync method accepts an array of IDs to place on the intermediate table. Any IDs that are not in the given array will be removed from the intermediate table.
To detach (delete entry in pivot table), simple use the detach method.
$product->categories()->detach([1, 2]);
Of course, do the same for Category.
Your model names are Product and Category and the derived relational table will be category_product because category came before product in alphabetical order.
You only have to add the pivot table:
public function categories()
{
return $this->belongsToMany(Product::class, 'product_categories')
}
public function products()
{
return $this->belongsToMany(Category::class, 'product_categories')
}
Now for save with relationship:
$product->categories()->attach($category);
$product->categories()->attach([$category_id_1, $category_id_2]);
You only have to add the pivot table:
public function products()
{
return $this->belongsToMany(Product::class, 'product_categories');
}
public function categories()
{
return $this->belongsToMany(Category::class, 'product_categories');
}
By default, laravel derives the table name from the alphabetical order of the related model names. Here your model names are Product and Category and the derived relational table will be category_product because category came before product in alphabetical order. Either you can change the table name or you can override this my mentioning the table name as the second parameter in the relational method as follows.
public function products()
{
return $this->belongsToMany(Product::class, 'product_categories');
}
public function categories()
{
return $this->belongsToMany(Category::class, 'product_categories');
}

Laravel: Eloquent Relationship error

I have a many to many relationship between products and a product_categories tables. Now I want to create a translation table for categories.
But how do I relate them in eloquent? i am learning database relationships so forgive my ignorance.
Here is my tables:
//languages
Schema::create('locales', function(Blueprint $table)
{
$table->increments('id');
$table->string('code', 2);
$table->string('name');
});
//products
Schema::create('products', function(Blueprint $table)
{
$table->increments('id');
$table->string('thumbnail');
$table->timestamps();
});
//categories
Schema::create('product_categories', function(Blueprint $table)
{
$table->increments('id');
$table->string('category');
});
//relationship table
Schema::create('product_productcategory', function(Blueprint $table)
{
$table->integer('product_id')->unsigned()->index(); // the id of the bear
$table->foreign('product_id')->references('id')->on('products');
$table->integer('product_category_id')->unsigned()->index(); // the id of the picnic that this bear is at
$table->foreign('product_category_id')->references('id')->on('product_categories');
});
//category translations
Schema::create('category_translations', function(Blueprint $table)
{
$table->increments('id');
$table->string('name');
$table->integer('category_id')->unsigned();
$table->foreign('category_id')->references('id')->on('product_categories')->onDelete('cascade');
$table->integer('locale_id')->unsigned();
$table->foreign('locale_id')->references('id')->on('locales')->onDelete('cascade');
$table->unique(['category_id', 'locale_id']);
});
Product Model:
class Product extends Model
{
protected $table = 'products';
public function product_category() {
return $this->belongsToMany('App\product_category', 'product_productcategory')->translation(1);
}
}
Product categories:
class product_category extends Model
{
protected $table = 'product_categories';
public function product() {
return $this->belongsToMany('App\Product', 'product_productcategory');
}
}
Category Translations
class Category_Translation extends Model
{
protected $table = 'category_translations';
public function product_category() {
return $this->belongsTo('App\product_category');
}
}
But when i run:
$product = App\Product::find(1)->first();
echo $product->product_category;
I get error:
Call to undefined method Illuminate\Database\Query\Builder::translation()
You should not call translation in the Product model category relation (because you still interacting with the query builder), instead you should access the translation as a property on the category object:
echo $product->product_category->first()->getTranslatedIn(1)->name;
So you could refactor your code like this:
Product Model:
class Product extends Model
{
protected $table = 'products';
public function product_category() {
return $this->belongsToMany('App\product_category', 'product_productcategory');
}
}
Product categories:
class product_category extends Model
{
protected $table = 'product_categories';
public function product() {
return $this->belongsToMany('App\Product', 'product_productcategory');
}
public function translations() {
return $this->hasMany('App\Category_Translation', 'category_translations');
}
// relation filtered by language (cannot be accessed as a property unless you define the parameter as optional)
public function translatedIn($language) {
return $this->hasOne('App\Category_Translation', 'category_id')->where('locale_id', $language);
}
// access translated object
public function getTranslatedIn($language) {
return $this->translatedIn($language)->getResults();
}
}

Resources