Laravel pass variable from controller query to model function - laravel

I have a function on my model that check active status in equipment_station table,
originally it only checked one status, now i need to pass a parameter to the model with active or inactive values, I've tried this with no success.
controller:
model :
How can i change the parameter in the model, I send status from controller as inactive or active.
thanks in advance

You could you query scope
public function scopeActive($query, $active)
{
return $query->where('active', $active);
}
then you can call it in your model
Estacion::active(true)->get();

You could Constraint Eager Loading by specifying additional query constraints for the eager loading
$historial_estaction =
Estacion::where('estacion.id', $id)
->whereHas('equipos', function($query) use ($estado1) {
$query->where('equipo_estacion.estado', $estado1);
})->with(['equipos' => function ($query) use ($estado1) {
$query->where('estado', $estado1);
}])->get();
Model:
public function equipos()
{
return $this->belongsToMany('App\Equipo')
->withPivot('estado')
->withTimestamps();
}

Related

Laravel nested `hasOne` relationship with `where` clause

I have Shop model which has multiple Content entries:
public function contents(): HasMany
{
return $this->hasMany(Content::class);
}
And I had hasOne relationship with one specific type of content like this:
public function widgetContent(): HasOne
{
return $this->hasOne(Content::class)->where('type', Content::WIDGET);
}
It was working fine but I moved Content's type into a new model called ContentType, and removed the type field from Content model, but instead added another hasOne relationship via content_type_id field.
Now, I'm trying to achieve the same widgetContent relationship but I can't. Here's my code:
public function widgetContent(): HasOne
{
return $this
->hasOne(Content::class)
->whereHas('contentType', fn ($q) => $q->where('type', ContentType::WIDGET));
}
What should I do to achieve this? Also, if this is not the best practice (that's how I feel), what is the best practice?
You could create a closure and use that in stead. So you would still have the relationship like this:
public function content(): HasOne
{
return $this
->hasOne(Content::class);
}
But then you add a closure in your model:
public function getWidgetContent()
{
return $this->content()->whereHas('contentType', function(Builder $q){
$q->where('type', ContentType::WIDGET)
})->get();
}
And then you just call the closure function when you need the results.

Sort inside the with in laravel

$posts = PostUrl::with(['post' => function ($q) {
$q->orderBy('created_at', 'DESC');
}])
->where('category','like' ,'%'.$cat.'%')
->paginate(8);
How can I sort the result as per the created_at of the post inside?
When try to ->orderBy('post.created_at','DESC') it show column not found.
Add PostUrl models
public function post(){
return $this->hasMany('App\Post', 'postid')->orderBy('created_at', 'DESC');
}
Controller :
$posts = PostUrl::with(['post'])->where('category','like' ,'%'.$cat.'%')->paginate(8);
Make sure you have established correctly in your PostUrl model the relationship with your Post model (if it is so called). You should have a function similar to the following in your model in order to with() method works correctly in the controller:
public function post(){
return $this->hasMany('App\Post', 'postid');
}
This way there should be no problem for the orderBy clause to work properly.

Laravel error using with() method in Eloquent

I'm trying to call using with() method in Laravel Eloquent ORM, but getting the following error.
Argument 1 passed to
App\Http\Controllers\DashboardController::App\Http\Controllers\{closure}()
must be an instance of Illuminate\Database\Eloquent\Builder,
instance of Illuminate\Database\Eloquent\Relations\HasMany given
I'm using the latest version of Laravel 6. Any ideas what might have caused this?
Controller
class DashboardController extends Controller
{
public function __construct()
{
$this->middleware('auth:api');
}
public function formIndex(Request $request)
{
$id = auth()->user()->id;
$item = Groupe::find($id)->with(
[
'etudiants' => function (Builder $query) {
$query->select('id');
}
]
)->first();
return $item;
}
}
Model
class Groupe extends Authenticatable implements JWTSubject
{
public function etudiants()
{
return $this->hasMany('App\Etudiant');
}
}
The error comes from the type hint you put on the $query variable, as the error message said the object that gets passed in there is a relationship not a raw Query Builder. Just remove the type hint. Also ::find() executes a query, so you're be executing 2 queries, use the query below instead
Groupe::where('id', $id)->with(['etudiants' => function ($query) {
$query->select('id');
}])->first();
Additionally, you don't need to use the callback syntax to only eager load certain columns, the callback syntax is for putting contraints on which records get returned. Try this instead.
Groupe::where('id', $id)->with('etudiants:id,name,email')->first();
But what do you want return? groupe->students[]?? you can use
$item = Groupe::where('id',$id)->with('etudiants')->first();

Weird behaviour of Eloquent One To One relationship

I need to get User with related Profile, but In case below the profile field is null:
Route::get('/user', function (Request $request) {
return $request->user()->load('profile'); // { id: 1, ... profile: null }
});
But in this case the profile field is filled:
Route::get('/user', function (Request $request) {
$user = $request->user();
$profile = $user->profile;
return $user; // { id: 1, ... profile: { name: 'alex', ... } }
});
How can you explain this behavior and what is the correct way to load Profile in my case?
Relations:
public function user(){
return $this->belongsTo('App\Models\User');
}
public function profile(){
return $this->role == 'model' ? $this->hasOne('App\Models\Model\Profile') : $this->hasOne('App\Models\Client\Profile');
}
load() is Lazy Eager Loading
Using load(), you nedd to run the initial query first, and then eager load the relation at some later point. This is "Lazy" eager loading. lazy eager load a relationship after the parent model has already been retrieved.
laravel with() method versus load() method
Go through this for a clear view Eager loading
So to get relationship using with() it will run both queries at same time and will have relation attached to model collection but while using load() first we get the model then on some condition we use load to get relational data. e.g. :
$users = User::all(); //runs first query
if($condition) {
$users = $users->load('organisations'); //lets assume organisations is relation here.
//here runs the 2nd query
}
Hope this helps.

Laravel - How to get data from a table related with pivot table

I have this model for notifications table:
class Notification extends Model
{
public function users()
{
return $this->belongsToMany(User::class, 'notification_user', 'notification_id', 'user_id');
}
}
And this method in controller for getting data from notifications where id of notifications is related to a pivot table named notification_user:
$myNotifications = DB::table('notification_user')
->join('notifications', 'notifications.id', 'notification_user.notification_id')
->where('notification_user.user_id', $userId)
->where('notification_user.seen', 0)
->get();
the result of $myNotifications is correct but I want to use Model and its relationship instead of DB.
How can I get all records in notifications where each notification related to a specific user which is not seen by the user.
You need to add ->withPivot('seen') to the relationship:
public function users()
{
return $this
->belongsToMany(User::class, 'notification_user', 'notification_id', 'user_id')
->withPivot('seen');
}
Then you can do:
Notification::whereHas('users', function ($q) use ($userId) {
$q->where('id', $userId)->where('seen', 0);
})->get();
To avoid joining users, your other option is whereExists:
Notification::whereExists(function ($q) use ($userId) {
$q
->selectRaw(1)
->table('notification_user')
->whereRaw('notifications.id = notification_user.notification_id')
->where('user_id', $userId)
->where('seen', 0);
})->get();
Should still be more performant, but not much more elegant.
You will have to define the same relation in User model as notifications and then:
$notifications = User::where('id', $user_id)->notifications()->where('seen', 0)->get();
You can use with keyword for eager loading inside your controller.
like if you have any relation defined inside your model, just add a with('modelRelation') before your get() statement in eloquent.
Happy Coding.

Resources