I concerned about auto naming tables in many-to-many Laravel relationship.
for example:
Schema::create('feature_product', function (Blueprint $table) {}
when change the table name to:
Schema::create('product_feature', function (Blueprint $table) {}
I have an error in my relationship.
What's the matter with product_feature?
Laravel's naming convention for pivot tables is snake_cased model names in alphabetical order separated by an underscore. So, if one model is Feature, and the other model is Product, the pivot table will be feature_product.
You are free to use any table name you want (such as product_feature), but you will then need to specify the name of the pivot table in the relationship. This is done using the second parameter to the belongsToMany() function.
// in Product model
public function features()
{
return $this->belongsToMany('App\Feature', 'product_feature');
}
// in Feature model
public function products()
{
return $this->belongsToMany('App\Product', 'product_feature');
}
You can read more about many to many relationships in the docs.
Related
I have a problem with Laravel, let me describe all steps.
Created migration "create_user_role_table" with:
$table->unsignedBigInteger('user_id');
$table->unsignedBigInteger('role_id');
Created Role and UserRole models
In UserRole model:
protected $table = "user_role";
protected $guarded = false;
In Role and User models added function belongsToMany.
IndexController: $user = User::find(1); dd($user->role[0]->title);
After those steps, laravel without reason trying to open "role_user" table, not "user_role". Where did he find this table in the code? "SQLSTATE[42S02]: Base table or view not found: 1146 Table 'blog.role_user' doesn't exist". If rename table in DataBase to "role_user", it's work. How to solve that, where did he found table with name "role_user"?
Laravel's naming convention for pivot tables is snake_cased model names in alphabetical order separated by an underscore. So, if one model is User, and the other model is Role, the pivot table will be role_user.
You are free to use any table name you want (such as user_role), but you will then need to specify the name of the pivot table in the relationship. This is done using the second parameter to the belongsToMany() function.
return $this->belongsToMany(Role::class, 'user_role', 'user_id', 'role_id');
What do I forget about doing migrations in Lavarel that once relations act to me like this and once so? Presenting what I want to get is I want to assign the user his order and order the products he ordered. So I have a User table, the Order table, and the OrderProduct table. Usera table with one-to-many relation with the Order table, Order table with one-to-many relation with the OrderProduct table. Starting from the relation Order and OrderProduct, I get an error:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'order_products_tables.order_table_id' in 'where clause' (SQL: select * from `order_products_tables` where `order_products_tables`.`order_table_id` = 1 and `order_products_tables`.`order_table_id` is not null)
And this error says clearly and clearly that he can not find the order_table_id column in the order_products_tables table and I am not surprised what it may sound silly because there is no such field but there is an order_id field and in migrations is described with which field is the relationship and I can not understand why Laravel tries refer to order_products_tables.
Migrations Order:
Schema::create('order_tables', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->unsigned()->nullable();
$table->foreign('user_id')
->references('id')
->on('users');
$table->timestamps();
});
Migrations OrderProduct:
Schema::create('order_products_tables', function (Blueprint $table) {
$table->increments('id');
$table->integer('order_id')->unsigned();
$table->integer('count')->unsigned();
$table->integer('price')->unsigned();
$table->foreign('order_id')
->references('id')
->on('order_tables');
$table->timestamps();
});
As it results from the migration, the order_products_tables table stores the record ID from the order_tables table and the relationship is based on that ID.
Model Order table:
class OrderTable extends Model
{
protected $table = 'order_tables';
public function user()
{
return $this->belongsTo(User::class, 'id');
}
public function products()
{
return $this->hasMany('App\OrderProductTable');
}
}
Model OrderProduct table:
class OrderProductTable extends Model
{
protected $table = 'order_products_tables';
public function order()
{
return $this->belongsTo(OrderTable::class, 'id');
}
}
I do not understand why the reference to order_table_id is going. I have done other relations, eg User and Order on the same principle, and it works without a problem, suddenly here I have such a case. Where should I look for a solution and why does it wo
This error comes from using wrong table names or, to be more correct, not defining the relationship correctly. The following relationship definitions will fix your issue:
class OrderTable extends Model
{
protected $table = 'order_tables';
public function products()
{
return $this->hasMany('App\OrderProductTable', 'order_id', 'id');
}
}
class OrderProductTable extends Model
{
protected $table = 'order_products_tables';
public function order()
{
return $this->belongsTo(OrderTable::class, 'order_id', 'id');
}
}
The reason your previous code did not work is that Laravel uses default values which are basically assumptions and require your database to follow certain naming conventions. Here is a list of conventions you should follow*:
Tables should be named after the model name in plural form and snake_case:
Model User is supposed to have a table named users.
Model Category is supposed to have a table named categories (see the english plural).
Model AccountManager is supposed to have a table named account_managers.
If there is no model for a table, i.e. a many-to-many relationship table, the table name is expected to be in singular form and snake_case, where the model names that hold the relation are ordered alphabetically:
If there are models Category and Product (with tables categories and products) and there is a many-to-many relationship (belongsToMany()) between them, the table for the pivot table is expected to be called order_product (and not product_order because o comes before p in the alphabet).
Foreign key columns are expected to be called after the model they represent with _id as postfix:
When referencing the User model on a BlogPost model for example, Laravel expects a user_id column as foreign key on the BlogPost model. The referenced primary key on the User model is taken from the $primaryKey property, which is 'id' by default.
For your particular scenario, this means we would expect the following models, tables and columns:
Model User with table users and columns like in the default migration of Laravel.
Model Order with table orders and columns like id, user_id, created_at, ...
Model Product with table products and columns like id, name, price, ...
Model OrderProduct with table order_products and columns like id, order_id, product_id, quantity, ...
In theory, the model OrderProduct is not necessary. You should also be able to build the same system without it by defining $this->belongsToMany(Product::class)->withPivot('quantity') on the Order model and $this->belongsToMany(Order::class)->withPivot('quantity') on the Product model (note the pivot fields). Personally, I prefer extra models for many-to-many relations though.
For reference to Eloquent relationships, have a look at the documentation. There are examples for all relationship types and additional information for the additional parameters when you need to override the default table or column names for your relations.
* This list may lack important information. It was created as best effort.
I have a many to many relationship. The pivot model hasMany children. When I call detach on the many to many, I need to also delete the pivot model's children. I wanted to use onDelete('cascade'), but that doesn't seem to work. I also tried this: http://laravel-tricks.com/tricks/using-model-events-to-delete-related-items, but that doesn't seem to work either. Neither are working probably because the destroy event is not being triggered.
Any ideas on how I can get the children to delete when I call detach?
Here's some of my code in case I made a mistake:
My pivot model:
Schema::create('beer_distributions', function(Blueprint $table)
{
$table->increments('id');
$table->integer('beer_id');
$table->integer('distributor_id');
The pivot model's children:
Schema::create('kegs', function(Blueprint $table)
{
$table->increments('id');
$table->integer('beer_distribution_id');
$table->dropForeign('kegs_beer_distribution_id_foreign');
$table->foreign('beer_distribution_id')
->references('id')
->on('beer_distributions')
->onDelete('cascade');
I don't know if there is anyway to salvage this approach. I called sync and then tried to delete the children, not realizing the parent was already gone making the children inaccessible.:
$attachments = $beer->distributors()->sync(Input::get('distributors'));
foreach ($attachments['detached'] as $distributor_id) {
BeerDistribution::where('beer_id', '=', $id)
->where('distributor_id', '=', $distributor_id)->first()->destroy();
}
UPDATE:
Just to be clear, I have four models I am working with. Beers and distributors with a many to many relationship. The pivot model, BeerDistributions, hasMany kegs. When I call sync to update a beers distributors, the BeerDistributions do get deleted automatically, and I want the kegs to get deleted at the same time.
Here are some of my models:
class Beer extends Eloquent {
public function distributors()
{
return $this->belongsToMany('Distributor', 'beer_distributions');
}
Beer ^ manyToMany with Distributor:
class Distributor extends Eloquent {
public function beers()
{
return $this->belongsToMany('Beer', 'beer_distributions');
}
The pivot model...
class BeerDistribution extends Eloquent {
public function kegs()
{
return $this->hasMany('Keg', 'beer_distribution_id');
}
has many kegs:
class Keg extends Eloquent {
public function beerDistribution()
{
return $this->belongsTo('BeerDistribution');
}
There seems to be some confusion here about pivot tables, detach, and cascades.
Basically, the detach method should be all you need for this. All it's doing is managing the pivot table through the belongsToMany() relationship.
So if you do $keg->distributors()->detach([1,2,3]) and $keg->id is 5, it will search and remove items from the pivot where the distributor is 1, 2, or 3 AND the keg id is 5. In most cases, you shouldn't even need an eloquent model for the pivot tables. detach(), attach(), and sync() will handle that table for you.
Delete on cascade is likely what is causing you issues because you have it backwards. In this case, the delete on cascade key would be put on the pivot table. What this means is when you delete a parent (keg or distribution), those items belonging to that parent in the pivot table would automatically be removed. This saves you from having orphaned data in the table.
Why I say you are doing this backwards is because you put the key on your kegs table which means when an item in the pivot table is deleted, your keg is also deleted. This is bad and not at all what you want. You want to delete items from the pivot table when your keg is deleted.
Remove that key and in your schema to create the beerDistributions add two keys that will look something like this...
$table->foreign('beer_id')->references('id')->on('beers')->onDelete('Cascade');
$table->foreign('distribution_id')->references('id')->on('distributors')->onDelete('Cascade');
And if you have a key which is deleting on cascade on your distributor's table, remove that too. Should only have those foreign keys on the pivot table.
Edit: Seeing as how you want to delete kegs, it looks as though you are referencing the wrong columns in the pivot table.
$table->foreign('id')
->references('beer_distribution_id')
->on('beer_distributions')
->onDelete('cascade');
I have generate the following database table and need to create model form them.
Creating a model seems to be an easy task, but I am confused how should i define the relationship between two tables. In users table RoleId is foreign key. My question is where and how should I define the relationship (in User model or Role model). Should I use hasOne, hasMany, or belongsTo
In your User model
public function roles()
{
return $this->hasOne('Role', 'id', 'RoleId');
}
In your Role model
public function users()
{
return $this->belongsTo('User', 'RoleId', 'id);
}
I have a couple of models that I have included pivot tables for to avoid a polymorphic relation.
role table
id
name
description
restriction table
id
rule
status
restriction_role table
id
restriction_id
role_id
Reason for this setup is that both Roles and Restrictions can actually belong to multiple other models. In this case, a Role can only have 1 Restriction. I would normally define this as
class Role extends Eloquent {
public function restrictions()
{
return $this->hasOne('Restriction');
}
}
This obviously does not work because Laravel is unaware of the pivot table connecting this relation. I could easily accomplish this by using a many-to-many relationship instead, but this is not exactly how my model works. Not seeing anything in the documentation for defining this. Any thoughts?
I've solved this by using the belongsToMany relation and defining a custom accessor for it, like so:
public function foo()
{
return $this->belongsToMany(App\Bar::class);
}
public function getFooAttribute()
{
return $this->foo()->first();
}
As #deczo stated in the comments, belongsToMany() is about all that will work here. I recommend returning the first result using the first() method if you require only one result but cannot use a hasOne() relationship.