How to get model id from the global scope - laravel

Users are related to each other with many to many relationships.
I have a scope to check if a user is a friend of the user who sends the request.
There is a request that fetches all users.
I need to write a condition in my query to check if the pivot table contains an entry with the friend_id column equals to the id of the querying user. Here is the apply method of my scope:
class IsFriendScope implements Scope
{
public function apply(Builder $builder, Model $model)
{
if (!auth()->check()) return;
$id = $model->id;
$authId = auth()->id();
$builder->selectSub(function (\Illuminate\Database\Query\Builder $query) use ($authId, $id) {
$query->selectRaw("EXISTS(SELECT * FROM friendships WHERE user_id = $authId AND friend_id = $id)");
}, 'is_friend');
}
}
The query does not work, as the $model variable is always null. So what is the way of achieving this goal?

Try this
public function apply(Builder $builder)
{
$model = $builder->getModel();
}

Related

Eloquent 'with()' returns null

I have a simple relationship between two models: User and Prescription. A user has many prescriptions. In the PrescriptionsController, when I try to get the user that the prescriptions belongs to, it returns null when using with().
PrescriptionsController
public function index()
{
$user_id = Auth::id();
$prescriptions = Prescription::with('user')->where('prescription_for', $user_id)->get();
return response()->json($prescriptions);
}
The result from that Eloquent query:
[{"id":1,"prescription_for":1,"prescription_by":1,"prescription_content":"Paracetamol 120mg - O cutie. Mod administrare: 1 Dimineata | 0 Pranz | 0 Seara","created_at":"2020-10-13T17:33:35.000000Z","updated_at":null,"user":null}]
You can see that the last parameter is null.
In my User model, I have set up the relationship using:
public function prescriptions()
{
return $this->hasMany(Prescription::class);
}
And the Prescription model:
protected $table = 'prescriptions';
public $primaryKey = 'id';
public $timestamps = true;
public function user()
{
return $this->belongsTo(User::class);
}
I am using VueJs so I cannot just do $prescription->user->name as you can in Blade files, that's why I need to eager load the data.
The way I set up the Prescriptions table:
$table->id();
$table->unsignedBigInteger('prescription_for');
$table->foreign('prescription_for')->references('id')->on('users');
$table->unsignedBigInteger('prescription_by');
$table->foreign('prescription_by')->references('id')->on('users');
$table->string('prescription_content');
$table->timestamps();
Any ideas to why this happens? Thanks!
On your prescriptions table, your primary key is prescription_for. If the parent model does not use id as its primary key, or you wish to find the associated model using a different column, you may pass a third argument to the belongsTo() method specifying the parent table's custom key :
public function user()
{
return $this->belongsTo(User::class, 'id', 'prescription_for');
}

Laravel Eloquent How Can I Select Using Condition "where" for pivot table

I have three database tables called user(id,name), group(id,name) and user_group(user_id, group_id,valid_before) with relations many to many.
class User extends Model
{
protected $table = 'user';
public function groups()
{
return $this->belongsToMany(Group::class, 'user_group')
->withPivot('valid_before');
}
}
class Group extends Model
{
protected $table = 'group';
public $timestamps = false;
public function user()
{
return $this->belongsToMany(User::class, 'user_group');
}
}
How can I select all users (using Eloquent) who have
valid_before < $some_date
?
There are many ways to achieve this goal. I'll show you an example using query scopes.
In your User class you have to make a little update:
class User extends Model
{
protected $table = 'user';
public function groups()
{
return $this->belongsToMany(Group::class, 'user_group')
//->withPivot('valid_before'); <-- Remove this
}
}
and create a scope in your Group model:
class Group extends Model
{
protected $table = 'group';
public $timestamps = false;
public function user()
{
return $this->belongsToMany(User::class, 'user_group');
}
/**
* This scope gets as input the date you want to query and returns the users collection
*
* #param \Illuminate\Database\Eloquent\Builder $query
* #param string $date
* #return \Illuminate\Database\Eloquent\Builder
*/
public function scopeUsersValidBefore($query, $date)
{
return $query->users()->wherePivot('valid_before', '<', $date);
}
}
Now, I imagine you have a GroupController that somewhere creates a query to retrieve the valid before users. Something like:
// [...]
$users = Group::usersValidBefore($yourDate)->get();
// [...]
If you want to create the query from the other side, I mean you want to use the User model and list all the Users that has a pivot relation with valid_before populated, than the right approach is creating a UserGroup intermediate model that can be easily used to create a query.
If you are using Laravel 8.x.x
It's much easier with Inline Relationship Existence Queries
If you would like to query for a relationship's existence with a single, simple where condition attached to the relationship query, you may find it more convenient to use the whereRelation and whereMorphRelation methods. For example, we may query for all posts that have unapproved comments:
use App\Models\Post;
$posts = Post::whereRelation('comments', 'is_approved', false)->get();
Of course, like calls to the query builder's where method, you may also specify an operator:
$posts = Post::whereRelation(
'comments', 'created_at', '>=', now()->subHour()
)->get();

Laravel implicit binding with pivot relation on user

I don't think this is possible in Laravel, but I am still going to ask it ;)
I have a Group model that has a pivot relation(via group_user) to User. I have a group controller where this is the index method:
public function index(Request $request)
{
return $request->user()->groups;
}
groups in User is a belongsToMany relation. It will load all groups that have a relation to a user. This will also load the pivot table in the pivot relation.
But now I want to get a single group, this is the controller to get a group with pivot relation:
public function show($id, Request $request)
{
$group = $request->user()->groups()->findOrFail($id);
$this->authorize('view', $group); // Authorization....
return $group;
}
But I would like to use Implicit binding like this:
public function show(Group $group)
{
$this->authorize('view', $group);
return $group;
}
But it won't load the pivot table because I don't get it via the user...
So I should get the group via the user. But how can I do this with implicit binding?
When this isn't possible: How can I load a pivot relation when I already have the group model?
public function show(Group $group, Request $request)
{
// Load the pivot relation here in $group by using the user in $request->user()?
$this->authorize('view', $group);
return $group;
}
Put this is the RouteServiceProvider:
Route::bind('group', function ($value) {
if (auth()->check()) {
return auth()->user()->groups()->findOrFail($value);
} else {
abort(404);
}
});
The view policy isn't even needed this way because the group is from the groups relation:
public function show(Group $group)
{
return $group;
}

Retrieving relevant record from a relationship

I am allowing user to search by type which is passed into a function:
public function typeSearch($type)
{
$events = Event::where('type', $type)
->with('entities')
->get();
return view('events.searchResultEvents', compact('events'));
}
Which works nearly as it's supposed to do, it does retrieve the entities but not the right entities for example:
Event id = 25, entity_id = 2 it retrieves: Entities id = 25 while it should be 2.
How can I change this so it retrieves the right record?
Example::
Looking at the image, Event is = 25 and entity_id = 1. entity_id is a foreign key which is linked to id on 'entities' table
From Relations we have 'entities' with id = 25, while it should be 1 as entity_id = 1
Event model::
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Laravel\Scout\Searchable;
class Event extends Model
{
protected $table = 'events';
public $timestamps = true;
use Searchable;
public function entities()
{
return $this->belongsTo('App\Entity', 'id');
}
public function users()
{
return $this->belongsTo('App\User', 'id');
}
public function events()
{
return $this->belongsTo('App\DirtyEvent', 'id');
}
}
I think there's problem in your relations method.
public function entities()
{
return $this->belongsTo('App\Entity', 'id'); // Ithink you need to change it
}
Change that 'id' in your second parameter to 'entity_id'
public function entities()
{
return $this->belongsTo('App\Entity', 'entity_id');
}
The second parameter is used like this, I don't know how to explain it in technical but here's an example:
$event = Event::find(1);
//this will return the events with id=1 and that data have entity_id=2
$entities = $event->entities;
//If you set the second parameter in your Event model to 'id',
//this $entities variable contain the data from entities table with id=1, because your $event id=1
//But if you set the second parameter to 'entity_id'
//this $entities variable contain the data from entities with the id=2, because your $event entity_id=2

Trouble getting attribute of relation in Laravel

I'm having a trouble with a relation in Laravel 5. the thing is that I have a table User and that user belongs to a Group for that, in the User model I have this:
public function group(){
return $this->belongsTo('App\models\Group');
}
The model Group have this attributes: name,unity,level, init_date. I also put there a default function to return a group as String, this is the code:
public function __toString(){
return $this->name.' Unity '.$this->unity;
}
So, the thing that in a view a have many users and for each of them I want to display the unity, name,date. When I call $user->group it returns me correctly the name and the unity in a String (because the _toString function) that means that he is really querying the group perfectly, but then, when I want to access a simple attribute as unity,date,or name with $user->group->name Laravel gives me this error:
Trying to get property of non-object
I even tried $user->group()->name then I gets: Undefined property: Illuminate\Database\Eloquent\Relations\BelongsTo::$name
Edited:
The model User:
class User extends Model implements AuthenticatableContract, CanResetPasswordContract {
use Authenticatable, CanResetPassword;
protected $table = 'users';
protected $fillable = ['email', 'password','estate','filial_id','perfil_id','rol','cat_teacher'];
/**
* The attributes excluded from the model's JSON form.
*
* #var array
*/
protected $hidden = ['password', 'remember_token'];
public function __toString(){
return $this->email;
}
public function filial(){
return $this->belongsTo('App\models\Filial');
}
public function perfil(){
return $this->belongsTo('App\models\Perfil','perfil_id');
}
public function grupo(){
return $this->belongsTo('App\models\Group','group_id','id');
}
}
The model Group:
class Group extends Model {
protected $table = 'groups';
protected $fillable = ['name','unity','date'];
public function filiales() {
return $this->belongsTo('App\models\Filial');
}
public function teacher(){
return $this->belongsTo('App\models\User','teacher_id');
}
public function users() {
return $this->hasMany('App\models\User');
}
}
Then, in the controller I made a dd($users) and there not appear the relations, appears other relations but not this one. In the view I want to print some of the attributes in a table, for that I have:
<td>{{$user->group}}</td>
<td>{{$user->group->unity}}</td>
The first line works perfectly, and I donĀ“t know why.
The reason you're unable to return your group's name is that ->group() returns an instance of the query builder, and not an eloquent collection/object. Since a user belongs to a single group, modify your code in one of these two ways:
public function group(){
return $this->belongsTo('App\models\Group')->first();
}
And then access the group using one of the following methods:
$user = User::with("group")->where("id", "=", 1)->first();
$group = $user->group;
echo $group->name;
// OR
$user = User::where("id", "=", 1)->first();
$group = $user->group();
echo $group->name;
Or, leave the group() function as it is and access ->group()->first() on your $user object:
$user = User::where("id", "=", 1)->first();
$group = $user->group()->first();
echo $group->name;
Any of the above methods should properly return your group object's name (or other attributes). Check the Eloquent Documentation for detailed explanations on how to access these objects.

Resources