Joining Tables in Laravel 4.2 Eloquent - php

I'm not so good at making queries using Laravel Eloquent. I've two tables
stories table
------------------------------------------------------------------
id | title | body | author_id |...
------------------------------------------------------------------
1 | Story 1 | Once a.. | 2
2 | Story 2 | There is | 4
3 | Something | You are. | 2
activities table
------------------------------------------------------------------
id | story_id | liker_id |...
------------------------------------------------------------------
1 | 2 | 2
Here author_id & liker_id are actually user_id. I want to get the Stories authored and liked by a specific user to display these stories in his profile.
I want to use the Eloquent ORM. I tried something like this using query builder
$stories = DB::table('stories')
->join('activities', function($join)
{
$join->on('stories.author_id', '=', 'activities.liker_id')
})
->where('stories.author_id', $author_id)
->get();
return $stories;
I can get story_id for a specific liker_id by join but couldn't get the details from stories table using story_id in a Single query.

Here is simple method with query builder to get Stories authored and liked by a specific user
$author_id = 1;
$stories = DB::table('stories')
->join('activities', 'stories.author_id', '=', DB::raw('activities.liker_id AND stories.id = activities.story_id'))
->Where('stories.author_id', $author_id)
->get();
//select * from `stories` inner join `activities` on `stories`.`author_id` = activities.liker_id AND stories.id = activities.story_id where `stories`.`author_id` = 1"
with Eloquent you can do as following create 2 model file
1. Story model (Story.php)
2. Activity Model (Activity.php)
Story.php
class Story extends Eloquent {
public function activities()
{
return $this->hasMany('Activity');
}
}
Activity.php
class Activity extends Eloquent {
public function story()
{
return $this->belongsTo('Story');
}
}
than you can write function within Story to get data as your need
$stories = Story::with('activities')
->where(DB::raw('stories.id = activities.story_id'))
->Where('stories.author_id', $author_id)
->get();
// haven't tested with eloquent but it should work

Related

Multiple relationships on same table with two column Laravel

If the bookstore does not have any books in stock, this bookstore can purchase books from the other bookstore it is contracted with.
book_transfers table is as follows.
ID | sender_bookstore_id | delivery_bookstore_id
1 | 2 | 3
2 | 1 | 2
3 | 3 | 1
books table
ID | store_name
1 | London Garden Book Store
2 | Englaland Cafe Book
3 | Domesday Book Store
Two-column sender_bookstore_id and delivery_bookstore_id belong to the same table. The name of this table books.
My Controller code is below:
$data = BookTransfer::join('books', 'books.id', '=', 'book_transfers.sender_bookstore_id')
->select(
'book_transfers.*',
'book_transfers.sender_bookstore_id as sender_id',
'book_transfers.delivery_bookstore_id as delivery_id',
'books.store_name as sender_store_name'
)
->groupBy('book_transfers.id')
->get();
return $data;
I can only get sender_store_name here. I need to add extra code for delivery_store_name in the above controller But I don't know how to get delivery_store_name.
Best Regards,
Using relation would be much more simpler.
// BookTransfer Model
public function sender(){
return $this->belongsTo(Book::class, 'sender_bookstore_id');
}
public function delivery(){
return $this->belongsTo(Book::class, 'delivery_bookstore_id ');
}
Your controller would look like this
$data = BookTransfer::with(['sender', 'delivery'])->get();
If you want to get the datas by join, you can join the same books table again, and alias it another name:
BookTransfer::join('books AS sender_books', 'sender_books.id', '=', 'book_transfers.sender_bookstore_id')
->join('books AS delivery_books', 'deliery_books.id', '=', 'book_transfers.delivery_bookstore_id')
->select(
'book_transfers.*',
'book_transfers.sender_bookstore_id AS sender_id',
'book_transfers.delivery_bookstore_id AS delivery_id',
'sender_books.store_name AS sender_store_name',
'delivery_books.store_name AS delivery_store_name'
)

Laravel 5.6 Eloquent ORM where join table

I am dealing with Eloquent ORM collections and query builders. I am trying to figure out how to join and use "where" in a collection, like in query builder.
For example, I have the following tables:
Users:
ID | Name | Last name
-------------------------
1 | Martin | Fernandez
2 | Some | User
Persons:
ID | Nick | User_ID | Active
----------------------------------
1 | Tincho | 1 | 1
Companies:
ID | Name | User_ID | Active
----------------------------------
1 | Maramal| 1 | 0
2 | Some | 2 | 1
This is an example, the tables I am working on have more than 30 columns each one. I want to select all the user that are active.
Usually I would do a query like:
SELECT *
FROM users
LEFT JOIN persons ON users.id = persons.user_id
LEFT join companies ON users.id = companies.user_id
WHERE persons.active = 1
OR companies.active = 1
That can be translated to Laravel Query Builder like:
DB::table('users')
->leftJoin('persons', 'users.id', '=', 'persons.user_id')
->leftJoin('companies', 'users.id', '=', 'companies.user_id')
->where('persons.active', 1)
->orWhere('companies.active', 1)
->get();
But what I want to use is a Laravel Eloquent ORM Collection, until now I am doing the following:
$users= User::orderBy('id',' desc')->get();
foreach($users as $k => $user) {
if($user->company && !$user->company->active || $user->person && !$user->person->active) {
unset($users[$k]);
}
... and here a lot of validations and unsets ...
}
But I know that at this point, I already grabbed all the users instead those who are active.
How would I achieve what I did with query builder within a collection? Thanks in advance.
This should do it:
$users = User::whereHas('companies', function($q) {
$q->where('active', true);
})->orWhereHas('persons', function($q) {
$q->where('active', true);
})->with(['companies', 'persons'])->orderBy('id', 'desc')->get();

Laravel (5.3) Eloquent - Relationship issue

I have the following 3 tables which are normalised:
`Table: TheMovies`
id | MovieName
---------------------
1 | Zootopia
2 | Moana
3 | Toy Story
`Table: TheGenres`
id | GenreName
---------------------
21 | Action
22 | Animation
23 | Adventure
`Table: mMoviesGenres`
movieID | genreID
---------------------
1 | 21
1 | 23
2 | 22
2 | 21
3 | 23
3 | 21
As you can see in the 3rd table a movie has multiple genres, and a genre has multiple movies.
I've created TheMovies and TheGenres models in laravel.
I made sure that the relationship is made inside the models using the following code:
class TheMovies extends Model
{
public function TheGenres() {
return $this->belongsToMany('App\TheGenres', 'mMoviesGenres', 'seriesID', 'genreID');
}
}
class TheGenres extends Model
{
public function TheGenres() {
return $this->belongsToMany('App\TheMovies', 'mMoviesGenres', 'genreID', 'seriesID');
}
}
I've tested everything, and I succeeded displaying a list of genres for a particular movie, and I also succeeded displaying a list of movies for a particular genre.
The actual problem is that I want to display related movies for a particular movie based on genre.
Let's take TheMovies.id = 1 which is similar with TheMovies.id = 3, they are both Action and Adventure as you can see in the third table.
I've found out the query which is needed based on the following post:
SQL Query based on other table.
SELECT m2.movieId
FROM mMoviesGenres m1
INNER JOIN mMoviesGenres m2
ON m1.genreID = m2.genreID
WHERE m1.movieId = 1 AND
m2.movieId <> 1
GROUP BY m2.movieId
HAVING COUNT(*) >= 2
But I don't know how to transform this query in Eloquent style, and yes I can make a raw query in Eloquent, but I want to make use of the relationship created.
Please give me some advice.
You can try as:
// returns array of genre_ids associate with the TheMovies.id => 1
$genre_ids = TheGenres::whereHas('TheMovies', function($q) {
$q->where('id', 1);
})->pluck('id')->toArray();
Then use those $genre_ids to fetch the related movies as:
TheMovies::whereHas('TheGenres', function($q) use($genre_ids) {
$q->whereIn('id', $genre_ids);
})->get();
Update
Assuming you have:
$genre_ids = [21, 23];
then your query can be as:
TheMovies::whereHas('TheGenres', function($q) use($genre_ids) {
$q->whereIn('genreID', $genre_ids)
->groupBy('movieID')
->havingRaw('COUNT(DISTINCT genreID) = 2');
})->get();
Note - I have not tested it but you can give it a try.

Laravel leftJoin AS

How can I make that query in Laravel Eloquent or Fluent?
DUELS
|id|userId1 | UserId2
-------------------------
|1| 1 | 4 |
|2| 3 | 2 |
|3| 2 | 1 |
-------------------------
USERS
|id| firstName |
----------------
|1| Bob |
|2| Hans |
|3| Jerome |
|3| Katy |
----------------
Query: get the names of the users in the duels where the user with $userId is participating:
SELECT u1.firstName AS user1FirstName, u2.firstName AS user2FirstName
FROM duels
LEFT JOIN users AS u1
ON userId1 = u1.id
LEFT JOIN users AS u2
ON userId2 = u2.id
WHERE userId1 = $userId || userId2 = $userId
Using Laravel's Fluent, to perform that query you need to do the following:
DB::table('users')->join('duels', function($join) use ($userId){
$join->on('users.id', '=', 'duels.userId1')
->orOn('users.id', '=', 'duels.userId2')
->where('users.id', '=', $userId);
})->get();
Using Laravel's Eloquent, however, you may consider the user as either first player, or as second player.
In your User model, define the above two relationships as such:
class User extends Eloquent{
/**
* ...
*/
public function duelsAsFirstPlayer(){
return $this->belongsToMany( 'App\User', 'duels', 'user_id_1', 'user_id_2');
}
public function duelsAsSecondPlayer(){
return $this->belongsToMany( 'App\User', 'duels', 'user_id_2', 'user_id_1');
}
}
Now, in order to get all the users the user with $userId has duels with, query the User model as such:
as first player:
$users = App\User::find($userId)->duelsAsFirstPlayer()->get();
or as second player:
$users = App\User::find($userId)->duelsAsSecondPlayer()->get();

Query relation in same table with Eloquent ORM in Laravel 4.1

I am just discovering Laravel, and getting into Eloquent ORM. But I am stumbling on a little issue that is the following.
I have three tables with the following structures and data :
words
id | language_id | parent_id | word
-------------------------------------------
1 | 1 | 0 | Welcome
-------------------------------------------
2 | 2 | 1 | Bienvenue
-------------------------------------------
documents
id | title
---------------------
1 | Hello World
---------------------
documents_words
document_id | word_id
--------------------------
1 | 1
--------------------------
As you see, we have a parent/child relationship in the words table.
The documents Model is defined as following
class Documents extends Eloquent {
protected $table = 'documents';
public function words()
{
return $this->belongsToMany('Word', 'documents_words', 'document_id');
}
}
And the words model :
class Word extends Eloquent {
protected $table = 'words';
public function translation()
{
return $this->hasOne('Word', 'parent_id');
}
}
Now my problem is that I want to retrieve documents that have translated words, so I thought this would do it :
$documents = Documents::whereHas('words', function($q)
{
$q->has('translation');
})
->get();
But I get 0 results, so I checked the query that Eloquent generates and uses :
select * from `prefix_documents`
where
(
select count(*) from
`prefix_words`
inner join `prefix_documents_words`
on `prefix_words`.`id` = `prefix_documents_words`.`word_id`
where `prefix_documents_words`.`document_id` = `prefix_documents`.`id`
and (select count(*)
from `prefix_words`
where `prefix_words`.`parent_id` = `prefix_words`.`id`) >= 1
) >= 1
The problem is that it doesn't use aliases for the tables, what my query should be more like this to work (and it does) :
select * from `prefix_documents`
where
(
select count(*) from
`prefix_words`
inner join `prefix_documents_words`
on `prefix_words`.`id` = `prefix_documents_words`.`word_id`
where `prefix_documents_words`.`document_id` = `prefix_documents`.`id`
and (select count(*)
from `prefix_words` as `w`
where `w`.`parent_id` = `prefix_words`.`id`) >= 1
) >= 1
But how can I do this with Eloquent ORM ?
Thanks a lot for your help guys, hope I am clear enough.
In the Word Model, change the
public function translation()
{
return $this->hasOne('Word', 'parent_id');
}
to
public function translation()
{
return $this->belongsToMany('Word', 'words', 'id', 'parent_id');
}
This way we are telling the Laravel to create an alias in the eloquent when using your query. I didn't test the other cases, but I think it will work.

Categories