Does where() method have the same power like whereRaw() method? - laravel

I have a Video model and a Tag model. Let's say I would like to get all videos that have tags, maybe all the videos that have more than three relations with tags. I would do this:
Video::has('tags', '>=', 3)->get();
If I want do add more constrains, for example get all videos with at least 3 tags and the tag name should contain 'something'. I could do something like this:
Video::whereHas('tags' function(Builder $query){$query->where('name', 'like', '%something%');}, '>=', 3)->get();
But what if I would like to do something more, like only tags with odd/even id to be counted. Something like fmod('id', 2) to be used inside the closure. To check if the id is even or odd. Since I can't do something like: $query->where('id%2', '=', 0 );. Well, in this case I know I could use $query->where('name', 'like', '%something%')->whereRaw('tags.id%2=0');. But is there any other way using where() method?

where() first parameter will always be the column, but in cases where you specifies columns in the queries like where() and select(), you can use DB::raw(); This should make this syntax viable, which i think is the best solution the Eloquent ORM.
->where(DB::raw('tags.id%2'), 0);

Related

laravel withsum with additional where clause

I know you can do a withSum on a relationship like this:
$posts = Post::withSum('comments', 'votes')->get();
But I like to chain an additional where clause on this, something like this (doesn't work but as an example):
$posts = Post::withSum('comments', 'votes', function (Builder $query) {
$query->where('comments.votes', '>', 5);
})->get()
Is that possible?
While Aggregating Related Models is not explicit about this in the documentation, it does give us a clue by mentioning:
If you need to set additional query constraints on the count query, you may pass an array keyed by the relationships you wish to count. The array values should be closures which receive the query builder instance.
If you need to set additional query constraints on the count query, you can pass an encoded array by the relationships you want to count. The values in the array must be anonymous functions that receive the query builder instance.
So, we can take advantage of that anonymous function to modify the query builder instance so that instead of taking the default values (which would use the aggregate 'count'), and pass it the subquery we want to do, which is the where clause and the 'sum' of the column.
Said that, your query cuold looks like:
Post::withCount(['comments as comments_sum_votes' => function($query) {
$query->where('comments.votes', '>', 5)->select(DB::raw('sum(votes)'));
}])->get()

Display no result after merging 2 table and do a where statement in Laravel

I trying to merge 2 table of the same database as follow
$this->make_model_list = DB::table('car__models')->select(
"car__makes.id",
"car__makes.name AS make_name",
"car__models.id AS model_id",
"car__models.name AS model_name",
"car__models.car__make_id",
DB::raw("CONCAT(`car__makes`.`name`,' ',`car__models`.`name`) AS make_model")
)->leftJoin('car__makes', 'car__makes.id', '=', 'car__models.car__make_id')
->get();
And then I do a where statement as follow
$this->makemodels = $this->make_model_list->where('make_model', 'like', '%' . $this->makemodel . '%');
But it return [].
Your advices to this is greatly appreciated. Thanks
It looks like you're adding a where() after your get()
The get() executes your query and returns a collection of objects.
It's okay to call a where() on a collection but the parameters you've given your where() are more appropriate for a DB query.
I would suggest you drop the get() from your query. (For the sake of good variable naming you should then call make_model_list make_model_list_query)
$this->make_model_list_query = DB::table('car__models')->select(
"car__makes.id",
"car__makes.name AS make_name",
"car__models.id AS model_id",
"car__models.name AS model_name",
"car__models.car__make_id",
DB::raw("CONCAT(`car__makes`.`name`,' ',`car__models`.`name`) AS make_model")
)->leftJoin('car__makes', 'car__makes.id', '=', 'car__models.car__make_id');
And then call the get() after you've added your where()
$this->make_model_list_query->where('make_model', 'like', '%' . $this->makemodel . '%')->get();
It would probably make everything much easier for you if you created eloquent models for you tables and relationships between the models so you can take advantage of the relationship and scopes that can make your filtering much cleaner.
Models handle a huge amount of the query writing for you.
EDIT:
Having not noticed that your where was on your concatenated value at first I missed that your query would throw a SQL error.
You can't run your where on the aliased output of your concat.
So you would need to put the concat in the where clause too. Like so:
$this->make_model_list_query->where(DB::raw("CONCAT(`car__makes`.`name`,' ',`car__models`.`name`)"), 'like', '%' . $this->makemodel . '%')->get();
Be sure to check out the links I added in the comments for Eloquent Models.

How to add dynamic 'where' to eloquent ORM with() relation

I'm, trying to do something like this:
$verfuegbarkeiten = Verfuegbarkeit::verfuegbar()->with('product', 'producer', 'producer.user', 'producer.user.ort')->where('product.kategorie_id', '=', $_GET['kat'])->get()->toArray();
I want to use a 'where' clause so i can only get the results where the 'product's attribute 'kategorie_id' matches the GET parameter. How can I 'where' on a relation? It's really important to me that this value can be dynamic, so writing a fix function in the related Model won't be a good solution.
Every hint appreciated
You want whereHas(), documentation here: https://laravel.com/docs/5.2/eloquent-relationships#querying-relations
For your example, that would mean something like this:
$kat = $_GET['kat'];
$verfuegbarkeiten = Verfuegbarkeit::verfuegbar()
->with('product', 'producer', 'producer.user', 'producer.user.ort')
->whereHas('product', function($query) use ($kat) {
$query->where('kat', $kat);
})
->get()
->toArray();
Although I might add that using $_GET is generally discouraged in Laravel.

Laravel whereDoesntHave() - multiple OR conditions

In Laravel 4.2 I have a model called Product with many-to-many relationshis to other models like Country or Category. I want to filter out products that are "incomplete", which means they have no connected countries or no connected categories. I can use whereDoesntHave() method to filter out one relation. When I use it two times in one query it creates AND condition, but I need OR. I can't find orWhereDoesntHave() method in API documentation. I can't pass multiple relations as arguments because it expects first argument to be a string.
I need something like this:
$products = Product::whereDoesntHave('categories')->orWhereDoesntHave('countries')->get();
Is there any way to achive whereDoesntHave() with multiple OR conditions?
You can use doesntHave and specify the boolean operator:
$products = Product::doesntHave('categories')->doesntHave('countries', 'or')->get();
Actually you only need whereDoesntHave if you want to pass in a closure to filter the related models before checking if any of them exist. In case you want to do that you can pass the closure as third argument:
$products = Product::doesntHave('categories', 'or', function($q){
$q->where('active', false);
})->doesntHave('countries', 'or')->get();
Since Laravel 5.5 there is an orWhereDoesntHave function.
You may use it like this
Product::whereDoesntHave('categories', function($q){ //... })
->orWhereDoesntHave('countries', function($q){//...})
->get();
From you example it seems that you are not using a where clause, so you may just use
Product::doesntHave('categories')
->orDoesntHave('countries')
->get();
Use
Product::whereDoesntHave('categories')->doesntHave('countries', 'or')->get();
Laravel Source Code:
whereDoesntHave https://github.com/illuminate/database/blob/master/Eloquent/Builder.php#L654
calls
https://github.com/illuminate/database/blob/master/Eloquent/Builder.php#L628
internally.
Let’s say we have Authors and Books, with 1-n relationship – one Author can have one or many Books. Here’s how it looks in app\Author.php:
public function books()
{
return $this->hasMany(\App\Book::class, 'author_id');
}
Now, what if we want to show only those Authors that have at least one book? Simple, there’s method has():
$authors = Author::has('books')->get();
Similarly, there’s an opposite method – what if we want to query only the authors without any books? Use doesnthave():
$authors = Author::doesnthave('books')->get();
It’s not only convenient, but also super-easy to read and understand, even if you’re not a Laravel developer, right?

Laravel: Difference between where and whereHas

What is the difference between the two methods where() and whereHas()? They both seem to be quite similar in the laravel documentation.
The method where() behaves like a regular SQL WHERE query part.
The method has() uses foreign key relationships to return something which has something else. For instance, Student::has('classes')->get(); would return all students who have classes.
The method whereHas() is like a regular has(), but it lets you put constraints on the search. Unlike where(), this is done on the child table rather than the parent one. Here's an example:
$students = Student::where('name', 'Pingu') // constrains the students table
->whereHas('classes', function($query) {
$query->where('name', 'like', '%physics%'); // constrains the classes table
})->get();
In this highly realistic example, you'd want all students with a name of Pingu, who are taking some class in physics.

Resources