L5.5 relationship of pivot table with another model - php

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

Related

I don’t know how to get data in laravel correctly by linking the data in this database

In this figure, the remaining tables are linked to the datainfo table. I need to retrieve the entire table data from the datainfo table.
In this picture I have shown the tables themselves
You can create Eloquent Models for each table and define Relationships among them. This is the Correct Laravel Way.
Let's assume Your datainfo table represents your Datainfo model,
Your cars table represents Car model. Same as washtypes and boxes.
then depending on your relation type defined the relation in Datainfo model.
class Datainfo extends Model
{
public function cars()
{
return $this->hasMany(Car::class);
}
}
You also can use hasOne instead of hasMany for one - to one relation
Similarly, create relation defining functions as washtypes() and boxes().
Then To get Datainfo with all related data using something like think in your controller
return Datainfo::with('cars','washtypes','boxes')->get();
Alternatively, you can get the count
return Datainfo::with('cars','washtypes','boxes')->count();
To get a count on a date
return Datainfo::with('cars','washtypes','boxes')->where('created_at',$date_var)->count();
If you only want Datainfo that has relation with cars, washtypes or boxes:
return Datainfo::has('cars','washtypes','boxes')->where('created_at',$date_var)->count();
Use laravel eloquent join clauses, https://laravel.com/docs/8.x/queries#joins
For total amount in same day
You can use eloquent sum and group by methods based on the date

Understanding hasOne() and belongsTo() functions in Laravel

All I'm trying to do is understanding when exactly should I use hasOne() and when should I use belongsTo(). Both seem identical to me. For example, here is my model:
use Illuminate\Database\Eloquent\Model;
use App\Categories;
use App\User;
class tickets extends Model
{
protected $table = "tickets";
public function category()
{
return $this->hasOne(Categories::class, 'id', 'category_id');
}
public function user()
{
return $this->hasOne(User::class, 'id', 'user_id');
}
}
I can do the same by using belongsTo() function too. Just I should put them into user and category models instead. Anyway, when should I use either hasOne() or belongsTo() ?
When dealing with 1 to many relationships, you will have a hasMany()and a belongsTo() .
The rule of thumb I use, is if a table has a foreign key (tickets table has a user_id fk) then this model belongsTo users.
The same with Category.
So your above example, Ticket belongsTo User & Category.
Inversely, User hasMany Ticket and similarly Category hasMany Ticket
Anyway, when should I use either hasOne() or belongsTo() ?
Think of it like what would be hasMany if there is one to many relation probable in the future. For example: consider User and Phone models. Nature of relation would be User hasOne Phone, but if you would like to extend functionality for it so user could have multiple phone numbers registered User would still have has* relation while Phone would keep belongsTo relation. Just consider which one could be "parent" entity and that one should have hasOne relation in method. I would always consider User as parent entity and for me logically would be user has one ticket.
Also, try to stick with Eloquent/Laravel/artisan naming convention and name that model Ticket and other one Category (Eloquent and Laravel will solve plural where needed i.e. table name).
hasOne is a 1:1, or one-to-one relationship.
hasMany is a 1:n, or one-to-many relationship.
The belongsTo method in Eloquent is used to define the inverse of these relationships.
The definition of these will depend on your data model.
In your case:
You have a Category model, which hasMany Tickets.
You also have a User model, which hasMany Tickets.
Now from the Ticket perspective, you would want to define the inverses of these 2 hasMany relationships. You will do this by defining a belongsTo.
So the Ticket belongsTo a User and belongsTo a Category.
To answer your question:
From the Tickets perspective, it is a 1:1 relation, because the foreign key in the Ticket model points to 1 User and the category foreign key points to 1 Category.
But since the relation you created is a 1:n (one-to-many) and you have also defined it on the User and Category models, you should define the relation in your Ticket model as the inverse of those relations, and the inverse of a hasMany (and hasOne) is belongsTo.
When defining your relations in Laravel, keep your database schema in mind and define your relations in the same way that they exist in your database schema.
These are same with a single difference. Both returns the single associated object with one difference. When we declare some relation as belongsTo it means there is a database table which has a foreign key of some other table. When we declare hasOne relation it means that this table's primary key has been referenced in another table. Think of it as a parent child table. When we would make the child table we reference each child to its parent, right? This is belongsTo. And when we would make the parent table we know that each entry in parents table can have a single or many entries in the child table. That's hasOne or hasMany relation. You can ask further if you need any more clarification.

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.

translating database relationships to Eloquent relationships

So, I've been trying to watch and read eloquent relationships from laracasts. Unfortunately I still don't quite get how to translate database relationships to eloquent relationships (hasOne, belongsTo, hasMany, etc).
Let's say I have an Account and Customer tables. Account table has a "Customer_id" foreign key which references to the "id" on Customer table. Let's assume it's a one-to-many relationship. How should I put it on my models on laravel?
Which table should contain the "hasMany" and which one should have the "belongsTo"?
Just think about how you would say it. In your case it sounds like a Customer has many Accounts and an Account belongs to one Customer.
So you would put the hasMany() in your Customer model and the belongsTo() in your Account model.
class Customer extends Model {
public function accounts() {
return $this->hasMany('App\Account');
}
}
class Account extends Model {
public function customer() {
return $this->belongsTo('App\Customer');
}
}
You can read more about Laravel database relationships here.

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