Laravel Query with Relation and Where/orWhere for Search field - mysql

there are 2 models. Customers & Locations.
In a location single page, it should now be possible to display all customers from the location and filter them according to customer attributes.
The problem here is that when you enter something in the search field, customers are no longer picked out specifically from the location, but from all customers that exist.
Filtering is possible on the overview page (where all customers are displayed). However, as soon as the query is added that it should be specifically for customers who own the location, it is no longer possible.
return \App\Models\Customer::with('locations')
->whereHas('locations', function($q)
{$q->where('locations.id', $this->location->id)
->Where('customers.name','like', '%'.$this->search.'%')
->orWhere('customers.domain','like', '%'.$this->search.'%')
->orWhere('customers.number','like', '%'.$this->search.'%')
->orWhere('customers.email','like', '%'.$this->search.'%'); })
->orderBy($this->sortField, $this->sortDirection)
->paginate($this->page_number);
Unfortunately, I am not sure how to build the query that requires the first whereHas (which is only to find customers from the locations) and then the other Where commands for the search field.

To filter by specific location and using the search value
return \App\Models\Customer::with('locations')
->whereHas('locations', function($q) {
$q->where('id', $this->location->id);
})
->where(function($q) {
$q->Where('name','like', '%'.$this->search.'%')
->orWhere('domain','like', '%'.$this->search.'%')
->orWhere('number','like', '%'.$this->search.'%')
->orWhere('email','like', '%'.$this->search.'%');
})
->orderBy($this->sortField, $this->sortDirection)
->paginate($this->page_number);

Related

A (sum)count within a count on the other side of a hasManyThrough eloquent

I have a hasManyThrough in my model which i use in my repository.
I have an interesting count that i must do but im not sure how to approach it.
The hasManyThrough is a count with a condition but then this also has a hasMany to a number of vehicles that must also be counted with a condition.
2.Here is my code so far but i feel its expensive as its on a grid so each row executes this:
$queryBuilder->withCount([
'hotLeads as hot_leads_count' => function($query) {
$query->whereRaw("laravel_reserved_1.id != leads.id");
}
])->with(['hotLeads' => function($query) {
$query
->withCount('vehicles'); **-> needs to actually sum all counts**
}]);
Table Structure (in scope):
I have a leads table with has a person_id which links to a person who should be validated and have a unique id number:
Here is the relation that depicts this:
Lead model:
public function hotLeads(): HasManyThrough
{
return $this->hasManyThrough(
Lead::class,
Person::class,
'id',
'person_id',
'person_id',
'id'
)
->where('validated', 1)
->whereNotIn('status', [Status::LEAD_CLOSED->value, Status::SEAL_LEAD_CLOSED->value]);
}
So what im looking for is hotLeads. Its the same person_id connected to many other leads and that person is validated.
I need to count how many times this person is connected to other leads and exclude the current lead id.
The lead who is connected to the person also has many vehicles so i need a count for this as well.
So its a count of hot leads excluding the current lead record and a count of that leads vehicles summed up. So i could have 5 hot leads with 13 vehicles total
lead -> person -> leads(many count) -> lead_vehicles (many count)

Laravel order By name in ascending order except some specific rows

I'm building an API to return shops from a database in ascending order except that it should begin with all shops named swiva eg Swiva Electronics, Swiva Gas, Swiva Mall etc. then proceed to all the other shops in ascending order.
I have tried the following code
$shops=Shop::join('users','users.id','=','shops.owner_id')
->select('shops.id','shops.name','users.email','users.tel','users.estate','shops.logo')
->orderBy('shops.name')
->get()
->partition(function ($item) {
return $item->name != 'Swiva Electronics';
})->flatten();
but that is not doing what I want as
It is not beginning with the intended row rather it is ending with it.
It is only working with one row only, I do not know how to specify all the other rows
Note that the output of this query is being returned as a json as follows
if(!$shops->isEmpty()){
return response()->json([
'success'=>true,
'shops'=> $shops
]);
}else if($shops->isEmpty()){
return response()->json([
'success'=>false,
'message'=> 'There exists no subscribed shops from '
]);
}
How can I achieve the intended output either through formatting the JSON( Which I do not know how to do) or by using eloquent functions.
You can use the Field Function of MySQL to achieve this see: https://www.w3schools.com/sql/func_mysql_field.asp
$shops = Shop::join('users','users.id','=','shops.owner_id')
->select('shops.id', 'shops.name', 'users.email', 'users.tel', 'users.estate', 'shops.logo')
->orderByRaw("FIELD(shops.`name`, 'Swiva Electronics', 'Swiva Gas', 'Swiva Mall') DESC, shops.`name`")
->get()
As we can't add all names in FIELD options by default it will list all other names first Use DESC order to invert it will move those names first in results and then sort the all other shop names by adding simple ASC order by shop names.

Using count subquery within CakePHP ORM

I'm looking through the CakePHP docs and I can't see anywhere that explains how you execute a subquery in the MySQL statement. I would essentially like to count the number of credits each user has as a field, but at the moment it is counting the credits cumulatively for all users into one field:
$this->Users->find()
->contain(['Plans','Products'])
->contain('Credits', function ($q) {
return $q->select(['count' => $q->func()->count('*')]);
})->group(['Users.id']);
The query I'm trying to create is more like :
SELECT *, (SELECT COUNT(*) FROM credits Credits WHERE Credits.user_id = Users.id) as credit_count FROM users Users group by Users.id ASC
Contained hasMany associations will always be retrieved in a separate query, and that is where the conditions will be applied that you are defining in the contain callback (check Sql Log tab of DebugKit).
To get the results that you are looking for requires to either join in the association, and counting the Credits in the same query, something like this:
$this->Users
->find()
->select(function(\Cake\ORM\Query $q) {
return ['count' => $q->func()->count('Credits.id')]
})
->select($this->Users)
->contain(['Plans','Products'])
->leftJoinWith('Credits')
->group(['Users.id']);
or to explicitly use a subquery, which works by simply creating a regular query object, and passing it to wherever the query builder accepts expression objects, for example as the value in your select list:
$subquery = $this->Users->Credits
->find()
->select(function(\Cake\ORM\Query $q) {
return ['count' => $q->func()->count('Credits.id')]
})
->where(function (\Cake\Database\Expression\QueryExpression $exp) {
return $exp->equalFields('Credits.user_id', 'Users.id'):
});
$this->Users
->find()
->select(['count' => $subquery])
->select($this->Users)
->contain(['Plans','Products']);
See also
Cookbook > Database Access & ORM > Query Builder > Selecting Specific Fields
Cookbook > Database Access & ORM > Query Builder > Advanced Conditions

Eloquent Query, possible Join

I have three models: driver, designation and dpsObject, with the following replationships:
driver->hasMany(dpsObject)
driver->belongsTo(Designation)
designation->hasMany(Driver)
dpsObject->belongsTo(Driver)
I'm trying to write a query to return a list of dpsObject records that correspond to the values of three user inputs, which are: a date range(From and To) holding the values of an EntryDate field in the dpsObject and a Designation input, holding the value of a Designation_name field in the Designation object.
Currently this is my Query:
$dps = dpsObject::where([['entryDate', '>=', $from],
['entryDate', '<=', $to]]);
$from and $to hold the request values gotten from the form user's submit.
I need to complete the query to capture the Designation name of a driver that that has dpsObject records. The challenge is that the designation_name field does not exist on the dpsObject model but only on the driver and designation models. This is how I want to maintain the database model. I think I need to be using a join or something similar, but I'm not sure how to go about it.
What is the best way to write such a query?
Kind regards
You can use nested whereHas():
$dpsObjects = dpsObject::whereBetween('entryDate', [$from, $to])
->whereHas('driver', function ($q) use($designationName) {
$q->whereHas('designation', function ($q) use($designationName) {
$q->where('designation_name', $designationName);
});
})
->get();
Here, designation and driver are belongsTo() relationships.

Laravel multiple column eloquent search query

i am very new in Laravel,currently working with Laravel4.I am trying to add a multiple column search functionality in my project.I can do single column eloquent search query,But honestly i have no idea how to do multiple column eloquent search query in laravel.I have two drop down menu
1.Locatiom
2.blood group.
i want to search an user having certain blood group against certain location.That is, user will select a location and blood group from those two drop down menu at a time and hit the search button.
In my database,i have two column, one contains the location and another contains the blood group of a certain user. Now,what should be the eloquent query for such a search?
Simply chain where for each field you need to search through:
// AND
$results = SomeModel::where('location', $location)->where('blood_group', $bloodGroup)->get();
// OR
$results = SomeModel::where('location', $location)->orWhere('blood_group', $bloodGroup)->get();
You can make it easier to work with thanks to the scopes:
// SomeModel class
public function scopeSearchLocation($query, $location)
{
if ($location) $query->where('location', $location);
}
public function scopeSearchBloodGroup($query, $bloodGroup)
{
if ($bloodGroup) $query->where('blood_group', $bloodGroup);
}
// then
SomeModel::searchBloodGroup($bloodGroup)->searchLocation($location)->get();
Just a sensible example, adjust it to your needs.
This is a great way but I think there is an error somewhere as laravel would not allow you to access a non-static function so instead of using
SomeModel::searchBloodGroup($bloodGroup)->searchLocation($location)->get();
you could simply use
SomeModel::BloodGroup($bloodGroup)->Location($location)->get();
take note of the searchBloodGroup has been changed to BloodGroup, that's how you will use it for all others also.
$errors = $connection->table('test_sessions_table')
->where('user_id', $user->id)
->where('status_question', 'false')->count('status_question');
in this method your code takes the following form
SQL code
select count(`status_question`) as aggregate from `test_sessions_table` where `user_id` = ? and `status_question` = ?
orWhere your code will look like this
$errors = $connection->table('test_sessions_table')
->where('user_id', $user->id)
->orWhere('status_question', 'false')->count('status_question');
SQL code
select count(`status_question`) as aggregate from `test_sessions_table` where `user_id` = ? or `status_question` = ?
Personally, I recommend using two ‘where’