Laravel Eloquent belongsToMany - php

I have three db tables:
attributes
---------------------------------
| id | name | showed_name | class
attributes_profiles
----------------------------------------------
| id | attribute_name | profile_id | content |
profiles
------------
| id | ... |
When a User go on the profile site, I want to load ALL Attributes from the table, but I also want the content from the intermediate table (pivot) for this user (id).
public function Attribute(){
return $this->belongstoMany('App\Attribute', 'attributes_profiles', 'profile_id', 'attribute_name','id','name')->withPivot('content');
}
With this class in the profiles model, I wouldn't be able to get all attributes.
When I use a Profiles() Class in the Attributes Model, I get every Attribute but not the content for the user... but for every user.

When you use a Many-to-many relationship, you can access the intermediate table with the pivot attribute. I see you already have the withPivot directive in the relationship, so you are ready to go.
foreach($profile->attribute as $attribute) {
$attribute->pivot->content; // The content in the intermediate table
}

Related

Laravel has_many relationships issue

i have next issue:
I have two tables:
pages
| id | title | content | description | image | status | noindex | viewed | author | template_id | created_at | updated_at |
page_relations
| id | page_id | parent_id |
And my task is: i want to output pages by relationship.
For example: page 1 is parent of a page 2.
What i did:
in my model i use has_many:
public function relation(){
return $this->hasMany(PageRelation::class , 'parent_id');
}
in my controller i add:
$pages = Pages::with('relation')->get();
But in dd() i saw that i get all pages with bound relations to that by value in page_relations table.
But... My question: what should i do to get pages by this ids in this model.
For example: i have list of pages and have relations with child pages (not only ids from page_relations) with title, desctiption ... from pages table?
You could use a HasManyThrough relation. In your case, Page has many Page through PageRelation. I think the docs will provide you with your answer - link.
On another note, there are other ways of handling that type of relation using a parent_id field on itself.
// pages migration
// schema function
$table->id();
$table->string('page_name')
$table->unsignedInteger('parent_id')->nullable();
$table->timestamps();
// end schema function
// Page.php
public function children()
{
return $this->hasMany(Page::class, 'parent_id', 'id');
}
I normally use this when the dataset will not be huge, instead of having an intermediary table. Hope this helps.
I had solve it by that:
public function relation(){
return $this->hasManyThrough(
Pages::class,
PageRelation::class,
'parent_id', // Foreign key on the PageRelation table...
'id', // Foreign key on the Pages table...
'id', // Local key on the projects table...
'page_id' // Local key on the environments table...
);
}

Laravel, show only owner's product list throw same Route and multiple Models

I am trying to display multiple owner's product lists throw the same route.
For example, my route is:
http://example.com/store/public/products
N.B: I don't want to put id in the route.
Now, I have five tables. They are like,
users table
+----+---------+------+-------+----------+
| id | role_id | name | email | password |
+----+---------+------+-------+----------+
roles table
+----+------+
| id | role |
+----+------+
Role and User have One-to-One relationship.
For example, I have two types of role. Admin & Manager.
The Admin is allowed to view all the products but the Manager is allowed to view only products that are owned by him. At first, it seems an easy problem.
But my products have a complex relationship with other tables or models.
Like, My store has many areas which are under different managers.
areas table
+----+------+---------+
| id | area | user_id |
+----+------+---------+
And each area has multiple departments.
departments table
+----+------+---------+
| id | area | area_id |
+----+------+---------+
And finally, each product belongs to specific departments.
products table
+----+---------+---------------+
| id | product | department_id |
+----+---------+---------------+
Now what I am trying to say is, My managers aren't allowed to show products which are under other managers, but admin is allowed to show all products.
I have done the relationship methods correctly in the models. For checking the role of a user, I defined a method named checkRole in the User model. It looks like this,
public function checkRole(){
return $this->role()->pluck('role')->first();
}
And in the controller, I checked the role and showed the products according to roles. That is, in the Controller I tried,
public function getProducts(Request $request, Product $products){
$products = $products->newQuery();
if (Auth::user()->checkRole() == "manager") {
$products= $products->whereHas('department',
function($query){
$query->whereHas('area',
function($query){
$query->where('user_id', Auth::id());
});
})->orderBy('created_at' , 'desc')->get();
}
else{
$products= $products->orderBy('created_at' , 'desc')->get();
}
return $products;
}
It does the work, But is there any better way to do this? I mean throw Middleware or Policy. I tried Middleware, but the problem is, this Route is valid for every user.

Laravel's pivot table + Pivot table in general

What are laravel pivot tables and pivot tables in general? What is this all about?
Recently I made research about Pivot table. I thought I know them and What they are but then I probably was wrong about that.
I have always thought that a pivot table is just a table that is between two tables (Relation many to many)
But then I started this research and It happened to be not that, but something like different architecture of normal table, where rows are columns. It's changed.
But then Laravel's got pivot tables too. Started reading the documentation and doing research.Maybe I read wrong, but it looks like just pivot table in laravel - table in between two tables, many-to-many.
Searching elsewhere but can't find proper information about it.
Okay, so be it. Laravel's pivot just many to many!
Then I started project and Today I went to the point that making this in-between table as pivot drived me to an Issue, I had a problem with that... minutes and hours... couldn't fix that.
Model was class Room_Student extends Pivot
And what was the fix? Just changing it to class Room_Student extends Model.
I don't think I understand pivot tables anymore and are they different types of pivots? Laravel's pivots are different?
So my question is, what pivot tables really are? + Laravel's pivot tables. Are they different? What is this about?
Please help me understand this.
When learning, focus only the pivot tables concept in Laravel (or eloquent). When I was learning I did not care about the general meaning of pivot table. I focused only on facts in the documentation (https://laravel.com/docs/5.5/eloquent-relationships#many-to-many)
many-to-many relationships require an additional table.And we can insert other useful data to this table as well. And can be used as a model in the system.
Example :
User and Roles many-to-many relationship = User_roles
Because of Pivot tables, you can retrieve intermediate table data as a model (like other models in the system).
Example:
//get user by id
$user = App\User::find(1);
//get roles of this user
foreach ($user->roles as $role) {
//pivot attribute returns a model which represent user_role table
echo $role->pivot->created_at;
}
NOTE: you can create a class by extending pivot. But you have to implement the correct relationships to make it work. Your code should look somewhat similar to below code.
class Student extends Model
{
/**
* The users that belong to the role.
*/
public function Rooms()
{
return $this->belongsToMany('App\Room')->using('App\Room_Student');
}
}
class Room extends Model
{
/**
* The users that belong to the role.
*/
public function Students()
{
return $this->belongsToMany('App\Student')->using('App\Room_Student');
}
}
class Room_Student extends Pivot
{
//
}
I hope this helps.
Simply put is a pivot table a table that joins two tables together
say you have a table users
USERS:
user_id, user_name
say you have a table games
GAMES
game_id, game_name
a user can play many games. games have many users playing them.
To link them you make a third table
GAMES_TO_USERS
game_id, user_id
with this table you can request which games a user plays, and which users play which game.
this table GAMES_TO_USERS is in this case the pivot table.
If you know about many-to-many relationships this is common, to handle many-to-many relationships we use intermediate (pivot) table to store relationships of two tables.
Ex: consider about “education” and “person” tables which are listed below
table: person
|------|-------|-----|
| id | name | age |
|------|-------|-----|
| 1 | Bob | 30 |
| 2 | John | 34 |
| 3 | Marta | 28 |
|------|-------|-----|
table: education
|------|-------|
| id | level |
|------|-------|
| 1 | BSc |
| 2 | MSc |
| 3 | PhD |
|------|-------|
Think that Bob has BSc, MSc and John has BSc, MSc, PhD and Marta has BSc, now this is consider as many-to-many relationship and to sort this relationship you need to have intermediate table such as,
table: person_education
|------------|--------------|
| person_id | education_id |
|------------|--------------|
| 1 | 1 |
| 1 | 2 |
| 2 | 1 |
| 2 | 1 |
| 2 | 3 |
| 3 | 1 |
|------------|--------------|
This table mainly stores the primary keys (IDs) of each relationship. This is the basic idea behind the pivot table and when you use larval there are some best practises such as,
Name of the pivot table should consist of singular names of both
tables, separated by undescore symbole and these names should be
arranged in alphabetical order
Laravel Ex:
Class Person extends Model {
public function education ()
{
return $this->belongsToMany('App\Education', 'person_education');
}
}
Moreover, you can specify the actual field names of that pivot table, if they are different than default person_id and education _id. Then just add two more parameters – first, the current model field, and then the field of the model being joined
public function education() {
return $this->belongsToMany('App\Products', 'products_shops', 'shops_id', 'products_id');
}
Keep this in mind
Pivot table — is a table used for connecting relationships between two tables.
Laravel part — laravel provides many-to-many relationship where you can use pivot table, and it is very useful for many cases.
Example:
databases: users, post_user, posts
User.php (Model)
class User extends Model{
public function posts(){
return $this->belongsToMany('Post');
}
}
Now, to access all posts of authenticated user: (view)
#foreach(auth()->user()->posts as $post)
<li>{{ $post->name }}</li>
#endforeach
Relationship happened:
Remember we have post_user table which is the pivot table we used. If we have:
user_id of 1 and we expect that it is the logged in user and post_id of 1, 2, 3, 4, all this posts will be printed out like so:
|------------|--------------|
| post_id | user_id |
|------------|--------------|
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 1 |
|------------|--------------|
Output:
PostName1
PostName2
PostName3
PostName4

How to return multiple relationships with Laravel Eloquent?

I have a table called users. Each of these users has different things:
country
device
computer
category
I have created a table for each of these above 'things'. Similar the following:
1 | United States
2 | United Kingdom
3 | Australia
4 | Canada
5 | Italy
etc...
I'm storing these values in the users table as follows:
ID | Country | Device | Computer | Category |
---|---------|--------|----------|----------|
1 | 3 | 2 | 6 | 2 |
2 | 4 | 3 | 9 | 1 |
etc...
Now each of the above numbers are associated with the corresponding table's ID.
What I want is do an Eloquent Query and search for all the users and 'replacing' their corresponding values from their helper table.
I was thinking about doing a hasOne() Eloquent relationship for each of those things in the users table, but then I'm not sure how to get/call them at once.
Anyone can help me tacke this issue?
$model = Model::with('relatedModel', 'relatedModelTwo')->get();
So in your case, it can be something like this. If you only want one relations returned with the user, remove the others.
$user = User::with('country', 'Device', 'Computer', 'Category')->get();
When you dd($user), you should see the related models in the relations array attribute.
To access the relations' properties from there, it is simply
$user->device->deviceAttribute
Edit For Comment:
Eloquent will assume the foreign key uses the Model name. So if your user table has the id column, it assumes there will be a column on device table called user_id. If you did this, then you are set and nothing should have to be done.
If you named your column to relate the models something else, you will need to pass that through as a second argument in the relation method.
public function device()
{
return $this->hasOne('App\Device', 'foreign_key_here',);
}
Inversely, if you wanted to get the user the device belongs to, Eloquent will attempt to match the user_id column on the device table to the id column on the user table. As before, if you used a different column to related them, declare the foreign key as the second argument.
public function user()
{
return $this->belongsTo('App\User', 'foreign_key_here',);
}
Laravel Doc One-To-One Relation
You're looking for this: $books = App\Book::with('author', 'publisher')->get();
Check out the documentation for eager loading multiple relationships.

how to using just one model for some tables?

I have a website that users can send their product (like car, mobile, computers) and sell it online on my website, maybe something like Ebay and Amazon.
I have ads table that store all public information about one thing using Mass Assignment, and other categories like Mobile, Car and Computers have their own table and will store professional and additional information of that category on it (for example Cars have some additional information like color, fuel type, guaranty, accidents,insurance).
Now as you know I have two tables (ads and ads_mobile), and for all forms I have a controller that is adsController and ads model, form will create dynamically and each form has its own inputs (For Example:Mobile and car has different inputs and fields), and I just send all dynamic forms to adsController#check and then I check what kind of form it is (is that Mobile? is that Car?) and then I want to send this data to model:
//adsController(This is just Example);
class User extends Eloquent {
protected $fillable_ads = array('field_one', 'field_two', 'field_three');
//And I want to use fillable_mobile_ads too
protected $fillable_mobile_ads = array('field_one', 'field_two', 'field_three');
}
Is this possible?
How should be model and controller?
any suggestion for the structure of my program?
Given your design description, I'd look into a polymorphic relationship. This is useful for when you have multiple models (Mobile, Car, Computer) that share a specific set of information (ads) that is common to all models.
class Ad extends Eloquent {
protected $fillable = array('ad_field_one', 'ad_field_two');
public function adable() {
return $this->morphTo();
}
}
class Mobile extends Eloquent {
protected $fillable = array('mobile_field_one', 'mobile_field_two');
public function ad() {
return $this->morphOne('Ad', 'adable');
}
}
class Car extends Eloquent {
protected $fillable = array('car_field_one', 'car_field_two');
public function ad() {
return $this->morphOne('Ad', 'adable');
}
}
class Computer extends Eloquent {
protected $fillable = array('computer_field_one', 'computer_field_two');
public function ad() {
return $this->morphOne('Ad', 'adable');
}
}
To support the above relationships, you would need to add two fields to your ads table: adable_type and adable_id. This can be done in a migration using the statement $table->morphs('adable');
Documentation on polymorphic relationships can be found here.
Laravel always uses one model for one table.
I suggest to re-think your database design. Why don't you create one table for ads and put all ads in there (like mobile, car and computers all in one table) and add a column which specifies which type that is:
+----+----------+-----------+-----------+-------------+
| ID | type | field_one | field_two | field_three |
+----+----------+-----------+-----------+-------------+
| 1 | Mobile | {data} | {data} | null |
| 2 | Mobile | {data} | {data} | null |
| 3 | Car | null | null | {data} |
| 4 | Mobile | {data} | {data} | null |
| 5 | Computer | {data} | {data} | {data} |
+----+----------+-----------+-----------+-------------+
In this example you have 3 mobiles, 1 car and 1 computer in one table. Now lets say mobile only uses field one and two, car uses field three and computer uses all fields.
Now from your car form you submit a hidden field type=car and field 3 only. From your mobile form you submit a hidden field type=mobile and fields 1 and 2. And so on. The non submitted fields remain null.
I see no need for more than one table.

Categories