Laravel 5.1 - Querying multiple relationships - eloquent

I've got a problem which I don't know how to solve.
I've got companies which have a profile(profile belongs to company) and have locations(company has many locations).
I'm trying to get all companies which have a name like $request->input('search_term') and have a least one location with a zip or city matching $request->input('search_addition') and a profile with a type of 0.
My code is:
$companies = Company::with(['profile' => function ($query) {
$query->where('type', 0);
}])
->whereHas('locations', function ($query) use ($request) {
$query->where('zip', 'like', '%'.$request->input('search_addition').'%')
->orWhere('city', 'like', '%'.$request->input('search_addition').'%');
})
->where('name', 'like', '%'.$request->input('search_term').'%');
At the end I add $companies = $companies->paginate(25);
The result I get is not what I want. I get all companies which have a name like $request->input('search_term'). It ignores the type of the profile and the locations. The locations array is empty for those companies which don't match the specified search_addition but it still returns the company.

with() is used for relationship eager loading either with or without constraint, not used as a constraint to filter the parent model which you need to use where function family instead.
This is what I think the code should be (not tested).
$companies = Company::with('profile')
->with(['locations' => function ($query) use ($request) {
$query->where('zip', 'like', '%'.$request->input('search_addition').'%')
->orWhere('city', 'like', '%'.$request->input('search_addition').'%');
}])
->whereHas('profile', function ($query) {
$query->where('type', 0);
})
->whereHas('locations', function ($query) use ($request) {
$query->where('zip', 'like', '%'.$request->input('search_addition').'%')
->orWhere('city', 'like', '%'.$request->input('search_addition').'%');
})
->where('name', 'like', '%'.$request->input('search_term').'%');

Related

Modify Solr Query by adding additional filters in TYPO3

I'm trying to add custom filters to the query (TYPO3 v10, EXT:solr 11.2). However, this doesn't want to work.
After I simplified the use-case significantly and debugged it, I'm still not further, but rather more confused.
Filter works, if added via TypoScript:
plugin.tx_solr {
search {
filter {
jobTitle = title:Dev*
}
}
}
The same filter added via modifySearchQuery-hook does not work:
public function modifyQuery(Query $query)
{
$filterQuery = new FilterQuery([
'key' => 'jobTitle2',
'value' => 'title:Dev*',
]);
return $query->addFilterQuery($filterQuery);
}
When debugging the query, both filters look the same.
Thanks to Guido, who hit me on the right point: sometimes, keys are keys.
In the hook, the array-keys for FilterQuery have to be key and query (not value, as I've used)
public function modifyQuery(Query $query)
{
$filterQuery = new FilterQuery([
'key' => 'jobTitle2',
'query' => 'title:Dev*', // <-- correct key
]);
return $query->addFilterQuery($filterQuery);
}

Selectet data and data from with(), Laravel

I want to select some columns and some data from with(), the problem is that I get only data from select().
$today = date('Y-m-d', strtotime('-7 days'));
$contracts = Contract::select('
'contracts.id',
'contracts.contract_value_exc_VAT_total',
'customers.account_name',
'users.name',
)
->whereHas('dates', function($q) use($today){
return $q->whereDate('date', '>=', $today)
->where(function($q) {
$q->where('lkp_contract_date_tag_id', 4)
->orwhere('lkp_contract_date_tag_id', 7);
});
})
->with(['dates' => function($q){
$q->select('id', 'date');
}])
->join('customers','contracts.customer_id', 'customers.id')
->leftJoin('users','contracts.account_manager_select', 'users.id')
->get();
return response()->json($contracts);
From response, dates are null
//date....
dates: []
//date...
You can do it without using the select()
You can have the relations in the ContractModel. You can always process the data after getting from the database and manipulate it in a format you want to return.
There are two options to do that
Do it here in the controller itself.
Create an API resource for the Contract. (https://laravel.com/docs/7.x/eloquent-resources#introduction)
I would suggest the latter as it's more convenient.
For both of them you need to do this first. Make some changes in the contract model.
ContractModel.php
// I'm assuming that you have dates relation in the contract(because you've added it in the `with()` for eager loading.)
public function dates(){
...
}
// Instead of joining while doing the query, add the following
// relations in the contract as well.
public function customer(){
return $belongsTo('App\Customer', 'customer_id', 'id');
}
public function accountManagerSelect(){
return $belongsTo('App\User', 'account_manager_select', 'id');
}
This is how you go with the API resource approach.
Create the Contract Api Resource. And this is how the toArray() method should be.
toArray() {
// Get the dates in the format you want. I'have added the below
// format by considering the 'select' statement you added for
// dates.
$dates = [];
// will use the relation dates, to get the associated dates.
foreach($this->dates as $date){
array_push($dates, [
'id' => $date->id,
'date' => $date->date,
]);
}
return [
'id' => $this->id, // id of the contract.
'contract_value_exc_VAT_total' => $this
->contract_value_exc_VAT_total,
'account_name' => $this->account_name,
// This will use the accountManagerSelect relation to get the
// User instance and then you can access the name from that.
'name' => $this->accountManagerSelect->name,
'dates' => $dates, // The dates variable that we created earlier.
];
}
All you need to do is return using API resource in your controller.
instead of doing this
return response()->json($contracts);
Use Api resource
return ContractResource::collection($contracts);

postgres ignore -> orWhereHas

I Have 2 version app, one in local use MySQL and the other one is build in Heroku using PostgreSQL
The plan is to have search form that able to lookup data from different table
The table is books, writters, categories, and publishers
Here the controller
public function search(Request $request)
{
$keyword = $request->input('keyword');
// multiple query from different table
$query = Book::where('judul','like','%'.$keyword.'%')
->orWhere('label','like','%'.$keyword.'%')
->orWhere('isbn','like','%'.$keyword.'%')
->orWhere('status', 'like', '%'.$keyword.'%')
->orWhereHas('writter', function ($query) use ($keyword) {
$query->where('nama_penulis', 'like', '%'.$keyword.'%');
})
->orWhereHas('category', function ($query) use ($keyword) {
$query->where('nama_kategori', 'like', '%'.$keyword.'%');
})
->orWhereHas('publisher', function ($query) use ($keyword) {
$query->where('nama_penerbit', 'like', '%'.$keyword.'%');
})
;
$book_list = $query->paginate(5);
$pagination = $book_list->appends($request->except('page'));
$total_book = $book_list->total();
return view('dashboards.index', compact('book_list', 'keyword', 'pagination', 'total_book', 'nama_penulis'));
}
The form works like a charm on local (using my MySQL), but when I'm using Postgres the search form only able to fetch from books table.
I wonder what make postgres ignoring my code
someone on the Laracast explain to me that The problem is from like which is Case Sensitive for the Postgres, thats why my code didnt work.
If you have same issue, i recommend you to use ilike to make POstgres insensitive.
or you can try the alternative way by whereRaw instead.

Eloquent using parent field in subquery

How can i access the 'id' field in the first query, and use it in the second subquery in this example:
$users = \App\User::where('active', 1)->where('deleted_at', null)->where('recieve_jobagent', 1)
->with(['companies' => function($query){
$query->where('active', 1);
$query->with(['posts' => function($posts){
$posts->where('active', 1);
$posts->whereHas('users', function($postUsers){
**I do not have access to 'users.id' here**
$postUsers->where('user_id', 'users.id');
});
}]);
}]);
I'm using lumen 5.1.
My goal here is to get all users and their related companies, and the companies' posts that isn't related to the user.
I dont think you need to do that. You can use whereHas and by drilling down into the relationships it returns only the ones that belong to the thing you're querying.
Without seeing your relationship structure, I would assume you need something like this?
$users = \App\User::where('active', 1)->where('deleted_at', null)->where('recieve_jobagent', 1)
->whereHas('companies', function($query){
$query->where('active', 1)
->whereHas('posts', function($query){
where('active', 1);
})
})
->with(['companies' => function($query){
$query->where('active', 1);
$query->with(['posts' => function($posts){
$posts->where('active', 1);
}]);
}]);

Laravel - SELECT only certain columns within a `::with` controller function

The following code I have is working perfectly fine, however, it returns more data than what is necessary from each table:
public function getIndex()
{
$alerts = Criteria::with('bedrooms', 'properties')
->where('user_id', '=', Auth::id())
->get();
$this->layout->content = View::make('users.alert.index',
array('alerts' => $alerts));
}
What I'd like to do is, for example, select only the bedroom column out of the bedroom table. As it stands now, it returns all columns.
I have tried:
public function getIndex()
{
$alerts = Criteria::with('bedrooms' => function($q){
$q->select('bedroom');
}, 'properties')
->where('user_id', '=', Auth::id())
->get();
$this->layout->content = View::make('users.alert.index',
array('alerts' => $alerts));
}
But I am presented with the following error:
syntax error, unexpected '=>' (T_DOUBLE_ARROW)
Any help as to how I can achieve this will be hugely appreciated.
Update
public function getIndex()
{
$alerts = Criteria::with(
['coordinate' => function($w){
$w->select('name', 'id');
}],
['bedrooms' => function($q){
$q->select('bedroom', 'criteria_id');
}]
, 'properties')
->where('user_id', Auth::id())
->get();
$this->layout->content = View::make('users.alert.index',
array('alerts' => $alerts));
}
The correct select query works for which ever is queried first. If I swap the queries around, the bedroom function works correctly, but the rest aren't eager loaded nor does the select query work.
Just pass an array there:
// note [ and ]
$alerts = Criteria::with(['bedrooms' => function($q){
$q->select('bedroom', 'PK / FK');
}, 'properties'])
Also mind that you need to select the keys of that relation (primary key/foreign key of the relation).
The answer to your update question is that you need to eager load other values in the same array some thing like this.
public function getIndex()
{
$alerts = Criteria::with(
['coordinate' => function($w)
{
$w->select('name', 'id');
},
'bedrooms' => function($q)
{
$q->select('bedroom', 'criteria_id');
}
, 'properties'])
->where('user_id', Auth::id())
->get();
$this->layout->content = View::make('users.alert.index',
array('alerts' => $alerts));
}