Laravel scope query wherePivot - php

I am trying to better at using scopes to make cleaner calls to specific information.
Currently I have a weeks, workouts and week_workout tables. I am trying to get a workout for Carbon->today(). To do this I need to access the date field on the week_workout table.
week_workout
| week_id | workout_id | date
Workout.php
public function weeks(){
return $this->belongsToMany('App\Week')
->withPivot( ['program', 'warmup', 'date'] )
->orderBy('date', 'asc');
}
public function scopeToday($query)
{
return $query->with('weeks')->wherePivot('date', Carbon::today());
}
Controller
$workouts = Workout::today()->get();
When I do this I get `Column not found: 1054 Unknown column 'pivot' in 'where clause' (SQL: select * from `workouts` where `pivot` = date)
I am not sure why its looking for pivot column. The docs seem to suggest it will look for date in the pivot table if I load it with the relationship but it appears I am missing something.

So it looks like you have to use whereHas. I updated the scope to just take any date to make it more powerful:
public function scopeDate($query, $date)
{
return $query->whereHas('weeks', function ($q) use($date){
$q->where('date', $date);
});
}
then in the controller:
$workouts = Workout::date( Carbon::today() )->get();

Related

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;
}

How replace join query with whereHas?

I am using Laravel 5.6 and i have a standard query
Order::where('dict_statuses_id', 1)
->leftJoin('dict_statuses', 'dict_statuses_id', '=', 'dict_statuses.id')
->get();
So i have list of orders with details where status = 1 (new) after join table i see status as New or Complete. Is any way to change this query using whereHas ?
i tried use
Order::whereHas('status', function($q){
$q->where('dict_statuses_id', 1);
})->get();
But no results, in model Order i have
public function status()
{
return $this->hasMany('App\DictStatuses');
}
[Updated]
i have an error:
Column not found: 1054 Unknown column 'dict_statuses.orders_id'
in 'where clause' (SQL: select * from `orders` where exists
(select * from `dict_statuses` where `orders`.`id` = `dict_statuses`.`orders_id` and `dict_statuses_id` = 1)
and `orders`.`deleted_at` is null)
In my table i have table Orders where is field: dict_statuses_id
and table dict_statuses with fields: id, public_name
Why error is about dict_statuses.orders_id
Try Order::has('status')->get();
You can pass in variables to a relationship so you could potentially do.
public function status($id) {
return $this->hasMany(DictStatuses::class)->where('dict_statuses_id', $id);
}
Try defining the local key & foreign key.
$this->hasMany(DictStatuses::class, 'foreign_key', 'local_key');
I think your dict_statuses doesn't have a column called order_id.
Please include that column in your migration
then call
Order::whereHas('status', function($q){
$q->where('dict_statuses_id', 1);
})->get();
in your controller
or change the relation in Order model as
public function status(){
return $this->belongsTo('App\DictStatuses'):
}

Laravel Eloquent - Query builder cant find column with having function

I have a pivot table 'game_genre'(with game_id and genre_id). The game and genre model has a belongsToMany relationship similar to example below.
I have been attempting to gather the games which contain both genre_id of 60 and 55 together. I have been getting the correct result using the following SQL query, but when using the following query builder I end up getting a column not found error when using the having() function.
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'genre_id' in 'having clause'
Im not sure how else to structure the query builder?
MODEL:
class Game extends Model
{
public function genres()
{
return $this->belongsToMany('App\Genre');
}
}
SQL:
SELECT *
FROM game_genre
WHERE genre_id = 55 OR genre_id = 60
GROUP BY game_id
HAVING COUNT(DISTINCT genre_id) = 2;
CONTROLLER:
$game = Game::whereHas('genres', function ($query)
{
$query->where('genre_id', '55')
->orWhere('genre_id', '60')
->groupBy('game_id')
->having('genre_id','=', 2);
})->get();
You forgot the aggregate function (in this case COUNT) in your HAVING condition:
$query->where('genre_id', '55')
->orWhere('genre_id', '60')
->groupBy('game_id')
->havingRaw('COUNT(DISTINCT genre_id) = 2');
Instead of adding several where() and orWhere() to your query, you could also use whereIn() which takes an array:
$myArray = [55,60];
$query->whereIn('genre_id', $myArray)
->groupBy('game_id')
->havingRaw('COUNT(DISTINCT genre_id) = 2');
You can use the following query to get the Games which contain both genre_id of 60 and 55:
$games = Game::whereHas('genres', function ($query) {
$query->where('genre_id', '55');
})
->whereHas('genres', function ($query) {
$query->where('genre_id', '60');
})
->get();

Laravel 5 - Find Fields on "MorphOne" Relationship

I'm quite new to Laravel and I'm now facing this issue while trying to create a query:
I have the following Morphable classes:
\App\User
class User {
public function userable()
{
return $this->morphTo();
}
}
\App\Distributor
class Distributor {
public function user()
{
return $this->morphOne('App\User', 'userable');
}
}
user table has the fields: name, email, status, userable_type and userable_id.
distributor table has the fields: store_code and location_id.
By using Eloquent, i need to start the query from Distributor model and select only the following fields: 'name, email, store_code'.
I'm trying the following, but laravel says user.name doesn't exists :(
$queryBuilder = \App\Distributor::has('user');
$queryBuilder->select(['user.name']);
$queryBuilder->get();
QueryException in Connection.php line 651:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'user.name' in 'field list' (SQL: select user.name from distributor where (select count(*) from user where user.userable_id = distributor.id and user.userable_type = App\Distributor and user.deleted_at is null) >= 1)
I was able to achieve my goal forcing the join relationship, but this seems wrong, I think Eloquent is able to find the relation by itself as the Morph relationship is specified in the Model.
Just for record, this works good:
$queryBuilder = \App\Distributor::has('user');
$queryBuilder->join('user', function($join) {
$join->on('userable_id', '=', 'distributor.id')
->where('userable_type', '=', \App\Distributor::class);
});
$queryBuilder->select(['user.name']);
$queryBuilder->get();
Also, since its a one-to-one like relationship, sometimes I'll need to order the results using one of the users columns
But I need another way to do it without forcing the join, something clean as the first example.
read about with() function in the docs
$queryBuilder->select('id','store_code');
$queryBuilder = \App\Distributor::with(['user'=>function($query){
$query->select('id','name','email')
}]);
$queryBuilder->has('user');
$queryBuilder->get();

laravel join tables column not found

Hi I am building an application and I have a table for example projects and then settings. However they do not have a foreign key with each other and i have other tables such as tasks, clients etc. And these have settings which I am planning to save in the settings table.
The settings table has a column of type, which i will fill with the related model name e.g. project. Anyway when i am fetching a project I also want to fetch a the settings where the type = project. So I've tried to do a table join instead however this has thrown the following error:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'project' in 'on clause' (SQL: select * from `projects` inner join `settings` on `type` = `project`)
The code I've used is as follows:
return \Project::()->join('settings', 'type', '=', 'project')->get();
I see what the problem is, its looking for a column called project however there isn't one. I suppose what i want to do is use eloquent and a query function to join the table and then query the settings table where type = project. does anyone know how i can do this?
update from burak answer
I've tried to put this in my model as so so
settings.php
public function sprint() {
return \Setting::where('type', '=', 'sprint')->get();
}
and sprint.php
public function settings() {
return \Setting::where('type', '=', 'sprint')->get();
}
however I get this error Call to undefined method
Illuminate\Database\Eloquent\Collection::addEagerConstraints() and I've called it using this method:
return Sprint::with(['settings'])->get();
what have i done wrong here?
Because you are not referencing the table names and you are comparing columns. Instead, what you need is a where statement within your join condition to compare with a value.
return DB::table('projects')
->join('settings', function ($join) {
$join->where('settings.type', '=', 'project');
})->get();
But you should better get settings and projects one by one as all identical settings columns will be added to your projects rows which is not good.
$data = [];
$data['projects'] = Project::all();
$data['settings'] = Settings::where('type', '=', 'project')->first();
return $data;
Update:
Within your Sprint model
public function scopeWithType()
{
return static::join('settings', function ($join) {
$join->where('settings.type', '=', 'sprint');
});
}
Then within the controller
Sprint::withType()->get();
I have not tried but I think this is what you want. This is how we do subqueries or query joins with where clause.
return \Project::join('settings', function($q) {
$q->where('type', '=', 'project');
})->get();
your code looks for records matching project field in the table settings and type field in the project table, which is not the case.

Categories