How to pass condition in laravel 5 relation model - laravel

I am trying to get the data from group model but i am relate the student table new_group_id to group table id if it not null else connect the group_id to group table id.
public function grade(Builder $query)
{
return $query
->when($this->new_group_id != 0, function ($q) {
return $q->with('new_group_id');
})
->when($this->new_group_id === 0, function ($q) {
return $q->with('group_id');
});
}
But given the error is
Argument 1 passed to App\Students::grade() must be an instance of
App\Builder
please help me to solve these error

It looks as though you're using a query scope which Laravel will resolve and inject an instance of Builder into your function via the service container.
For this to happen though you need to follow the Laravel convention of prefixing your local scope with the word scope:
public function scopeGrade($query)
{
return $query
->when($this->new_group_id != 0,function($q){
return $q->with('new_group_id');
})
->when($this->new_group_id === 0,function($q){
return $q->with('group_id');
});
}

Related

In Laravel hasMany relationship How to use with and where?

In Job model :
public function jobApplications() {
return $this->hasMany(JobApplication::class, 'job_id');
}
In JobApplication Model
public function jobs()
{
return $this->belongsTo(Job::class, 'job_id');
}
In job_applications migration
$table->id();
$table->foreignId("job_id")->constrained("jobs");
$table->foreignId("user_id")->constrained("users");
$table->text('remarks')->nullable();
$table->unsignedInteger('status')->default(1);
I need to get all jobs and its job applications where job_applications.status = (user input status) and job_applications.user_id =authenticated users id. How can i get that?
Below is the syntax i tried, which returned undefined variable status
$jobs = Job::where('status',1);
$status =$request->status;
if($status){
$jobs = $jobs->whereHas('jobApplications', function($q){
$q->where('status',$status);
$q->where('user_id',Auth()->user()->id);
});
return $jobs->get();
Can any one sugest a solution?
If you use closer the variabl that is defined outside the closer is not accessible. so you should use it. Like this.
if($status){
$jobs = $jobs->whereHas('jobApplications', function($q) use($status){
$q->where('status',$status);
$q->where('user_id',Auth()->user()->id);
});
This will remove the error undefined veriable $status.
to use an external variable in closure method you need to pass that variable into method using "use" keyword like
if($status){
$jobs = $jobs->whereHas('jobApplications', function($q) use ($status) {
$q->where('status',$status);
$q->where('user_id',Auth()->user()->id);
});}
return $jobs->get();

Where clause in polymorphic relationship

I have the tables
threads
- id
replies
- id
- repliable_id
- repliable_type
I want to add another column to the Thread, which is the id of the most recent reply.
Thread::where('id',1)->withRecentReply()->get()
And the following query scope
public function scopeWithRecentReply() {
return $query->addSelect([
'recent_reply_id' => Reply::select('id')
->whereHasMorph('repliable', ['App\Thread'], function ($q) {
$q->where('repliable_id', '=', 'threads.id');
})->latest('created_at')
->take(1),
]);
}
I have also tried
public function scopeWithRecentReply() {
return $query->addSelect([
'recent_reply_id' => Reply::select('id')
->where('repliable_id', '=', 'threads.id')
->latest('created_at')
->take(1),
]);
}
But in both cases the
recent_reply_id => null
If instead of threads.id i enter an integer, it works and the recent_reply_id is not null
For example
public function scopeWithRecentReply() {
return $query->addSelect([
'recent_reply_id' => Reply::select('id')
->whereHasMorph('repliable', ['App\Thread'], function ($q) {
$q->where('repliable_id', '=', 1);
})->latest('created_at')
->take(1),
]);
}
My question is
Is there a way to be able to fetch the recent_reply_id using the respective threads.id ?
I would suggest using appends instead of query scopes so in your Thread model we will add
protected $appends = ['recent_reply_id'];
.....
public function replies () {
// you need to add here your relation with replies table
}
public function getRecentReplyIdAttribute () {
return $this->replies()->latest('id')->first()->id;
}
now wherever you query the threads table you will have access to recent_reply_id like
$thread = Thread::where('id',1)->withRecentReply()->get();
$thread->recent_reply_id;

How to get latest eloquent relationship by column name in Laravel

I am building a small application on Laravel 5.6 where I am having two models Project and Status. In this I am having a relation as such:
In Project Model I am having:
public function statusUpdate()
{
return $this->hasMany('App\Status','project_id','id');
}
and to retrieve latest status I have:
public function latestStatus()
{
return $this->hasOne('App\Status','project_id','id')->latest();
}
In status I have columns: date, status, sub_status, comments.
I want to retrieve Status where I am having latest status by date mentioned in the column
I tried doing this in my model:
public function latestStatus()
{
return $this->hasOne('App\Status','project_id','id')->latest('date');
}
But this thing is not working out, help me out in this. Thanks
edit
I am using this relation in eager loading something like this:
Project::when( $request->name , function( $q) use( $request ) {
$q->where('name', 'like', '%' . $request->name .'%');
})->with('latestStatus')
->orderBy($request->sort_by_col, $request->order_by)
->paginate(30);
You can use orderBy in the relationship.
public function latestStatus()
{
return $this->hasOne('App\Status','project_id','id')->orderBy('date', 'desc');
}
Try it out.
You got your models wrong. This is what should be in the Project model
public function statuses() //plural because a project has many statuses
{
return $this->hasMany('App\Status','id','project_id');
}
If you want the latest status, call this in your controller:
Project::where('name', 'like', "%{$request->name}%")->with('statuses', function($q) {
return $q->orderBy('date', $request->order_by);
})->paginate(30);
If you want the latest project where the status has changed, first the Status model:
public function project()
{
return $this->hasOne('App\Project','project_id','id');
}
And in your controller:
$project = Status::latest()->first()->project;
Add first to the end of the query.
public function latestStatus()
{
return $this->hasOne('App\Status','project_id','id')->latest()->first();
}
This is how it works
The statusUpdate method builds the query and does the setup for has many relationship
The latest method adds the order by clause
The first methods adds the limit 1 clause, then executes the query and returns the first result

Laravel oneToMany accessor usage in eloquent and datatables

On my User model I have the following:
public function isOnline()
{
return $this->hasMany('App\Accounting', 'userid')->select('rtype')->latest('ts');
}
The accounting table has activity records and I'd like this to return the latest value for field 'rtype' for a userid when used.
In my controller I am doing the following:
$builder = App\User::query()
->select(...fields I want...)
->with('isOnline')
->ofType($realm);
return $datatables->eloquent($builder)
->addColumn('info', function ($user) {
return $user->isOnline;
}
})
However I don't get the value of 'rtype' for the users in the table and no errors.
It looks like you're not defining your relationship correctly. Your isOnline method creates a HasMany relation but runs the select method and then the latest method on it, which will end up returning a Builder object.
The correct approach is to only return the HasMany object from your method and it will be treated as a relation.
public function accounts()
{
return $this->hasMany('App\Accounting', 'userid');
}
Then if you want an isOnline helper method in your App\User class you can add one like this:
public function isOnline()
{
// This gives you a collection of \App\Accounting objects
$usersAccounts = $this->accounts;
// Do something with the user's accounts, e.g. grab the last "account"
$lastAccount = $usersAccounts->last();
if ($lastAccount) {
// If we found an account, return the rtype column
return $lastAccount->rtype;
}
// Return something else
return false;
}
Then in your controller you can eager load the relationship:
$users = User::with('accounts')->get(['field_one', 'field_two]);
Then you can do whatever you want with each App\User object, such as calling the isOnline method.
Edit
After some further digging, it seems to be the select on your relationship that is causing the problem. I did a similar thing in one of my own projects and found that no results were returned for my relation. Adding latest seemed to work alright though.
So you should remove the select part at very least in your relation definition. When you only want to retrieve certain fields when eager loading your relation you should be able to specify them when using with like this:
// Should bring back Accounting instances ONLY with rtype field present
User::with('accounts:rtype');
This is the case for Laravel 5.5 at least, I am not sure about previous versions. See here for more information, under the heading labelled Eager Loading Specific Columns
Thanks Jonathon
USER MODEL
public function accounting()
{
return $this->hasMany('App\Accounting', 'userid', 'userid');
}
public function isOnline()
{
$rtype = $this->accounting()
->latest('ts')
->limit(1)
->pluck('rtype')
->first();
if ($rtype == 'Alive') {
return true;
}
return false;
}
CONTROLLER
$builder = App\User::with('accounting:rtype')->ofType($filterRealm);
return $datatables->eloquent($builder)
->addColumn('info', function (App\User $user) {
/*
THIS HAS BEEN SUCCINCTLY TRIMMED TO BE AS RELEVANT AS POSSIBLE.
ARRAY IS USED AS OTHER VALUES ARE ADDED, JUST NOT SHOWN HERE
*/
$info[];
if ($user->isOnline()) {
$info[] = 'Online';
} else {
$info[] = 'Offline';
}
return implode(' ', $info);
})->make();

Laravel 5 - Use 'isAdmin' role check method when querying a model

I have implemented a basic role system that uses a table 'role_user'.
On my user model I have a few methods that check the roles, one of them is:
public function isStaff()
{
foreach ($this->roles()->get() as $role)
{
if ($role->id == 3)
{
return true;
}
}
return false;
}
How can I use this method when I am querying users?
This query here:
return User::where('name', 'like', "%".$request->name."%")
->orWhere('email', 'like', "%".$request->name."%")
->whereDoesntHave('Teams', function ($query) use($teamId) {
$query->whereId($teamId);
})
->with('teams')
->get();
Currently returns all users, but I only wish to return users that have a role of 3 (isStaff)
You can using Scopes With Laravel instead of multiple methods to check for different methods.
public function scopeRole($query, $flag)
{
return $query->where('role', $flag);
}
and then
$users= User::role(3)->get();
check the reference tutorial for Creating Dynamic Scopes
it's better to do condition
return User::where('name', 'like', "%".$request->name."%")
->orWhere('email', 'like', "%".$request->name."%")
->whereDoesntHave('Teams', function ($query) use($teamId) {
$query->whereId($teamId);
})
->whereHas('roles', function($q) use ($role_id){
$q->where('id',$role_id);
})
->with('teams')
->get();
or also you can create a method for above query and based on param reurn result
You can have a scope called staff in your User model, then use that to narrow down your result:
public function scopeStaff($query, $roll_id = 3)
{
return $query->where('role_id', '=', $roll_id)
}
So when checking (with the model) for staff roles, you can improve the function that does that:
public function isStaff($role_id = 3)
{
return $this->role_id = $role_id ? $this : false;
}
Therefore, when using the query builder you can use the first method to narrow the result to those with the specified id, as you can see the default is 3 but will change to any value you give:
$staff_users = User::staff()->get();
Then the other one for verifying if a matched user model is a staff:
$user = User::find(1);
$is_staff = $user->isStaff(); //false or returns the same model
Hope this helps

Resources