Scope and Relation doesn't work together - Laravel - php

User Model
class User extends Authenticatable
{
use HasApiTokens,HasFactory, Notifiable;
protected $table = "users";
protected $primaryKey = 'ID';
public function scopeActive($query)
{
return $query->where('activated', 1);
}
public function followings()
{
return $this->hasMany('App\Models\Contacts','user_id','ID')->active();
}
Contacts Model
class Contacts extends Model
{
use HasFactory;
protected $table = "contacts";
protected $primaryKey = 'ID';
public function user()
{
return $this->belongsTo(User::class, 'user_id', 'ID');
}
When I call User::find(1)->followings()->count() on Tinker I get
BadMethodCallException with message 'Call to undefined method Illuminate\Database\Eloquent\Relations\HasMany::active()'
How can I get followings whose activated = 1 only?

I fixed it by adding a custom scope to Contacts model
public function scopeActiveFollowings($query)
{
return $query->join('users', function($join)
{
$join->on('users.ID', '=', 'contacts.contact_id')
->where('activated', '=', 1);
});
}

Laravel model has a property called query.
This property is used automatically when you call a query for the model
these two statements are exactly the same:
User::query()->where('id',1)->get();
User::where('id',1)->get();
When you call query() directly or indirectly, Laravel register the scopes in this line
when you use $this->hasMany('App\Models\Contacts','user_id','ID') the result will be from class HasMany and this class doesn't have a method called active(), this is why you see this error.
to fix it, you have to apply the scope when you use User model query:
$result=User::query()->activated()->with('followings')->findOrFail(1);
if you want the followings count for the activated user using scope, you should apply this scope on Following Model:
public function scopeHasActivedUser($query)
{
return $query->whereHas('user', function($query)
{
$query->where('users.activated', 1);
});
}
In the controller:
$fllowingsCountForActivatedUser=Fllowing::query()->hasActivedUser()->count();
If I were you, I would get the result this way:
$user=User::withCount(['followings'=>function($query){
$query->where('users.activated', 1)})])->find(1);
now the $user model instance should have a property called 'followings_count' for the only activated followings count

Related

Sort belongsToMany relation base on field in belongTo relation Laravel Eloquent

I have a scenario where User has a belongsToMany relation with PortalBreakdown, PortalBreakdown has a belongsTo relation with Portal. Portal has order column in it. I have a method listing_quota($id) in UserController which returns all breakdowns of the user. I want to sort these breakdowns based on order column of the portal. Below are the code of classes and a method I have tried.
class User extends Model {
protected $table = 'user';
public function listing_quota() {
return $this->belongsToMany('App\PortalBreakdown', 'user_listing_quota')->withPivot(['quota']);
}
}
class PortalBreakdown extends Model {
protected $table = 'portal_breakdown';
public function portal() {
return $this->belongsTo('App\Portal');
}
}
class Portal extends Model {
protected $table = "portal";
protected $fillable = ['name', 'description', 'order'];
}
Below is the method where I am trying to return sorted by order. I tried few things some of which can be seen in commented code but not working.
class UserController extends Controller {
public function listing_quota($id)
{
$user = User::with(['listing_quota' => function ($query) use ($id) {
// $query->sortBy(function ($query) {
// return $query->portal->order;
// });
}, 'listing_quota.portal:id,name,order'])->findOrFail($id);
// $user = User::with(['listing_quota.portal' => function ($q) {
// $q->select(['id', 'name',order']);
// $q->orderBy('order');
// }])->findOrFail($id);
return $this->success($user->listing_quota);
}
}
I also tried chaining orderBy directly after relation in Model class but that's also not working from me. Thank you in advance.
NOTE: I am using Laravel Framework Lumen (5.7.8) (Laravel Components 5.7.*)

Problem with Laravel Eloquent - relation not working

I'am beginner in Laravel. I have project in Laravel 5.8.
I have User model:
class User extends Authenticatable implements MustVerifyEmail
{
use Notifiable;
use psCMS\Presenters\UserPresenter;
use scopeActiveTrait;
public static $roles = [];
public $dates = ['last_activity'];
// ...
public function scopeHistory()
{
return $this->hasMany('App\UserLoginHistory');
}
// ...
}
and UserLoginHistory:
class UserLoginHistory extends Model
{
protected $quarded = ['id'];
public $timestamps = false;
protected $fillable = ['user_id', 'date_time', 'ip'];
public function user()
{
return $this->belongsTo('App\User');
}
}
I want show user login history by this code:
User::history()->where('id', $idAdmin)->orderBy('id', 'desc')->paginate(25);
but it's not working.
This function not working - I haven't got results.
How can I fixed it?
First of all, you are defining your relationship as a scope (prefixing the relationship with the scope keyword). Try updating your model relationship to this:
public function history()
{
return $this->hasMany('App\UserLoginHistory');
}
Then, given your query, it seems that you want to get all the UserLoginHistory
records for a given User. You could accomplish this in two ways (at least).
From the UserLoginHistory model itself, constraining the query by the foreign key value:
$userId = auth()->id(); // get the user ID here.
$results = UserLoginHistory::where('user_id', $userId)->paginate(15);
// ^^^^^^^ your FK column name
From the User model using your defined relationship:
$userId = auth()->id(); // get the user ID here.
$results = User::find($userId)->history;
The downside of the second approach is that you'll need to paginate the results manually.
in your User model you should define your relation by this way :
public function history()
{
return $this->hasMany('App\UserLoginHistory');
}
then if you would like to select with history model you can do that with WhereHas() method :
User::whereHas(['history'=>function($q) use ($idAdmin) {
$q->where('id',$idAdmin)
}])->orderBy('id', 'desc')->paginate(25);
You must be do this changes
public function history()
{
return $this->hasMany('App\UserLoginHistory');
}
usage
$user = User::find($idAdmin);
$userHistories = $user->history()->latest()->paginate(25);
or get user with all history
User::with('history')->find($idAdmin);
// Post model
namespace App;
use App\User;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
public function categories()
{
return $this->belongsToMany('App\Category')->withTimestamps();
}
}
// Category model
namespace App;
use Illuminate\Database\Eloquent\Model;
class Category extends Model
{
public function posts()
{
return $this->belongsToMany('App\Post')->withTimestamps();
}
}

Obtaining a list of non-linked models, in many_to_many relations, using Laravel Eloquent

I have a User-Roles model, using Laravel 4 where a user can have many roles, using Eloquent. I can access all roles linked to a user easily using this code :
class User extends Model {
protected $table = 'user';
protected $fillable = array('name');
public function rolesLinked() {
return $this->hasMany('App\UserRoleLink', 'user_id');
}
}
I've been trying to obtain the roles that are not linked to a user, to display on the specific user's page in a select box. Using this function, included in the User class.
public function rolesNotLinked() {
$user = this
$roles = Roles::whereDoesntHave('App\UserRoleLink',function($query) use ($user){
$query->where('user_id',$user->id);
});
}
The problem is, calling this function gives me the following error.
Call to undefined method Illuminate\Database\Query\Builder::App\UserRoleLink()
I've tried using has with < 1 to see if the function was problematic, but after reading this and the online source code, the function call pretty much does what I've tried.
Is something wrong in my function call, or have I messed up configurations somewhere?
For reference, here are my other Model classes:
class UserRoleLink extends Model{
protected $table = 'user_role_link';
protected $fillable = array('role_id','user_id);
public function role() {
return $this->hasOne('App\Role', 'role_id');
}
}
class Role extends Model{
protected $table = 'role';
protected $fillable = array('name');
}
EDIT: I've found out that I messed up by fillables when I copy-pasted. It didn't fix the issue, but I guess that's one step closer.
To use whereDoesntHave method, you must add the relation in your Role Model.
class Role extends Model{
protected $table = 'role';
protected $fillable = array('name');
public function UserRoles() {
return $this->hasMany('App\UserRoleLink', 'id');
}
}
Also, the whereDoesntHave method first parameter is not thte model but the function of the relation:
public function rolesNotLinked() {
$user = this
$roles = Roles::whereDoesntHave('UserRoles',function($query) use ($user){
$query->where('user_id',$user->id);
});
}

Laravel database error

Currently I'm making a ticket system with laravel.
But I'm not quite familiar with the database structure.
I've made two tables with migrations.
Called:
Tickets,
Comments
Obvisously a ticket can have multiple comments but a comment can only have one ticket. So it's a one to many relationship.
In the model of Tickets I've declared this:
class tickets extends Model
{
protected $fillable = ['title', 'content', 'slug', 'status', 'user_id'];
public function comments()
{
return $this->hasMany('App\comments', 'post_id');
}
}
In the model of Comments I've declared this:
class comments extends Model
{
protected $guarded = ['id'];
public function ticket()
{
return $this->belongsTo('App\tickets');
}
}
And this is my controller:
public function show($slug)
{
$ticket = tickets::whereSlug($slug)->firstOrFail();
$comments = $ticket->comments()->get;
return view('tickets.show',compact('ticket','comments'));
}
When exec this I receive the error:
ErrorException in TicketsController.php line 77: Undefined property:
Illuminate\Database\Eloquent\Relations\HasMany::$get
What am I doing wrong?
Thanks.
It seems you're trying to access the get property when i think your purpose is to call the get() method. Replace this:
$comments = $ticket->comments()->get;
with
$comments = $ticket->comments()->get();

Ordering of nested relation by attribute with laravel

Hi there i'm trying to sort a collection by attribute of the relation.
This is my model
class Song extends \Eloquent {
protected $fillable = ['title', 'year'];
public function artist(){
return $this->hasOne('Artist','id', 'artist_id');
}
}
class SongDance extends \Eloquent {
protected $table = 'song_dances';
protected $fillable = ['rating'];
public function dance(){
return $this->belongsTo('Dance', 'dance_id');
}
public function song(){
return $this->belongsTo('Song', 'song_id');
}
}
class Dance extends \Eloquent {
protected $fillable = ['name'];
public function song_dances(){
return $this->hasMany('SongDance','dance_id','id');
}
public function songs(){
return $this->belongsToMany('Song', 'song_dances', 'dance_id', 'song_id');
}
}
this is how far i'm by now:
$dance = Dance::find(1);
$songs = $dance->songs()
->with('artist')->whereHas('artist', function ($query) {
$query->where('urlName','LIKE','%robbie%');})
->where('song_dances.rating', '=', $rating)
->orderBy('songs.title','asc')
->where('songs.year', '=', 2012)
->get();
Yeah i just could add a ->sortBy('artist.name'); to the query, but he result-collection can be quite big (about 6000 items) therefore i would prefer a databased sorting.
is there a possibility to do this?
Since Eloquent's relations are all queried separately (not with JOINs), there's no way to achieve what you want in the database layer. The only thing you can do is sort the collection in your app code, which you've already dismissed.
If you feel you must sort it in the database then you should write your own join queries instead of relying on Eloquent's relations.

Categories