I am a happy user of Laravel Scout.
Now I'd like to extend my search:
$data
= new UserOverviewResourceCollection(User::search($searchphrase)
->currentStatus('active')->orderBy('lastname', 'asc')
->orderBy('firstname', 'asc')
->paginate(config('pagination.length')));
currentStatus comes from https://github.com/spatie/laravel-model-status .
Now I am getting a response, that currentStatus is not supported. I thought I could be a good idea to filter the result of User::search after it has been returned from scout?
Another idea: I'd like to add more complex where clauses:
->where([
[
'starts_on',
'<',
Carbon::now()->toDateTimeString(),
],
[
'ends_on',
'>',
Carbon::now()->toDateTimeString(),
],
])
Maybe you got a better idea?
I really need similar functionality as well but I'm afraid it's not possible at the moment (Laravel 8)
According to the docs; Laravel\Scout\Builder (which is what search() returns) only has a really basic implementation of the where method an can only handle exactly 2 arguments.
Here is the code from the scout package:
/**
* Add a constraint to the search query.
*
* #param string $field
* #param mixed $value
* #return $this
*/
public function where($field, $value)
{
$this->wheres[$field] = $value;
return $this;
}
See https://laravel.com/docs/8.x/scout#where-clauses
Putting the search() behind all regular eloquent builder methods won't work either since search will only be a static function of the model.
Hopefully this will be improved in the future.
You can extend Builder and add currentStatus method to store required status in builder. See example
https://github.com/matchish/laravel-scout-elasticsearch/issues/47#issuecomment-526287359
Then you need implement your own engine and build query using builder there.
Here is example for ElasticSearch engine
https://github.com/matchish/laravel-scout-elasticsearch/blob/06c90914668942b23ffaff7d58af5b9db1901fb1/src/Engines/ElasticSearchEngine.php#L135
Well rewriting it as this should work.
$data
= new UserOverviewResourceCollection(User::search($searchphrase)
->where('starts_on','<',now())
->orderBy('lastname', 'asc')
->orderBy('firstname', 'asc')
->paginate(config('pagination.length')));
Notice that now() is just a global helper function returning current moment Carbon instance. It's just shorter to write, no other reason for using it.
And if you want grouped where queries you do it like this:
$data
= new UserOverviewResourceCollection(User::search($searchphrase)
->where(function($q) {
$q->where('starts_on','<',now())->where('ends_on','>',now())
})
->orderBy('lastname', 'asc')
->orderBy('firstname', 'asc')
->paginate(config('pagination.length')));
And then you should be able to export this to the UserOverviewResourceCollection as a local scope, for example:
public function scopeActive($q) {
return $q->where('starts_on','<',now())->where('ends_on','>',now())
}
and then you can use something like this:
$data
= new UserOverviewResourceCollection(User::search($searchphrase)
->active()
->orderBy('lastname', 'asc')
->orderBy('firstname', 'asc')
I've written this from my head so there might be typos.
$data
= new UserOverviewResourceCollection(User::search($searchphrase)
->currentStatus('active')->orderBy('lastname', 'asc')
->where(function($q){
$query->where('starts_on', '<',Carbon::now()->toDateTimeString());
$query->where('ends_on', '>',Carbon::now()->toDateTimeString());
})
->orderBy('firstname', 'asc')
->paginate(config('pagination.length')));
Try this code. This will satisfy your complex where condition
Related
I am new to laravel,
I need to create a query for the db,
$query = Deal::query();
I want to use the wherehas operator.
this is my code that is worked.
else if ($group_by == 'precedence') {
if($get_deals_for == 'noprecedence'){
$get_deals_for = 0;
}
$precedenceStatus = $get_deals_for;
$query-> where('precedence', '=', $precedenceStatus);
// \Log::info('The request precedence: '.$precedenceStatus);
}
I want to add this code also to the query
if($person) {
$query->whereHas('personnel', function ($subQuery) use ($person) {
$subQuery->where('id', '=', $person);
});
}
So I need to change the first code?
how I can convert the first code to wherehas?
the first code is from table called deal, the second section is from realtionship called personnel.
the second section worked in other places in the code, I just need to fix the first section and not understand what to write in the use
I try this and get error on the last }
else if ($group_by == 'precedence') {
if($get_deals_for == 'noprecedence'){
$get_deals_for = 0;
}
$precedenceStatus = $get_deals_for;
$query-> where('precedence', '=', $precedenceStatus)
-> when ($person, function($query) use($person) {
$query->whereHas('personnel', function ($query) use ($person) {
$query->where('id', '=', $person);
});
})
}
There is a method you can use called when(, so that you can have cleaner code. The first parameter if true will execute your conditional statement.
https://laravel.com/docs/9.x/queries#conditional-clauses
$result = $query
->where('precedence', '=', $precedenceStatus)
->when($person, function ($query) use ($person) {
$query->whereHas('personnel', fn ($q) => $q->where('id', '=', $person));
})
->get();
You should also be able to clean up your precedence code prior to that using when( to make the entire thing a bit cleaner.
Querying to DB is so easy in laravel you just need to what you want what query you want execute after that you just have to replace it with laravel helpers.Or you can write the raw query if you cant understand which function to use.
using,DB::raw('write your sql query').
Now Most of the time whereHad is used to filter the data of the particular model.
Prefer this link,[Laravel official doc for queries][1] like if you have 1 to m relation ship so u can retrive many object from one part or one part from many object.like i want to filter many comments done by a user,then i will right like this.
$comments = Comment::whereHas('user', function (Builder $query) {
$query->where('content', 'like', 'title%');
})->get();
$comments = Here will be the model which you want to retrive::whereHas('relationship name', function (Builder $query) {
$query->where('content', 'like', 'title%');
})->get();
you can also write whereHas inside whereHas.
[1]: https://laravel.com/docs/9.x/eloquent-relationships#querying-relationship-existence
I am new to the laravel, i am joining three tables based on conditions every thing is working fine but i need to write conditionally if the $field is array it should run with whereIn otherwise it should run where condition,can you please help me to acheive this thing
//$field sometimes it's an array sometimes it's a string.
public function find($field){
}
For conditional constraints, you can use the when() clause:
$query = DB::table(...);
$data = $query
->when(is_array($field), function ($query) use ($field) {
$query->whereIn('my_field', $field);
}, function ($query) use ($field) {
$query->where('my_field', $field);
})
->get();
Now, as a tip, you could do this: Wrap the $fields variables to an array and then use always the whereIn clause. You can achieve this with the Arr::wrap() function:
use Illuminate\Support\Arr;
// ...
$query = DB::table(...);
$data = $query
->whereIn('my_field', Arr::wrap($field))
->get();
PS: I have linked the relevant functions to the docs so you can know how they work and their params.
I am trying to optimize a project that is working pretty slow using caching. I'm facing a problem that I don't quite understand how to cache full eloquent models with their relationships and later on covert them back to a model with all relations intact. Here's a fragment of my code
if (Cache::has($website->id.'_main_page')) {
$properties = (array) json_decode(Cache::get($website->id.'_main_page'));
$page = Page::hydrate($properties);
}else{
$expiresAt = now()->addMinutes(60);
$page = Page::with(['sections', 'pageSections.sectionObjects'])->where('website_id', $website->id)->where('main', 1)->first();
Cache::put($website->id.'_main_page', $page->toJson(), $expiresAt);
}
Problem is, hydrate seems to be casting this data as a collection when in fact it's suppose to be a single model. And thus later on I am unable to access any of it's properties without getting errors that they don't exists. $properties variable looks perfect and I would use that but I need laravel to understand it as a Page model instead of stdClass, I also need all of the relationships to be cast into their appropriate models. Is this even possible? Any help is much appreciated
Is there any reason you can't use the cache like this
$page = Cache::remember($website->id.'_main_page', 60 * 60, function () use ($website) {
return Page::with(['sections', 'pageSections.sectionObjects'])
->where('website_id', $website->id)
->where('main', 1)
->first();
});
Conditional
$query = Page::query();
$key = $website->id.'_main_page';
if (true) {
$query = $query->where('condition', true);
$key = $key . '_condition_true';
}
$query::with(['sections', 'pageSections.sectionObjects'])
->where('main', 1)
$page = Cache::remember($key, 60 * 60, function () use ($query) {
return $query->first();
});
I was going through my friend's laravel code, and saw some functions like withPost and others, here is the code
public function show($id)
{
$categorylist = Category::all();
$tagfoot = Tag::all();
$post = Post::find($id);
$popularposts= Post::selectRaw("posts.*, count('comments.id') as comments_count")->leftJoin('comments','comments.post_id', '=', 'posts.id')->groupBy('posts.id')->orderBy('comments_count', 'desc')->take(6)->get();
$prev = Post::where('id', '<', $post->id)->orderBy('id', 'desc')->first();;
$next = Post::where('id', '>', $post->id)->orderBy('id', 'desc')->first();
return view('posts.show')->withPost($post)->withTagfoot($tagfoot)->withCategorylist($categorylist)->withPrev($prev)->withNext($next)->withPopularposts($popularposts);
}
What do the withPost, withTagfoot, withCategorylist, withPrev, withNext, withPopularposts functions actually do?
Your mentioned code sends values to the view 'posts.show'.
Another way of sending value could be like the following. Here you can use the compact function of PHP to list the variables.
return view('posts.show', compact('post', 'tagfoot', 'categorylist', 'prev', 'next', 'popularposts'));
Using with keyword before a variable name to make a function is one of the ways you can pass that variable to views in Laravel. There are other ways and all are identical:
return view('posts.show')->withPost($post);
is just same as this:
return view('posts.show', compact('post'));
I have a code:
$response = $this->posts
->where('author_id', '=', 1)
->with(array('postComments' => function($query) {
$query->where('comment_type', '=', 1);
}))
->orderBy('created_at', 'DESC')
->limit($itemno)
->get();
And when I logged this query with:
$queries = \DB::getQueryLog();
$last_query = end($queries);
\Log::info($last_query);
In log file I see follow:
"select * from `post_comments` where `post_comments`.`post_id` in (?, ?, ?, ?) and `comment_type` <> ?"
Why is the question mark for comment_type in the query?
Update #1:
I replaced current code with following and I get what I want. But I'm not sure it is OK. Maybe exists many better, nicer solution.
$response = $this->posts
->where('author_id', '=', 1)
->join('post_comments', 'post_comments.post_id', '=', 'posts.id')
->where('comment_type', '=', 1)
->orderBy('created_at', 'DESC')
->limit($itemno)
->get();
Behind the scene the PDO is being used and it's the way that PDO does as a prepared query, for example check this:
$title = 'Laravel%';
$author = 'John%';
$sql = "SELECT * FROM books WHERE title like ? AND author like ? ";
$q = $conn->prepare($sql);
$q->execute(array($title,$author));
In the run time during the execution of the query by execute() the ? marks will be replaced with value passed execute(array(...)). Laravel/Eloquent uses PDO and it's normal behavior in PDO (PHP Data Objects). There is another way that used in PDO, which is named parameter/placeholder like :totle is used instead of ?. Read more about it in the given link, it's another topic. Also check this answer.
Update: On the run time the ? marks will be replaced with value you supplied, so ? will be replaced with 1. Also this query is the relational query, the second part after the first query has done loading the ids from the posts table. To see all the query logs, try this instead:
$queries = \DB::getQueryLog();
dd($queries);
You may check the last two queries to debug the queries for the following call:
$response = $this->posts
->where('author_id', '=', 1)
->with(array('postComments' => function($query) {
$query->where('comment_type', '=', 1);
}))
->orderBy('created_at', 'DESC')
->limit($itemno)
->get();
Update after clarification:
You may use something like this if you have setup relation in your Posts model:
// $this->posts->with(...) is similar to Posts::with(...)
// if you are calling it directly without repository class
$this->posts->with(array('comments' =. function($q) {
$q->where('comment_type', 1);
}))
->orderBy('created_at', 'DESC')->limit($itemno)->get();
To make it working you need to declare the relationship in your Posts (Try to use singular name Post if possible) model:
public function comments()
{
return $this->hasmany('Comment');
}
Your Comment model should be like this:
class Comment extends Eloquent {
protected $table = 'post_comments';
}