laravel Eloquent relationship using Distinct - laravel-5

I need show data with relationship using DISTINCT.
This is my sql data :
table pochettes
id |
49 |
table journees
id | formateurs_id | pochettes_id
1 | 3 | 49
2 | 4 | 49
3 | 3 | 49
table formateurs
id |
3 |
4 |
model Pochette
public function Journees()
{
return $this->hasMany('App\Journee','pochettes_id');
}
model Journee
public function Formateurs()
{
return $this->belongsTo('App\Formateur', 'formateurs_id');
}
I am used this code to show data with distinct formateurs because a Formateur can have many Journee in the same Pochette :
$pochette = Pochette::find(49);
foreach ($pochette->Journees->distinct('formateurs_id') as $formateur) {
echo $formateur->formateurs_id;
echo "<br>";
}
But this code dosn't work, I have this error message
**BadMethodCallException in Macroable.php line 81:
Method distinct does not exist.**
I would show this result :
3
4
not :
3
4
3

When you access an Eloquent relationship like a property, you will get an Eloquent Collection. However, distinct() is a Query Builder method and you need access to the Query Builder instance before returning the Collection. If you add () to the end of the relationship, you gain access to the Query Builder instance and can chain those Query Builder methods. In your case, you are actually looking for the groupBy() method and not distinct(). Don't forget to end the query with get().
foreach ($pochette->Journees()->groupBy('formateurs_id')->get() as $formateur) {
echo $formateur->id ;
echo "<br>";
}

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

Self referencing "ownerless" many_many relationships?

I have a many many relationship where I don't care who created the relationship, if the querying models ID is in either side of the relationship I need the other side.
--
Let's say I have this model
class Ingredient extends Model
{
public function complements()
{
return $this->belongsToMany(
self::class, 'ingredient_complements',
'ingredient_id', 'complement_id'
);
}
}
And I've created a few different instances as below
$ing1 = new Ingredient();
$ing2 = new Ingredient();
$ing3 = new Ingredient();
$ing4 = new Ingredient();
$ing5 = new Ingredient();
$ing6 = new Ingredient();
$ing1->save(); //2,3,4,5,6...
Next I go through and relate a few of them
$ing1->complements()->attach($ing2);
$ing2->complements()->attach($ing3);
$ing3->complements()->attach($ing4);
$ing4->complements()->attach($ing6);
$ing5->complements()->attach($ing6);
$ing6->complements()->attach($ing1);
So now we have a pivot table that looks like
| ing_id | cmp_id |
| 1 | 2 |
| 2 | 3 |
| 3 | 4 |
| 4 | 5 |
| 5 | 6 |
| 6 | 1 |
So..
if I call $ing1->complements I'll get back ing2
if I call $ing2->complements I'll get back ing3
But..
if I call $ing2->complements I won't get back ing1
if I call $ing3->complements I won't get back ing2
I need to fix that.
I've got a second method that I'm using at the moment that I can call using $ing3->complementaryIngredients; which ends up executing something like
select * from `ingredients`
inner join `ingredient_complements` on `ingredient_id` = '3'
or `complement_id` = '3' and `ingredient_id` = `id`
or `complement_id` = `id` where `id` <> '3'
Which works, but I don't feel this is something that I should have to break out of the ORM for?
public function getComplementaryIngredientsAttribute()
{
return self::join('ingredient_complements', function(JoinClause $join){
$join->where('ingredient_id', $this->id);
$join->orWhere('complement_id', $this->id);
$join->on('ingredient_id', '=', 'id');
$join->orOn('complement_id', '=', 'id');
})->where('id', '<>', $this->id)->get();
}
You actually need to define bi-directional relationship, so your model should have 1 more method which will define the opposite direction.
public function ingredients()
{
return $this->belongsToMany(
self::class, 'ingredient_complements',
'complement_id', 'ingredient_id'
);
}
Then you will get the other side of your relation in this way $ing2->ingredients() and it will return what you are looking for.
Another approach is to create model for your pivot table so you can query that model to get both sides of your relationship

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 4.2 HasMany Relationship using Like

I'm wondering if its possible to set the operator when using a HasMany relationship in Laravel 4.2.
I'm working with a users table and an email log table. The log table has a userID stored in serialised format (as there may be more than one userID stored within the log).
Users table
+---------+
| user_ID |
+---------+
| 1 |
| 2 |
+---------+
emailLog Table
+----+--------------------+
| ID | user_ID |
+----+--------------------+
| 1 | a:1:{i:0;s:1:"2";} |
| 2 | a:1:{i:0;s:1:"1";} |
+----+--------------------+
Am I able to use a hasMany relation with a 'Like' operator rather than an equals operator to return the correct email log ID? Would the statement be written something like the below?
return $this->hasMany('emailLog', 'user_ID', '%user_ID%', 'LIKE');
The proper way to return join table with a where clause would be:
return $this->hasMany('emailLog','user_id')->where('user_id', 'LIKE', '%user_id%');
I found a way to do something similar
class User extends Model
{
public function emailLogs()
{
// old code
// return $this->hasMany(EmailLogs::class, 'user_ID');
// Replace HasMany by like query
return EmailLogs::where('user_ID', 'LIKE', "%{$this->user_ID}%");
}
}

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