Query with pivot table laravel 5.1 - php

Query with pivot table laravel
Mappings
I am having a trouble with pivot query.
App/Entities/user.php
public function roles()
{
return $this->belongsToMany('App\Entities\UserRole', 'user_user_roles', 'user_id', 'user_role_id');
}
public function getPivotCondition($roleId)
{
return $this->roles()->wherePivot('user_role_id','=',$roleId);
}
Controller
use App/Entities/user;
public function getUserWithRole(user $User){
$users = $User->getPivotCondition(1)->get();
dd($users);
}
It results in a query
SELECT `user_roles`.*,
`user_user_roles`.`user_id` AS `pivot_user_id`,
`user_user_roles`.`user_role_id` AS `pivot_user_role_id`
FROM `user_roles`
INNER JOIN `user_user_roles`
ON `user_roles`.`id` = `user_user_roles`.`user_role_id`
WHERE `user_user_roles`.`user_id` IS NULL
AND `user_user_roles`.`user_role_id` = '1'
my question is that why i am getting user_user_roles.user_id is null in my query
I know that i can use WhereHas but i am looking for an alternative.I can use wherePivot('user_role_id','=',$roleId,'or'); else orWherePivot but it will result in query condition to or.

Related

Laravel latest not working (not appearing in my SQL query)

So I have a Student model with this function:
public function latestStatus()
{
return $this->hasOne(StatusStudent::class)->latest();
}
then I just do a query with this latestStatus()
$query = Student::findOrFail(1);
$query = $query->whereHas('latestStatus', function($query) use ($statusuri) {
$query->where('status_id', 1);
});
dd($query->toSql());
and the toSql() function returns:
"select * from `students` where exists (select * from `status_student` where `students`.`id` = `status_student`.`student_id` and `status_id` = ?)
as if latest() is ignored.
Why doesn't latest() add anything to the query?
Thanks.
Edit:
I tried adding selectRaw for example:
public function latestStatus()
{
return $this->hasOne(StatusStudent::class)->selectRaw('MAX(status_student.id)');
}
and still nothing appears in my query.
If you dig deeper to the whereHas() relationship. It calls the has() method then if you look for the has() method you will see the getRelationWithoutConstraints() method, means that it will call the relationship but it will remove all the constraints attach to it and will only call the base query instance :
public function latestStatus()
{
return $this->hasOne(StatusStudent::class)->latest(); // the latest() will be removed in the query if you call the `latestStatus` using the `whereHas() or has()`
}
so if you use the whereHas() like the way you use it :
"select * from `students` where exists (select * from `status_student` where `students`.`id` = `status_student`.`student_id` and `status_id` = ?)
it will return the query with out the latest().
Instead of doing it like that you can do it like :
Student Model
public function status() : HasOne
{
return $this->hasOne(StatusStudent::class);
}
Controller
$student = Student::findOrFail(1);
$student->whereHas('status', function($query) {
$query->where('status_id', 1)
->latest();
})
But since the relationship is define as one-to-one :
$student = Student::findOrFail(1);
$student->load('status');
or
$student = Student::findOrFail(1)->status()->get();
Maybe you want to get the latest of all the status.
StudentStatus::query()->latest()->get();
As stated in a comment by #matticustard,
findOrFail() returns a model, not a query builder.
Instead of findOrFail(1) use where('id', 1)

how to query whereHas on a belongs to many relationship using laravel

hi i am having a User and Task model and they have a many to many relation ship like below i added :
public function users()
{
return $this->belongsToMany(User::class,'user_tasks');
}
and in my user model :
public function tasks()
{
return $this->hasMany(Task::class);
}
and in my controller i want to get the task that are assigned to the logged in user like below :
$task = Task::whereHas('users', function(Builder $query){
$query->where('id',Auth::user()->id);
})->get();
dd($task);
but i get this error :
SQLSTATE[23000]: Integrity constraint violation: 1052 Column 'id' in where clause is ambiguous (SQL: select * from `tasks` where exists (select * from `users` inner join `user_tasks` on `users`.`id` = `user_tasks`.`user_id` where `tasks`.`id` = `user_tasks`.`task_id` and `id` = 4))
and when i change the id to users.id i get empty value but when i load it like below :
$task = Task::with('users')->get();
i get all the task with the relationships and they are working well but with whereHas its not working
thanks in advance
Since you are dealing with the pivot table with this relationship you can use the pivot table field user_id to filter:
$task = Task::whereHas('users', function (Builder $query) {
$query->where('user_id', Auth::user()->id);
})->get();
why not just:
$userTasks=Auth::user()->tasks;
this will get the current user tasks.

laravel querying many to many

I have 2 models, Service and Category. They are related with a many-to-many relationship like so:
Service.php
public function categories()
{
return $this->belongsToMany('App\Category')->withTimestamps();
}
Category.php
public function services()
{
return $this->belongsToMany('App\Service')->withTimestamps();
}
And of course they're joined by a pivot table:
category_service
- category_id
- service_id
- created_at
- updated_at
I'd like to use local scope to filter service result based on IDs of categories. I've done the following:
Service.php
public function scopeFilter($query, $category_ids)
{
$services = Service::whereHas('categories', function (Builder $query) use ($category_ids) {
$query->whereIn('category_id', $category_ids)->get();
});
return $services;
}
But I'm getting a Column not found error, specifically:
Column not found: 1054 Unknown column 'services.id' in 'where clause' (SQL: select * from `categories` inner join `category_service` on `categories`.`id` = `category_service`.`category_id` where `services`.`id` = `category_service`.`service_id` and `category_id` in (1, 2))
1 and 2 are the category IDs I pass.
I wrote the function based on the answer I found here and here.
Any pointers?
Your error message show that your query is begin with categories and without join services.
So put the ->get() outside the closure.
public function scopeFilter($query, $category_ids)
{
$services = Service::whereHas('categories', function (Builder $query) use ($category_ids) {
$query->whereIn('category_id', $category_ids);
})->get();
return $services;
}

Laravel Builder Scope with Union and many-to-many relationship

I have a notifications table (and model)
notifications table columns are thus:
id
title
body
is_public
...
I also have a users table (and model)
users table columns:
id
username
...
I also have a pivot notification_user table
columns:
user_id
notification_id
many-to-many relationship is set on both Notification and User models thus:
Notification.php
public function users()
{
return $this->belongsToMany('App\Api\V1\Models\User');
}
User.php
public function notifications()
{
return $this->belongsToMany('App\Api\V1\Models\Notification');
}
Now inside Notification.php I want to set a scope. In the scope I need to get public notifications and the current user's
private notifications in a single SQL query. from my table structure, public notifications are where is_public == 1. Private notifications are associated on the pivot table.
to achieve this, inside my Notification.php, I also have this setup:
public function scopePublicAndPrivate(Builder $query)
{
return $this->public($query)->union($this->private($query));
}
public function scopePublic(Builder $query)
{
return $query->where('is_public', 1);
}
public function scopePrivate(Builder $query)
{
$user = JWTAuth::parseToken()->authenticate(); //using JWT to get a user.
return $user->notifications();
}
Now when I try Notification::publicAndPrivate()->get() inside a controller, I get:
Illuminate\Database\QueryException with message 'SQLSTATE[21000]: Cardinality violation: 1222 The used SELECT statements have a different number of columns (SQL: (select * from `notifications` where `is_public` = 1) union (select * from `notifications` inner join `notification_user` on `notifications`.`id` = `notification_user`.`notification_id` where `notification_user`.`user_id` = 1))
Please I'll appreciate any help with getting this to work or a better solution.
I believe you should change:
return $user->notifications();
to something else, for example:
return $query->where('user_id', $user->id);
or maybe
return $query->whereHas('users', function($q) use ($user) {
$q->where('id', $user->id);
});
This is because in one query you are not using any join and in second you do and you are getting different number of columns for union parts.

Left join with Where in Eloquent ORM

I'm trying to write this SQL query with Eloquent ORM but still no success:
SELECT *
FROM article
LEFT JOIN article_category
ON article.category_id = article_category.id
WHERE article_category.name_url = 'html'
LIMIT 10`
This is what I've came up with so far (I try to write it with only one query just like above):
ArticleCategory::where('name_url', '=', 'html')->with('articles')->get();
But it shows an error:
Column not found:
1054 Unknown column 'article.article_category_id' in 'where clause'
(SQL: select * from `article` where `article`.`article_category_id` in (1))
My models:
class Article extends Eloquent {
protected $table = 'article';
public function categories() {
return $this->belongsTo('ArticleCategory', 'category_id');
}
}
class ArticleCategory extends Eloquent {
protected $table = 'article_category';
public function articles() {
return $this->hasMany('Article');
}
}
You can change your relationship function to use the correct ID.
public function articles() {
return $this->hasMany('Article', 'category_id');
}
It expects the column category_id to actually be named article_category_id. It expects this because it is referencing the table artice_catigory, so article_category_id makes sense.
If possible, just rename your column in the table article to article_category_id and everything should be good.
You can use left join using eloquent orm as follows
Article::leftJoin('article_category', 'article.category_id', '=', 'article_category.id')
->select(['*'])->where('article_category.name_url','html')->take(10)->get();

Categories