Laravel eloquent and relationship - laravel

I have a code:
$response = $this->posts
->where('author_id', '=', 1)
->with(array('postComments' => function($query) {
$query->where('comment_type', '=', 1);
}))
->orderBy('created_at', 'DESC')
->limit($itemno)
->get();
And when I logged this query with:
$queries = \DB::getQueryLog();
$last_query = end($queries);
\Log::info($last_query);
In log file I see follow:
"select * from `post_comments` where `post_comments`.`post_id` in (?, ?, ?, ?) and `comment_type` <> ?"
Why is the question mark for comment_type in the query?
Update #1:
I replaced current code with following and I get what I want. But I'm not sure it is OK. Maybe exists many better, nicer solution.
$response = $this->posts
->where('author_id', '=', 1)
->join('post_comments', 'post_comments.post_id', '=', 'posts.id')
->where('comment_type', '=', 1)
->orderBy('created_at', 'DESC')
->limit($itemno)
->get();

Behind the scene the PDO is being used and it's the way that PDO does as a prepared query, for example check this:
$title = 'Laravel%';
$author = 'John%';
$sql = "SELECT * FROM books WHERE title like ? AND author like ? ";
$q = $conn->prepare($sql);
$q->execute(array($title,$author));
In the run time during the execution of the query by execute() the ? marks will be replaced with value passed execute(array(...)). Laravel/Eloquent uses PDO and it's normal behavior in PDO (PHP Data Objects). There is another way that used in PDO, which is named parameter/placeholder like :totle is used instead of ?. Read more about it in the given link, it's another topic. Also check this answer.
Update: On the run time the ? marks will be replaced with value you supplied, so ? will be replaced with 1. Also this query is the relational query, the second part after the first query has done loading the ids from the posts table. To see all the query logs, try this instead:
$queries = \DB::getQueryLog();
dd($queries);
You may check the last two queries to debug the queries for the following call:
$response = $this->posts
->where('author_id', '=', 1)
->with(array('postComments' => function($query) {
$query->where('comment_type', '=', 1);
}))
->orderBy('created_at', 'DESC')
->limit($itemno)
->get();
Update after clarification:
You may use something like this if you have setup relation in your Posts model:
// $this->posts->with(...) is similar to Posts::with(...)
// if you are calling it directly without repository class
$this->posts->with(array('comments' =. function($q) {
$q->where('comment_type', 1);
}))
->orderBy('created_at', 'DESC')->limit($itemno)->get();
To make it working you need to declare the relationship in your Posts (Try to use singular name Post if possible) model:
public function comments()
{
return $this->hasmany('Comment');
}
Your Comment model should be like this:
class Comment extends Eloquent {
protected $table = 'post_comments';
}

Related

How to use where clause with local variable without passing a parameter in Laravel

I joined 2 tables and I want to display document_name from parent table(document_control_reviews) whose ID is currently posted in a child table (initial_approvals). The foreign key that holds the child document is 3.
If I hardcode the query with the ID = 3, I get the correct result just for testing purposes. But I want the documents to be display dynamically using $id instead of 3.
This hardcode test works fine when I use 3 as ID:
public function initial_approval(){
$approval_files = DB::table('document_control_reviews')
->leftJoin('initial_approvals', 'initial_approvals.document_control_review_id', '=', 'document_control_reviews.id')
->leftJoin('files', 'document_control_reviews.file_id', '=', 'files.id')
->select('document_control_reviews.*', 'initial_approvals.*', 'files.*')
->where('initial_approvals.document_control_review_id', '=', 3)
->get();
}
But I need a dynamic ID which is a local variable $id (as showed below):
public function initial_approval(){
$id = 3 //hardcoded. Here is where I'm stuck.
$docId = DocumentControlReview::find($id);
$approval_files = DB::table('document_control_reviews')
->leftJoin('initial_approvals', 'initial_approvals.document_control_review_id', '=', 'document_control_reviews.id')
->leftJoin('files', 'document_control_reviews.file_id', '=', 'files.id')
->select('document_control_reviews.*', 'initial_approvals.*', 'files.*')
->where('initial_approvals.document_control_review_id', '=', $id)
->get();
}
This is what I don't want. I dont need to pass any parameter. I don't need any argument in the method call.
public function initial_approval($id){
$approval_files = DB::table('document_control_reviews')
->leftJoin('initial_approvals', 'initial_approvals.document_control_review_id', '=', 'document_control_reviews.id')
->leftJoin('files', 'document_control_reviews.file_id', '=', 'files.id')
->select('document_control_reviews.*', 'initial_approvals.*', 'files.*')
->where('initial_approvals.document_control_review_id', '=', $id)
->get();
}
This piece of code won't work the way you intend to because here id is a collection not an integer.
$id = DB::table('document_control_reviews')->select('id')->get();
You think id will be an integer like $id = 3 but in fact here $id = Collection({"id"=>3},...) get() always return a collection.
What you are trying to do is unclear please elaborate with an example.
I finally figured it out. I simply use the where clause in my query where the child ID is a positive integer. And I get exactly what I wanted in this code below:
$approval_files = DB::table('document_control_reviews')
->leftJoin('initial_approvals', 'initial_approvals.document_control_review_id', '=', 'document_control_reviews.id')
->select('initial_approvals.*', 'document_control_reviews.*')
->where('initial_approvals.id', '>', 0)
->get();

Trouble converting an SQL query to Eloquent

Trying to get this query to work in eloquent
A user can be in multiple teams however I want to generate a list of users NOT in a specific team. The following SQL query works if executed directly but would like to make it cleaner by converting it to eloquent
SELECT * FROM users LEFT JOIN team_members ON team_members.member_id = users.id WHERE NOT EXISTS ( SELECT * FROM team_members WHERE team_members.member_id = users.id AND team_members.team_id = $team_id )
This should provide a list of all the users that are not members of team $team_id
This is a guess ad you do not give much info on your Eloqent models but here is a hint of where to go:
User::doesnthave('teamMembers', function($builder) use($team_id){
return $builder->where('team_members.team_id');
});
That is assuming you have a "User" model with a "teamMembers" relationship setup on it
You may have a closer look in the Laravel docs for doesntHave
Laravel 5.8
Let's assume you have model name "User.php"
& there is method name "teamMembers" in it.
Basic
$users = User::doesntHave('teamMembers')->get();
Advance
use Illuminate\Database\Eloquent\Builder;
$users = User::whereDoesntHave('teamMembers', function (Builder $query) {
$query->where('id', '=', {your_value});
})->get();
You can find details description in this link >>
https://laravel.com/docs/5.8/eloquent-relationships#querying-relationship-absence
Laravel 5.2
Example:
DB::table('users')
->whereExists(function ($query) {
$query->select(DB::raw(1))
->from('orders')
->whereRaw('orders.user_id = users.id');
})
->get();
Check this link for advance where clause:
https://laravel.com/docs/5.2/queries#advanced-where-clauses
You can use below example
$list = User::leftJoin('users', 'users.id', '=', 'team_members.member_id')
->whereNotExists(function ($query) use ($team_id) {
$query->from('team_members')
->whereRaw('team_members.member_id = users.id')
->where('team_members.team_id', '=', $team_id);
})
->get();

Laravel 5.5 can't get selected column data using belongsTo

I have 2 models (User & UsersDetails) in relation with Eloquent Laravel.
Model "User" Realation With 'SelDetails'
public function SelDetails {
return $this->belongsTo('App\UsersDetails', 'users_id');
}
I want to get only two column 'created_by_id', 'created_by_name' from SelDetails
UserController
$users = User::with(['SelDetails' => function($query){
$query->select(['created_by_id', 'created_by_name']);
}])
->where('is_active', '=', 0)
->orderBy('id', 'desc')
->get();
I am getting data from User but getting blank in SelDetails
[relations:protected] => Array
(
[SelDetails] =>
)
Please correct me.
guys thanks for your precious response on this issue. i got the solution via following way.
changes in "User" model Relation With 'SelDetails'
public function SelDetails {
#return $this->belongsTo('App\UsersDetails', 'users_id');// the old one
return $this->hasOne('App\UsersDetails', 'users_id');
}
changes in "UserController"
$users = User::with('SelDetails')->where('is_active', '=', 0)->orderBy('id', 'desc')->get();
that's the changes that I have made and got the result
Thanks
I might be wrong but it might be the array in select, try
$query->select('created_by_id', 'created_by_name');
Have you tried something like
$users = App\Book::with('author:id,name')->get(); from the documentation?
In your case it should looks like:
User::with('SelDetails:created_by_id,created_by_name')
->where('is_active', '=', 0)
->orderBy('id', 'desc')
->get();
with() method can take string (or array filled by strings) eg. relationName:column1,column2.

Eloquent / Laravel - Putting a WHERE Clause on a Reference Table With Chained Relationships

I have the following relationship functions in my Job model:
public function resourceTypes(){
return $this->belongsToMany('ResourceType', 'job_requests');
}
public function resources(){
return $this->belongsToMany('Resource', 'jobs_resources')->withPivot('flow_type', 'resource_type_id');
}
I am able to get an object with data from both of the above relationships using:
$job = Job::findorfail($projectId);
$result = $job->with('resources.resourceTypes')->get();
I would like to put a where clause on the jobs_resources pivot table - specifically on the column flow_type.
How would I do this?
Try something like this:
$job = Job::with('resources' => function($q) {
$q->with('resourceTypes')->where('flow_type',2);
})->findorfail($projectId);
In above you will get only those resources with flow_type = 2
I ended up using the following statement:
Job::with(['resources' => function ($query){
$query->wherePivot('flow_type', '=', '1' );
}, 'resources.resourceTypes'])->where('id', $projectId)->firstOrFail();
$result = DB::table('job')
->join('job_resources', 'job.id', '=', 'job_resources.job_id')
->join('job_requests', 'job_resources.request_id', '=', 'job_requests.id')
->where('job_resources.flow_type', '=', CONDITION)
->get();
Your table data is not clear from your input, but this method (query builder) should work

Eloquent ORM find by id and add where clause to a relationship model

Hey guys how you doing?
I'm trying to simply find by id and at the same time guarantee that a column from a relationship table is with a value.
I tried a few things but nothing works.
$tag = Tag::find($id)->whereHas('posts', function($q){
$q->where('status','=', 1);
})->get();
Also:
$tag = Tag::whereHas('posts', function($q) {
$q->where('status','=', 1);
})->where('id','=', $id)->get();
Can you help me?
It is a simple thing but I can't manage to do it...
You need to read on Eloquent docs. Learn what's find, first, get for that matter.
Your code does what you need, and more (a bit wrong though) ;)
$tag = Tag::find($id) // here you fetched the Tag with $id
->whereHas('posts', function($q){ // now you start building another query
$q->where('status','=', 1);
})->get(); // here you fetch collection of Tag models that have related posts.status=1
So, this is what you want:
$tag = Tag::whereHas('posts', function($q){
$q->where('status','=', 1);
})->find($id);
It will return Tag model or null if there is no row matching that where clause OR given $id.
Have you checked Query Scope ?
You can do this:
$tag = Tag::where('status', '=', 1)
->where('id', '=', 1, $id)
->get();

Resources