Eloquent query adding a new field depending on a pivot table - laravel

I'm trying to make some query with Eloquent but cannot get the result I really want. Using Laravel 6.
I have the next tables:
Table Users:
id | user
============
1 | Andy
Table Colors:
id | color
============
1 | red
2 | blue
3 | white
4 | green
5 | black
Table user_colors:
id | user_id | color_id
==========================
1 | 1 | 1
1 | 1 | 4
What I want is something to get all the colors, but mark as active the ones in the pivot. Something like this:
id | color | active
====================
1 | red | 1
2 | blue
3 | white
4 | green | 1
5 | black
Any idea?

This should return a collection of Color objects with the one's associated with the given user given a property of active set to true
$user_colors = User::find(1)->colors;
$colors = Colors::all()->transform(function ($color) use ($user_colors) {
if ($user_colors->contain($color)) {
$color->active = true;
}
return $color;
});
Whilst this should achieve the result you need, without knowing the context in which you want to use it, it may be inefficient.

There are several ways to achieve this task. One of them could be to use appends in models.
Appends are attributes that you can dynamically add to your model class.
E.g. you can edit your Color model like this:
class Color extends Model {
// Your code...
protected $appends = ['active'];
public function getActiveAttribute() {
$is_active = UserColor::whereColorId($this->id)->first();
if (!is_null($is_active)) return true; // Or 1, up to you
return false; // Or 0, up to you
}
}
If you use this method, you can access to $color->active attribute.
Note that this is only one of the different methods that you can use to do this task.
Reference: Laravel Appends Documentation

Related

In Laravel I'm attempting to get the info from a table with a pivot

I currently have 3 tables:
medias, colors, media_colors
media_colors is the pivot table I'm trying to use it contains
media_id | color_id
------------------
1 | 1
in colors table I have
id | front
----------
1 | color
My model for medias contains:
public function mediaColors()
{
return $this->belongsToMany(Color::class, 'media_colors');
}
In a controller I attempt to query front like so:
$m = Media::find($estimate->media_id);
dd($m->mediaColors[0]->pivot->front);
This returns null. How would I be able to access this?
You can access the colors directly from the relation collection as marked in the comment.
$m = Media::find($estimate->media_id);
foreach($m->mediaColors as $color) {
//you can access all the colors here
$fronts[] = $color->front;
}
//or if you only want the first one (if it exists)
$m->mediaColors[0]->front
one easier way to get just the first value if you only need that
$m = Media::find($estimate->media_id);
$front = $m->mediaColors()->value('front');
// this will return null if no relation found without triggering an exception

Getting author to view correct story in laravel

I'm using Laravel 7 and I'm trying to create a site where the user can login if they have a token. I seem to have that almost working in that if you don't
have a token you can't access the page and if you put in a token that isn't in the database then it throws out an error.
The problem I'm having is that a user can still view a page they not meant to. For example I have Story 1 and Story 2, Author 1 can
view both Story 1 and 2, but Author 2 can only view Story 2.
The issue is that Author 2 can view both Story 1 and Story 2, which is wrong they only supposed to see Story 2.
I wanted to use middleware for this but I kind of hit a brick wall and not sure what next to do.
My tables
Story Table
id | title
1 | Story 1
2 | Story 2
Author Table
id | name
1 | Author 1
2 | Author 2
author_story table
id | author_id | story_id
1 | 1 | 1
2 | 1 | 2
3 | 2 | 2
My Story.php
protected $fillable = ['title'];
public function authors()
{
return $this->belongsToMany('App\Author');
}
My Author.php
protected $fillable = ['name'];
public function stories()
{
return $this->belongsToMany('App\Story');
}
My ViewStory.php (middleware)
if(Auth::check())
{
return $next($request);
}else{
abort(401);
}
Do you get any error?
I think you should use hasMany relation in my author model:
return $this->belongsToMany('App\Story',story_id, id);

pivot table with multiple columns in Eloquent

Here's my scenario:
I have a Event model and a Stage model, a event can have multiple stages and a stage could be assigned to multiple events. So Many-to-many. The thing is, a stage has a sort_order, and that sort_order could be different in each event. That's why I added the sort_order into the pivot table instead in, for example, the stage table.
table: events_stages
| event_id | stage_id | sort_order |
------------------------------------
| 1 | 1 | 1 |
| 1 | 2 | 2 |
| 1 | 5 | 3 |
The thing is when I'm going to relate the Stage with the events its in,
I'm doing something like in the StageController:
sending a post with events: [1,2,3] and sort_order: [1,1,2]
$relatedEvents = array();
foreach ($request->events as $key => $event)
{
$relatedEvents[] = array(
'event_id' => $relatedEventId,
'sort_order' => $request->sort_order[$key]
);
}
$stage->events()->sync(
$relatedEvents
);
but rely simply in the order of the post, doesn't seem like a really good idea.
Does anyone have a nicer solution?
Thanks!
Sometimes is better to create another model (and use it as a pivot) rather than use pivot table itself. You have more control. I'm not sure what exactly you want to achieve.

Insert array on multiple rows

I have a multiple select:
Form::select('color', array('1' => 'Red', '2' => 'Blue', '3' => 'Green', ... ), null, array('multiple'));
How can I insert these values into a table on separate rows, like this:
id | user_id | color
----------------------------
1 | 1 | 1
2 | 1 | 2
3 | 1 | 3
4 | 1 | 4
5 | 2 | 1
6 | 2 | 3
In the above example, user with an id of 1 selected 4 different values in the select and each was inserted on a separate row.
I have this working in this way:
foreach (Input::get('tags') as $key => $value)
{
$user_color = new UserColor;
$user_color->user_id = $user->id;
$user_color->color = $key;
$user_color->save();
}
Is there a better way of doing this? It seems odd using a foreach loop when it feels like Laravel should have some sort of built-in method of inserting multiple values on multiple rows.
As Laravel doc provided,
You may also use the sync method to attach related models. The sync
method accepts an array of IDs to place on the pivot table. After this
operation is complete, only the IDs in the array will be on the
intermediate table for the model:
In this case,
$colors = Input::get('tags');
$user->colors()->sync($colors);
Please make sure to set relation in your User model :
public function colors()
{
return $this->belongsToMany('Color');
}
You can also use attach method when you parameter is not array. To more clear, Here is difference between attach and sync.

Laravel Categories Map Relationship

I have the following three tables but I don't know how to build a relation between the category and the other data type, in this case 'Page':
posts:
post_id | title | slug
1 | Test | test
2 | Another test | another test
catgory_map:
id | category_id | referrer_id | category_map_type
1 | 2 | 1 | Post
2 | 3 | 2 | Post
3 | 2 | 9 | Page
category
id | name
1 | Laravel
2 | Zend2
3 | Phalcon
So whenever I read a Category I like to be able to do something like this
foreach($category->destinations) ...
I have tried until now with hasManyThrough but it didn't work.
What you have is a many-to-many relation with some additional filtering on the relationship (for the category_map_type). Try this:
Post model
public function categories(){
return $this->belongsToMany('Category', 'category_map', 'referrer_id')
->where('category_map_type', 'Post');
}
Category model
public function posts(){
return $this->belongsToMany('Post', 'category_map', 'category_id', 'referrer_id')
->where('category_map_type', 'Post');
}
Usage
$category = Category::find(1);
foreach($category->posts as $post){
// ...
}
(And the same goes for Post)
You might also want to look into polymorphic many-to-many relations

Resources