Laravel. Eloquent query - php

I got this query:
$users = DB::table('users')->whereExists(function($query)
{
$query->select(DB::raw(1))
->from('galleries')
->whereRaw('galleries.user_id = users.id');
})->get();
This query selects all users who have gallery. Problem is that I can't use eloquent releationships now. Whenever i try to loop like this:
#foreach ($user->gallery as $gallery)
{{$gallery->name}}
#endforeach
I get error:
Undefined property: stdClass::$gallery
It happens with all other tables. What am I doing wrong here? My realationships are defined and they work just fine, i got problems only in this query. Thanks.
EDIT
Since it's not eloquent query, could you show me example how to write query, into few tables with eloquent. For example, I need all users who have their status approved in example table

First, determine a relationship in the User class, like this:
class User {
// Determine relation to Example table
public function examples() {
return $this->hasMany('Example', 'user_id', 'id'); // second parameter is the foreign key
}
}
Then the query:
User::whereHas('examples', function( $query ) {
$query->where('status','approved');
})->get();

Related

How to select only one Column with scope of eloquent model?

I got two tables. Both have a relationship to each other. I´m trying to query both to get the matching results. This results get checked if they also have an column which matches with a parameter value.
I´m trying it with a scope and it work. I only need one column from the second table and I´m trying to use it as column in my first table when I got my result.
So the code works and I got an result but I´m trying to filter to select only one column from the second table.
My code look like that.
My controller:
public function test()
{
$UID='LQuupgYvnuVzbEoguY4TF8bnHUU2';
$event=Events::withState($UID)->get();
echo $event;
}
My model scope function:
public function scopeWithState($query,$UID){
return $query->with(['EventLiked' => function($query) use($UID) {
$query
->where('EventLiked.UID', $UID)
;
}]);
}
My hasMany relationship function:
public function EventLiked()
{
return $this->hasMany(EventLiked::class,'EID','ID')->select('State','UID','EID');
}
I would go for specifying columns inside closure.
New scope:
public function scopeWithState($query,$UID){
return $query->with(['EventLiked' => function($query) use($UID) {
$query
->where('EventLiked.UID', $UID)
->select('State');
}]);
}
Calling scope:
$event=Events::withState($UID)->get();
You're not getting expected results because Laravel splits it into 2 queries:
First, for selecting events.
Then it plucks EID
Second, when it looks for EventLiked where matching ID's is found (from second step) and loads as relationships.
So you want to change select statement only in 2nd query. Not in a first one

Laravel eloquent how to get relationships relationship?

I have Users table,Jobs table and JobStatus table. I get user jobs using relationship
return User::find($dto->getUserId())
->jobs()
This will return all user jobs as collection, not as relationship inside user model.
Now I need to get jobs statuses, but when I try this
User::find($dto->getUserId())
->jobs()
->statuses()
I get error Call to undefined method. I need to get statuses as collection so I can use where,sort by etc while getting them from db. Is there any way to do so?
I need to do something like this , but with statuses
return User::find($dto->getUserId())
->jobs()
->has('status')
->where('role','responsible')
->where('jobs.created_at','>=',Carbon::now()->subDays($dto->getPeriod())->toDateString())
->get();
To retrieve the jobs by filtering on the statuses relationship, you can do it like this:
$user->jobs()->whereHas('statuses', function ($query) {
// Perform filter on the query for jobs->statuses
})->get();
For more information about querying relationship existence: https://laravel.com/docs/7.x/eloquent-relationships#querying-relationship-existence
If you want to retrieve the statuses instances, you can do it like this:
$statuses = JobStatus::where('created_at', '>=', now())
->whereHas('jobs', function ($query) use ($user) {
$query->whereUserId($user->id);
})
->get();
Just use jobs without parenthesises to get the model itself :
User::find($dto->getUserId())
->jobs
->statuses;
define your statuses() function first with the relations in your model with the jobs
like many to many or one to many relationship
public function statuses(){
return $this->belongsToMany('App\Job')->withTimestamps();
}

Laravel - Get users for tickers

I understand this might be really simple but I cannot get my head around it.
Say I am fetching all tickets
$tickets = Ticket::all();
And with a single line, I want to fetch all the users associated with each ticker, (every ticket has a field with user_id), is there a single line of code, which can do it in Laravel. I can do the old way to loop though each ticket and fecth the details for each user as below, but am just looking for best practices here.
foreach($tickets as $ticket):
$ticket->user = User::find($ticket->user_id);
endforeach;
i'm assuming you have defined a correct relationship in your models.
You can use eloquent relationship of laravel to get all tickets of users
$tickets = User::with('tickets')->get();
to get data if user has at least one ticket you can use the below code
$tickets = User::has('tickets')->get();
To get all tickets only:
$tickets = Ticket::all();
and then in your blade you can do:
#foreach($tickets as $ticket)
// getting user using relationship
{{ $ticket->user->name }}
#endforeach
or to get tickets associated with user you can use
$tickets = Ticket::whereHas('user', function ($q) {
$q->with('user');
})
->get();
to know more about relationships visit this
The first, you declare relation model Ticket with model User:
This is code in model Ticket:
public function user()
{
return $this->hasOne('App\Model\User', 'user_id', 'id'); //id is the primary key in User table
}
then fetching all tickets with user info
$tickets = Ticket::load('user')->all();
or
$tickets = Ticket::with('user')->all();
If you want to get the list of all tickets where has user, with the user associated with each ticket, try this:
$tickets = Ticket::whereHas('user', function ($query) {
$query->with('user');
})
->get();
If you are sure that all tickets have an associated user, use this:
$tickets = Ticket::with('user')->get();

laravel 5.2 eloquent order by on relationship result count

I have two tables website_link and website_links_type. website_link is related website_links_type with hasmany relationship.
$this->website_links->where('id',1)->Paginate(10);
and relationship
public function broken()
{
return $this->hasMany('App\Website_links_type')->where('status_code','!=',"200");
}
Now I want to get result from website_link table but Orderby that result on count of broken relationship result.
There are many ways to solve this problem. In my answer I'll use two I know.
You can eagerload your relationship and use the function sortBy(). However I don't think you can use the paginate() functionality with this solution.
Example:
$results = Website_link::with('website_links_type')->get()->sortBy(function ($website_link) {
return $website_link->website_links_type->count();
});
See this answer
You can also use raw queries to solve this problem. With this solution you can still use the pagination functionality (I think).
Example:
$results = Website_link
::select([
'*',
'(
SELECT COUNT(*)
FROM website_links_type
WHERE
website_links_type.website_link_id = website_link.id
AND
status_code <> 200
) as broken_count'
])
->orderBy('broken_count')
->paginate(10);
You may have to change the column names to match your database.
You can not put WHERE condition in model file.
You just give relationship hasMany in model file.
And use where condition in controller side.
Refer this document.
Try this
Model file:
public function broken()
{
return $this->hasMany('App\Website_links_type');
}
Controller file:
$model_name->website_links->where('id',1)
->where('status_code','!=',"200")
->orderBy('name', 'desc')
->Paginate(10);

How to order by pivot table data in Laravel's Eloquent ORM

In my Database, I have:
tops Table
posts Table
tops_has_posts Table.
When I retrieve a top on my tops table I also retrieve the posts in relation with the top.
But what if I want to retrieve these posts in a certain order ?
So I add a range field in my pivot table tops_has_posts and I my trying to order by the result using Eloquent but it doesn't work.
I try this :
$top->articles()->whereHas('articles', function($q) {
$q->orderBy('range', 'ASC');
})->get()->toArray();
And this :
$top->articles()->orderBy('range', 'ASC')->get()->toArray();
Both were desperate attempts.
Thank you in advance.
There are 2 ways - one with specifying the table.field, other using Eloquent alias pivot_field if you use withPivot('field'):
// if you use withPivot
public function articles()
{
return $this->belongsToMany('Article', 'tops_has_posts')->withPivot('range');
}
// then: (with not whereHas)
$top = Top::with(['articles' => function ($q) {
$q->orderBy('pivot_range', 'asc');
}])->first(); // or get() or whatever
This will work, because Eloquent aliases all fields provided in withPivot as pivot_field_name.
Now, generic solution:
$top = Top::with(['articles' => function ($q) {
$q->orderBy('tops_has_posts.range', 'asc');
}])->first(); // or get() or whatever
// or:
$top = Top::first();
$articles = $top->articles()->orderBy('tops_has_posts.range', 'asc')->get();
This will order the related query.
Note: Don't make your life hard with naming things this way. posts are not necessarily articles, I would use either one or the other name, unless there is really need for this.
For Laravel 8.17.2+ you can use ::orderByPivot().
https://github.com/laravel/framework/releases/tag/v8.17.2
In Laravel 5.6+ (not sure about older versions) it's convenient to use this:
public function articles()
{
return $this->belongsToMany('Article', 'tops_has_posts')->withPivot('range')->orderBy('tops_has_posts.range');
}
In this case, whenever you will call articles, they will be sorted automaticaly by range property.
In Laravel 5.4 I have the following relation that works fine in Set model which belongsToMany of Job model:
public function jobs()
{
return $this->belongsToMany(Job::class, 'eqtype_jobs')
->withPivot(['created_at','updated_at','id'])
->orderBy('pivot_created_at','desc');
}
The above relation returns all jobs that the specified Set has been joined ordered by the pivot table's (eqtype_jobs) field created_at DESC.
The SQL printout of $set->jobs()->paginate(20) Looks like the following:
select
`jobs`.*, `eqtype_jobs`.`set_id` as `pivot_set_id`,
`eqtype_jobs`.`job_id` as `pivot_job_id`,
`eqtype_jobs`.`created_at` as `pivot_created_at`,
`eqtype_jobs`.`updated_at` as `pivot_updated_at`,
`eqtype_jobs`.`id` as `pivot_id`
from `jobs`
inner join `eqtype_jobs` on `jobs`.`id` = `eqtype_jobs`.`job_id`
where `eqtype_jobs`.`set_id` = 56
order by `pivot_created_at` desc
limit 20
offset 0
in your blade try this:
$top->articles()->orderBy('pivot_range','asc')->get();
If you print out the SQL query of belongsToMany relationship, you will find that the column names of pivot tables are using the pivot_ prefix as a new alias.
For example, created_at, updated_at in pivot table have got pivot_created_at, pivot_updated_at aliases. So the orderBy method should use these aliases instead.
Here is an example of how you can do that.
class User {
...
public function posts(): BelongsToMany {
return $this->belongsToMany(
Post::class,
'post_user',
'user_id',
'post_id')
->withTimestamps()
->latest('pivot_created_at');
}
...
}
You can use orderBy instead of using latest method if you prefer. In the above example, post_user is pivot table, and you can see that the column name for ordering is now pivot_created_at or pivot_updated_at.
you can use this:
public function keywords() {
return $this->morphToMany(\App\Models\Keyword::class, "keywordable")->withPivot('order');
}
public function getKeywordOrderAttribute() {
return $this->keywords()->first()->pivot->order;
}
and append keyword attribiute to model after geting and use sortby
$courses->get()->append('keyword_order')->sortBy('keyword_order');

Categories