Laravel: How do I model this Article/Category scenario? - laravel

I have a scenario with Articles and Categories where each article can have only one category through a CategoryGroup.
This means the article can have more than one category but only one unique category from each category_group. Or, to put it another way, the article can have only one category from each category_group.
Do I model this scenario at the level of relationships? Or is this a matter of using custom validation?
This seems like a hasOneThrough scenario but this doesn't exist. So what's the workaround?
I have tried a many-to-many relationship between articles and categories but how do I constrain the article from having more than one of each category type while attaching categories to single articles?
Schema::create('articles', function (Blueprint $table) {
$table->increments('id');
$table->string('title');
$table->text('body');
$table->string('slug');
$table->timestamps();
});
Schema::create('categories', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->text('description');
$table->string('slug');
$table->string('handle');
$table->integer('category_group_id')->index()->nullable();
$table->timestamps();
});
Schema::create('article_category', function (Blueprint $table) {
$table->integer('article_id')->unsigned();
$table->integer('category_id')->unsigned();
$table->primary(['article_id', 'category_id']);
$table->timestamps();
});

Related

Laravel combine multiple collections into one query

I'm wondering if this is possible. I have 3 models.
Users
TenantPreferances
PropertyAdverts
I'm trying to find out if I can do a query like so.
Find all tenants, whose preferences, match the currently signed in users properties.
The 3 databases are like so
User Model
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('email')->unique();
$table->string('userType');
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
PropertyAdverts
Schema::create('property_adverts', function (Blueprint $table) {
$table->increments('id');
$table->string("photo");
$table->string('address');
$table->string('county');
$table->string('town');
$table->string('type');
$table->string('rent');
$table->string('date');
$table->string('bedrooms');
$table->string('bathrooms');
$table->string('furnished');
$table->longText('description');
$table->integer('user_id'); //Landlord ID
$table->timestamps();
});
Tenant Preferances
Schema::create('tenant_preferances', function (Blueprint $table) {
$table->increments('id');
$table->string('county');
$table->string('type');
$table->string('rent');
$table->string('bedrooms');
$table->string('bathrooms');
$table->boolean('status')->default('0');
$table->integer('user_id'); //Tenant ID
$table->timestamps();
});
Yes, that is possible. You need to dig in on relations. You can then create a function to define the relation on you model:
function propertyAdverts() {
return $this->hasMany(PropertyAdverts::class);
}
You can access the relation from the user model by using $user->propertyAdverts. If you want to eager load them you can do so:
User::with('propertyAdverts')->find(3);
But notice that Laravel does not do a regular join by default. It first fetches all users, and then fetches all propertyAdverts using a single query using a in statement.

Has Many Through where the middle table has both forain keys in laravel 5.6

I need to make a HasManyThough relation where the middle Model holds the foreign keys of both Models.
Here is detail:
Migrations:
Schema::create('carriers', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
});
Schema::create('shipping_zones', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
});
Schema::create('shipping_rates', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->integer('shipping_zone_id')->unsigned()->index();
$table->integer('carrier_id')->unsigned()->index();
$table->decimal('rate', 20, 6);
});
Now I need something like
$carrier->shippingZone()
Is there any easy way to get this?
As per your migrations you need Many To Many relation rather than the HasManyThough relation.
Carrier.php
public function shippingZones()
{
return $this->belongsToMany('App\ShippingZone', 'shipping_rates);
}
You can access all shipping zones related to the carrier using, $carrier->shippingZones.
If you need to chain the query you can use $shippingZones = $carrier->shippingZones()->orderBy('id')->get(); here
If you need to use HasManyThough you would have to change the migrations. here

Relationship between Users, Settings, Setting_types Eloquent Laravel 5.4*

How would you go to create a relationship between the folowing tables:
Users table:
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('firstname');
$table->string('surename');
$table->string('address')->nullable();
$table->string('city')->nullable();
$table->string('country')->nullable();
$table->string('postcode')->nullable();
$table->string('email')->unique();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
Setting_type table:
Schema::create('setting_types', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->timestamps();
});
Settings table:
Schema::create('settings', function (Blueprint $table) {
$table->increments('id');
$table->string('value');
$table->timestamps();
});
Setting_type_user table:
Schema::create('setting_type_user', function (Blueprint $table) {
$table->integer('user_id')->unsigned();
$table->integer('type_id')->unsigned();
$table->integer('setting_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users');
$table->foreign('type_id')->references('id')->on('setting_types');
$table->foreign('setting_id')->references('id')->on('settings');
$table->timestamps();
});
This is the result I want to get:
{"id":1,"value":"578943205.jpg","created_at":"2017-07-18 00:00:00","updated_at":null,"pivot":{"setting_id":1,"user_id":1,"type_id":1}}
It depends on many things, but it looks like you want to use many-to-many relationship here.
First, in settings pibot table change it to:
$table->unsignedInteger('user_id');
$table->unsignedInteger('type_id');
It's also a good idea to add foreign key constraints to the table:
$table->foreign('user_id')->references('id')->on('users');
$table->foreign('type_id')->references('id')->on('setting_types');
Then define belongsToMany() relationship in both User and SettingType models. Since you don't follow naming conventions, you have to define foreign keys manually. In the User model:
public function settingTypes()
{
return $this->belongsToMany('App\SettingType', 'settings', 'user_id', 'type_id');
}
And in the SettingType model:
public function users()
{
return $this->belongsToMany('App\User', 'settings', 'type_id', 'user_id');
}

One-To-Many Relation with Pivot Table

I have 2 tables Manufacturers and Suppliers ,and they have Many-to-Many relation
Schema::create('manufacturers', function (Blueprint $table) {
$table->increments('id');
$table->string('name')->unique();
$table->timestamps();
});
Schema::create('suppliers', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('location');
$table->timestamps();
​ });
so i created a pivot table called "manufacturer_supplier" and it works fine.
Schema::create('manufacturer_supplier', function (Blueprint $table) {
$table->increments('id');
$table->integer('manufacturer_id')->unsigned()->index();
$table->integer('supplier_id')->unsigned()->index();
$table->timestamps();
$table->foreign('manufacturer_id')->references('id')->on('manufacturers')->onDelete('cascade');
$table->foreign('supplier_id')->references('id')->on('suppliers')->onDelete('cascade');
});
My confusion comes from adding a new table "devices"
Schema::create('devices', function (Blueprint $table) {
$table->increments('id');
$table->string('serial')->unique();
$table->string('name');
​$table->integer('supplier_id')->unsigned()->nullable();
$table->integer('manufacturer_id')->unsigned()->nullable();
$table->text('notes')->nullable();
$table->timestamps();
$table->foreign('supplier_id')->references('id')->on('suppliers')->onDelete('cascade');
$table->foreign('manufacturer_id')->references('id')->on('manufacturers')->onDelete('cascade');
});
where i want to have a one-to-many relation with each of suppliers and manufacturers , so i would have a select list of manufacturers and then populate the next list from with suppliers from Pivot table that relate to the selected manufacturer.
currently my "device"​ model has the following relations which it relate them to the original table not the pivot so it doesn't work
//5
public function manufacturer(){
return $this->belongsTo('App\Manufacturer');
}
//6
public function supplier(){
return $this->belongsTo('App\Supplier');
}
I haven't done that before so i'm curious to know what will be the best fix for this to work.
Thanks a lot ,
If you want all suppliers associated with a single manufacturer you could get them using the many-to-many relation.
$suppliersList = $supplier->manufacturer()->suppliers();
howerver I don't understand why a device should be associated with a single supplier .... but that's up to you.

How to set up Eloquent relationships to work with a 3-way pivot table

I have a 3 way pivot table that ties a role to a user for a specific organization. Here's how the relevant tables are set up:
//users table
Schema::create('users', function($table)
{
$table->engine = 'InnoDB';
$table->increments('id');
$table->string('username', 30)->index();
//more (irrelevant) fields here
$table->timestamps();
});
//roles table
Schema::create('roles', function(Blueprint $table)
{
$table->engine = 'InnoDB';
$table->increments('id');
$table->string('name', 100)->index();
$table->string('description', 255)->nullable();
$table->timestamps();
});
//organizations table
Schema::create('organizations', function(Blueprint $table)
{
$table->engine = 'InnoDB';
$table->increments('id');
$table->string('name', 255);
$table->string('slug', 100);
$table->text('description');
$table->timestamps();
});
//organization user role table
Schema::create('organization_user_role', function(Blueprint $table)
{
$table->engine = 'InnoDB';
$table->increments('id');
$table->integer('role_id')->unsigned()->index();
$table->foreign('role_id')->references('id')->on('roles')->onDelete('cascade');
$table->integer('user_id')->unsigned()->index();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->integer('organization_id')->unsigned()->index();
$table->foreign('organization_id')->references('id')->on('organizations')->onDelete('cascade');
$table->timestamps();
});
Each user can belong to one or more organizations, with one or more roles. Roles are tied to both a user and an organization simultaneously. That is to say, a user must have a role in an organization in order to be associated with it.
This doesn't seem to fit the mold of the traditional many-to-many relationship pivot-table that works so well out-of-the-box with Eloquent. Can Eloquent handle this type of relationship, or do I need a new model dedicated to handling the relationship? Can someone please show me what the User, Organization, and Role models would look like to tie the 3-way pivot table relationships together with Eloquent?
Check this out: http://github.com/jarektkaczyk/Eloquent-triple-pivot
It works, however I wouldn't call it complete solution. Still you can build yours on top of that.

Resources