Laravel sends SQL request to the wrong table without reason - php

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');

Related

Laravel one-to-many relationship - a reference to a non-existent field

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.

L5.5 relationship of pivot table with another model

In my application, a model Device has a many-to-many relationship with model Task.
A combination of Device and Task could be assigned to a various number of model User.
example: Device A has a Task Check something and this should be done by User Frank and Steven.
From my point of view, this should be a "standard problem", but so far I could not find a proper solution.
Right now, I use following workaround:
a) added an unique ID id to the device_task pivot table
b) query id from the pivot table
c) create a new table device_task_user which contains user_id and device_task_id
b) use query builder to get/add users
But I am really not happy with this approche.
Would it be possible, that the pivot table also extends Model and then have a one-to-many relationship with User?
Or would you suggest to add a json colum to the pivot table and store the users there?
Any idea would be very welcome!
Would it be possible, that the pivot table also extends Model
Yes, it's possible. From the docs:
If you would like to define a custom model to represent the intermediate table of your relationship, you may call the using method when defining the relationship. All custom models used to represent intermediate tables of relationships must extend the Illuminate\Database\Eloquent\Relations\Pivot class
You also can create a new hasMany() and belongsTo() relationships between Task and Device models and use them as well as existing belongsToMany relationship. And you'll need to define a new relationship between pivot model and User model to be able to get data by device, task or user.
Modify many-to-many relationship to hold an extra field user_id
class Device extends Model
{
public function tasks()
{
return $this->belongsToMany(
Task::class,
'device_task',
'device_id',
'task_id'
)->withPivot('user_id');
}
}
And when updating do like this in controller
$device->tasks()->attach([$taskId]=>['user_id']=>$userId);
And of-course you need DeviceTask model and also a has-many relationship between User model and DeviceTask model to get user's task

Laravel eloquent many to many relationship determine if relation exist

I am working on a project with many-to-many relationship between two tables roles and users. I also have a pivot table role_user that holds information about the relation between the other two tables.
role_user two fields namely the ids of the two tables: role_id and user_id.
Now I have a user object gotten from the users table and another role object gotten from the roles table. I want to determine if a particular role belongs to a certain user.
I know this can be done by creating a model for the pivot table and then using the model, the role_user table can be queried and determined if the relation exists.
But I find this method stressful and wonder if eloquent provides an easy method to determine this.
Thanks for any help?
You don't need to have a role_user model. You might already have role model and the user model related to the tables you have.
Specify the many to many relationship in Role.php and User.php
User.php - function roles
public function roles()
{
return $this->belongsToMany('App\Role');
}
Role.php - function users
public function users()
{
return $this->belongsToMany('App\User');
}
You may have to define other parameters like pivot table etc if you don't follow the naming conventions in table columns and tables. Since you seem to have follow the rules I'm not going to explain it. But you always can refer to laravel documentation's eloquent many-to-may section
now you can easily check whether a user belongs to a certain role.
Consider the following examle
//select a user
$user = App\User::find(1);
//select a role
$role = App\Role::find(1);
//get $user's roles. This ill return an array of role objects that are belong to $user
$userRoles = $user->roles;
//check whether $role is in that array
if(in_array($role, $userRoles)){
//do something
}

Why the name convention of Laravel relationships so weird?

I have three tables:
users
columns: id, name
books
columns: id, name
book_user:
columns: user_id, book_id, state(not read yet, reading, read already)
I intended to user book_user as many-to-many relation table, so I follow the name convention from doc:
To define this relationship, three database tables are needed: users, roles, and role_user. The role_user table is derived from the alphabetical order of the related model names, and contains the user_id and role_id columns.
I wrote code:
class User extends Model
{
public function books()
{
return $this->belongsToMany('App\Book');
}
}
, and I can retrieve the books which related to the user by call user->books().
That works well, but when I try to retrieve the state of the book which related to a user, I create model:
class BookUser extends Model
{
//
}
When I use this Model, it claims:
Base table or view not found: 1146 Table 'myapp.book_users' doesn't exist
Conclusion:
the name convention of a table which can be used as many-to-many is <singular_noun>_<singular_noun> (such as book_user).
the name convention of table with multiple words which mapping to a Model is <singular_noun>_<plural_noun> (such as book_users).
I know I can set the table name manually which a model mappings to, but I just wonder:
Does that conflict is a design flaw or just I'm doing wrong in designing tables and models?
You don't need define a model for pivot table,just add withPivot
class User extends Model
{
public function books()
{
return $this->belongsToMany('App\Book')->withPivot('state');
}
}
Then you can retrieve book states from model pivot
Generally you don't need a model for pivot tables. You can define the inverse of the relationship. And if you want to store extra data in pivot table maybe you can check withPivot method. Or explain what are you trying to do.
But if you want to create a model, you need to specify your table name in your model manually. Because Laravel doesn't know if its a pivot table or normal table. It just tries to guess the table name by making it plural.

Laravel 5 database relation type

I would like to use Laravel 5 Models to retrieve a relationship, but i dont know which relation type i should use and how to implement it.
i have 4 database tables:
Users
Roles
Permissions
role_permission
i need to retrieve all the permissions for a "User" based on its "role_id" column.
I've created 3 models:
User
Role
Permission
The database table "users" holds 2 columns:
id
role_id
The database table "roles" holds 2 columns
id
name
The database table "permissions" holds 2 columns
id
name
The database table "role_permission" holds 3 columns that defines which Role is associated to which Permission.
role_id
permission_id
flag
What i want to achieve is the following syntax:
$user->role // Get the associated "Role"
$user->role->permissions // Get the associated permissions for a "Role"
App\Role::find(1)->permissions // Get the associated permissions for a "Role"
i did read the Laravel documentation about model relations but i really dont get it. Does someone understand what i'm trying to achieve and how to implement it in the Models? maybe with some simpel code examples so i can understand the relations and how they work?
Thanks in advance.
The way that you have your database defined, you have defined the following relationships: a one-to-many between role and users, and a many-to-many between roles and permissions. It can also be stated that a role has many users, a user belongs to a role, a role has many permissions, and a permission has many roles.
In Laravel, one-to-one relationships are modeled using a hasOne/belongsTo set, one-to-many relationships are modeled using a hasMany/belongsTo set, and many-to-many relationships are modeled using a belongsToMany/belongsToMany set.
The relationships are defined in the models below:
User:
Since the users table contains the foreign key to the roles table (role_id), the User model is on the belongsTo side of the one-to-one/one-to-many relationship.
class User extends Model {
public function role() {
return $this->belongsTo('\App\Role');
}
}
Role/Permission:
The many-to-many with permissions is done by both models having a belongsToMany relationship. The Laravel convention for the pivot table name is the combination of the singular table names, in alphabetical order, with an underscore separator, so it should be 'permission_role'. Since the pivot table name doesn't follow convention, it must be specified in the relationship definition. Also, since you have an extra field on the pivot table, you need to specify access to that field with the withPivot() method on the relationship.
class Role extends Model {
public function users() {
return $this->hasMany('\App\User');
}
public function permissions() {
return $this->belongsToMany('\App\Permission', 'role_permission')->withPivot('flag');
}
}
class Permission extends Model {
public function roles() {
return $this->belongsToMany('\App\Role', 'role_permission')->withPivot('flag');
}
}

Categories