I recently learned about dynamic where clauses (I think that's what is called) in Laravel 4 Eloquent which makes where clauses like User::where('first_name', 'Jon')->get() becomes nicer User::whereFirstName('Jon')->get(). How flexible is this??
Can i for example do the following
multiple columns User::whereFirstNameOrLastName('Jon', 'Smith')->get();
use operator other than = like >= or LIKE
You can use Query Scope to achieve what you needed.
A simple illustration:
public function scopeFirstOrLastName($query, $first, $last)
{
return $query->where('first_name', 'LIKE', '%' . $first . '%')
->where('last_name', 'LIKE', '%' . $last . '%');
}
Using it:
$user->firstOrLastName('John', 'Doe')->get();
You can name it as you see fit, and you can use any operator (or any query builder operation) inside.
Related
I am using laravel spatie for filtering the model i have following filters in allowed filter array
$this->allowedFilters = [
'name',
AllowedFilter::exact('company_id'),
'location',
'summary',
'client_name',
];
when I make request like
past-projects?filter[company_id]=${companyId}&filter[name]=${search}&filter[summary]={company_id}
it searches for the data which exactly contains all the passed search params with AND condition and returns no results if any of passed param do not match. I want to get results if any of the passed param match.
Any help will be appreciated.
As per Spatie Laravel Query Builder documentation the allowedFilters() method will take the array of strings and return a result where all the parameters match.
The bad news: Therefore, it will not work as how you are intending to use it.
What you want is Laravel's Or Where Clause.
The good news: since Spatie Laravel Query Builder extends Laravel's default Eloquent query builder you can use both Laravel queries and Spatie queries in conjunction.
Say you want to get all users from "Org ABC" and from that result you want to get all users with either the name "Jack" or the location "USA" or the client_name "John" or the summary "Hello World". Then you can try
$result = QueryBuilder::for(Projects::class)
->allowedFilters(['company_id']
->where(function ($query) use ($name, $location, ...)
$query
->where('projects.user.name', 'like', '%$title%')
->orWhere('projects.location', 'like', '%$location%')
->orWhere() ....
);
return $result
I came across this issue... Here's a way I resolved it.
You could also use the callback in the query builder like this...
$users = QueryBuilder::for(User::class)
->allowedFilters([
'user_type',
'user_city',
AllowedFilter::exact('status')->default('new'),
AllowedFilter::callback('search', function($query, $value){
$query->where('name', 'LIKE', '%' . $value . '%')
->orWhere('bio', 'LIKE', '%' . $value . '%')
->orWhere('state', 'LIKE', '%' . $value . '%')
->orWhere('address', 'LIKE', '%' . $value . '%');
})
])->get();
then the URL will look like this for example
?filter[user_type]=customer&filter[search]=doe&filter[user_city]=boston
The search parameter will be used to check the name, bio, state and address for any match.
I am trying to search relevant jobs from a list on jobs on my DB according to what user searches for and if the search term matches the job title its highly relevant search result so I am trying to assign the relevancy value to job objects right after their where condition gets satisfied. Also cleaner way of writing orWhere conditions?
public function search()
{
$searchText = $_GET['searchText'];
$jobs = Jobs::where('name', 'LIKE', '%' . $searchText . '%') //how to do $jobs->relevancy = 100 here? if this where condition is satisfied?
->orwhere('skills', 'LIKE', '%' . $searchText . '%')
->orwhere('desc', 'LIKE', '%' . $searchText . '%') //$jobs->relevancy = 10 here
->orwhere('desc1', 'LIKE', '%' . $searchText . '%')
->orwhere('desc2', 'LIKE', '%' . $searchText . '%')
->orwhere('desc3', 'LIKE', '%' . $searchText . '%')
->orwhere('desc4', 'LIKE', '%' . $searchText . '%')
->get();
return view('results', compact('jobs'));
}
If you want to group orWhere conditions to then apply another WHERE (AND) statement, you can use a closure for the grouping.
Imagine that you want something like this:
WHERE A
AND (WHERE B OR WHERE C)
AND (WHERE D OR WHERE E)
Then you could do:
$results = Model::where('A', 'something')
->where(function ($query) {
$query->where('B', 'something')
->orWhere('C', 'something');
})
->where(function ($query) {
$query->where('D', 'something')
->orWhere('E', 'something');
})
->get();
There's no easy way to know which part of the where clauses actually matched the query. You'd need to re-do the text comparisons after you got the results, which is probably not ideal.
In these sort of situations you might want to consider a full text search.
If you're using MySQL you can create a FULLTEXT index and then use MATCH ... AGAINST. (other DBMS have a different syntax but generally there is support).
$searchText = request()->searchText;
$jobs = Jobs::whereRaw('MATCH(name) AGAINST (? IN NATUAL LANGUAGE MODE)', [$searchText])
->orWhereRaw('MATCH(desc) AGAINST (? IN NATUAL LANGUAGE MODE)', [$searchText])
// ...
selectRaw('(100*MATCH(name) AGAINST (? IN NATUAL LANGUAGE MODE) + 10*MATCH(name) AGAINST (? IN NATUAL LANGUAGE MODE)) as score', [$searchText,searchText])
->addSelect("*")
->orderBy('score', 'desc')
->get();
MATCH ... AGAINST will return a relevance score so by doing e.g. 100*MATCH(name).. you are adding a weight of 100 to that match. The overall result should be ordered based on the total relevance of the search.
More on full text search in MySQL in the manual
If you are using this kind of condition in many places then you can do the following!
1- In your AppServiceProvider inside boot methode
use Illuminate\Database\Query\Builder;
public function boot()
{
Builder::macro('search', function($field, $string){
return $string ? $this->where($field, 'like', '%'.$string.'%') : $this;
});
Builder::macro('orSearch', function($field, $string){
return $string ? $this->orWhere($field, 'like', '%'.$string.'%') : $this;
});
}
2- Do your Query like the following
$jobs = Jobs::where(function($query) {
if($searchText != "") {
$query->search('skills', $searchText);
$query->orSearch('desc', $searchText);
$query->orSearch('desc1', $searchText);
$query->orSearch('desc2',$searchText);
$query->orSearch('desc3',$searchText);
}
})->get();
I think this is a cleaner way of doing this kind of query.
I'm trying to ignore specific types of objects in the query. there are types where I have banned or deleted data which I don't want the user be able to find. my query looks something like :
$posts = DB::table('posts')->where('content', 'like', '%' . $request['content'] . '%')
->where('isfutured', '!=', '0')
->orderByDesc('id')->get();
But now I also want to not get the data with isfutured of 4. how do I do that? or can I somehow prevent these in the Post model and do my regular Eloquent query?
using query builder
for multiple condition used whereIn or whereNotIn
$isfutured = [0,4]; // add in array which did not want to get
$posts = DB::table('posts')->where('content', 'like', '%' . $request['content'] . '%')
->whereNotIn('isfutured', $isfutured)
->orderByDesc('id')->get();
using elequent
$posts = Post::whereNotIn('isfutured', $isfutured)->where('content', 'like', '%' . $request['content'] . '%')->orderByDesc('id')->get();
I'm building up a filterable list with Laravel 5.0 and I'm crashing on following Problem.
I get the filter parameters from a HTML form and pass them to the Query Builder, but if a form input stays empty all rows of the table filtered by the other filters should be returned.
Example code:
$collection = Model::withTrashed()
->where('attr1', 'LIKE', \Request::input('attr1', '%'))
->where('attr2', 'LIKE', \Request::input('attr2', '%'))
->where('attr3', 'LIKE', \Request::input('attr3', '%'))
->get();
This seems to be most correct code for me, but it doesn't work as expected. Do you know a good solution for my Problem? I don't want to integrate a messy switch/case statement for proofing for existence and building the collection up manually. :(
Thanks for your help.
It seems that your problem is that you are always passing the filters to the query and you should only pass them if they are not empty.
Maybe somethig like this would work for you:
$results = Model::withTrashed();
if (\Request::input('attr1')) {
$results->where('attr1', 'LIKE', \Request::input('attr1', '%'));
}
if (\Request::input('attr2')) {
$results->where('attr2', 'LIKE', \Request::input('attr2', '%'))
}
if (\Request::input('attr3')) {
$results->where('attr3', 'LIKE', \Request::input('attr3', '%'))
}
$collection = $results->get();
You need to tweak your query a bit like this:
$collection = Model::withTrashed()
->where('attr1', 'LIKE', '%' . \Request::input('attr1') . '%')
->where('attr2', 'LIKE', '%' . \Request::input('attr2') . '%')
->where('attr3', 'LIKE', '%' . \Request::input('attr3') . '%')
->get();
This will make sure that the LIKE clause is still correct when an empty input parameter is sent.
I'm using the below code to pull some results from the database with Laravel 5.
BookingDates::where('email', Input::get('email'))->orWhere('name', 'like', Input::get('name'))->get()
However, the orWhereLike doesn't seem to be matching any results. What does that code produce in terms of MySQL statements?
I'm trying to achieve something like the following:
select * from booking_dates where email='my#email.com' or name like '%John%'
If you want to see what is run in the database use dd(DB::getQueryLog()) to see what queries were run.
Try this
BookingDates::where('email', Input::get('email'))
->orWhere('name', 'like', '%' . Input::get('name') . '%')->get();
I have scopes for this, hope it help somebody.
https://laravel.com/docs/master/eloquent#local-scopes
public function scopeWhereLike($query, $column, $value)
{
return $query->where($column, 'like', '%'.$value.'%');
}
public function scopeOrWhereLike($query, $column, $value)
{
return $query->orWhere($column, 'like', '%'.$value.'%');
}
Usage:
$result = BookingDates::whereLike('email', $email)->orWhereLike('name', $name)->get();
$data = DB::table('borrowers')
->join('loans', 'borrowers.id', '=', 'loans.borrower_id')
->select('borrowers.*', 'loans.*')
->where('loan_officers', 'like', '%' . $officerId . '%')
->where('loans.maturity_date', '<', date("Y-m-d"))
->get();
I think this is better, following the good practices of passing parameters to the query:
BookingDates::whereRaw('email = ? or name like ?', [$request->email,"%{$request->name}%"])->get();
Better:
BookingDates::where('email',$request->email)
->orWhere('name','like',"%{$request->name}%")->get();
You can see it in the documentation, Laravel 5.5.
You can also use the Laravel scout and make it easier with search.
Here is the documentation.
the query which is mentioned below worked for me maybe it will be helpful for someone.
$platform = DB::table('idgbPlatforms')->where('name', 'LIKE',"%{$requestedplatform}%")->first();
If you wish to use it on controller you can do something like:
$generatequery = 'select * from blogs where is_active = 1 and blog_name like '%'.$blogs.'%' order by updated_at desc, id desc';
$blogslists = DB::select($generatequery);
If you are using Postgres, The key word ILIKE can be used instead of LIKE to make the match case-insensitive according to the active locale. This is not in the SQL standard but is a PostgreSQL extension.
this worked for me.
User::where('name, 'ILIKE', $search)->get();
postgres documentation