Laravel multiple whereHas criteria for relationship - laravel

I have two tables - contacts and visits:
Contacts Table
id | name
----- | -------
1 | Joe
2 | Sally
Visits Table
id | contact_id | pathname | referrer
----- | ------- | ------- | -------
1 | 1 | about | google
2 | 1 | pricing | null
3 | 1 | signup | null
4 | 2 | about | null
5 | 2 | signup | null
Using eloquent, I would like to retrieve all contacts that have a both a pathname = 'signup' AND a referrer = 'google'.
What I've got so far is:
Contact::whereHas('visits', function($query) {
$query->where('pathname','=','signup');
})
->orWhereHas('visits', function($query) {
$query->where('referrer','=','google');
})
->get();
Which properly retrieves all contacts that have visited either the pricing OR signup page.
However, this example would also retrieve Sally (from the example table above), since she visited signup, but was not referred by google. I need a way to only retrieve Joe, who was both referred by google and visited pricing.
Any ideas? Thanks in advance!

You can use:
Contact::whereHas('visits', function($query) {
$query->where('pathname','=','signup');
})
->whereHas('visits', function($query) {
$query->where('referrer','=','google');
})
->get();

A refined version of the code above:
Contact::whereHas('visits', function($query) {
$query->where('pathname','signup')->where('referrer','google');
})->get();
Several noteworthy points:
You can chain where() clauses within a closure.
The default operator for a where clause is =, so you can omit it.
Use multiple whereHas() clauses, when accessing multiple related models.

Related

laravel eloquent nested relationship count

i have 4 database tables :
Broadcasters
| id | public_name | .... |
Articles
| id | title| .... |
Comments
| id | user_id| article_id | .... |
users
| id | login| .... |
i would like to list all broadcasters with number of article of each one (broadcaster) and the totale comments of all article ( of the broadcaster ). below my code that i make but it miss samething
Broadcaster::withCount(['articles'])
->withCount(['articles'=> function($query){
return $query->withCount("comments");
}])
->get();
i checked in stackoverflow forum but didnot get any answer of my question , please help and thx
You can declare a relation hasManyThrough in Broadcasters class:
function comments()
{
return $this->hasManyThrough('App\Comment', 'App\Articles');
}
So you can
Broadcaster::withCount(['articles','comments'])
Laravel Doc

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.

Laravel - don't show the same record twice using inRandomOrder()

I have the following query to get a random question from my database:
$q = Question::inRandomOrder()->first();
Each question i'm generating is saved at user_questions with the following structure:
id | question_id | user_id
My goal is to generate the random question using the eloquent query above and exclude all questions the user already has.
For example, if there are the following records in my user_questions table:
1 | 133 | 234
2 | 134 | 234
3 | 543 | 234
the query that return a random question excluding 133,134 and 543.
Any ideas?
You can use whereDoesntHave() to exclude questions which user already has:
$randomQuestion = Question::whereDoesntHave('users', function($q) use($userId) {
$q->where('id', $userId);
})
->inRandomOrder()
->first();

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