Hello StackOverflow Community, after some research we decided to ask you for the solution.
We would like to have a link with a defined array. The goal would be to have a link such as:
www.testurl.com/restaurants/CUISINENAME/
Then, we would just like to see all restaurants with the particular cuisine. The filter is currently working on the website with a checkbox.
Router
Route::group(['prefix' => 'restaurants', 'namespace' => 'frontEnd', 'middleware'=>'checkzipcode'], function () {
Route::get('/', 'RestaurantController#showAllRestaurants');
Route::post('/', 'RestaurantController#showAllRestaurants');
});
Controller
if (request('cusineName')) {
if (is_array(request('cusineName'))) {
$cusineName = request('cusineName');
} else {
$cusineName = (explode(",", request('cusineName')));
}
$all_restaurant = $all_restaurant->whereIn('restaurant_cuisines.type_cuisine_id', $cusineName);
}
We were thinking of setting the array into the controller. Does anyone have any other suggestions?
Firstly, your array check is fine. However, you should return false if no cusineName has been passed through (As there is no point continuing).
You then are able to do an eloquent query for restaurants which have a particular cuisine by using the whereHas() method:
...
$restaurants = Restaurant::whereHas('cuisine', function($query) use ($cuisines) {
$query->whereIn('id', $cuisines);
})->get();
...
In the example, we pass through $cuisines to be used within the whereHas() eloquent method, to then use in the whereIn() method. This will check against the array if the cuisine's id is found.
Related
I do a specific relation query all over the application, where I only need the User's subscriptions that have active column set to true.
And I have a scope method in User model, which applies said filter, to avoid copy/paste, like:
public function scopeWithActiveSubscriptions($query)
{
$query->with([
'subscriptions' => function ($query) {
$query->where('active', true);
},
]);
}
Now sometimes I want to eager-load the plan of each subscription, too.
For that I tried something like:
$user = User::where('id', 1)
->withActiveSubscriptions()
->with('subscriptions.plan')
->first();
$subscriptionList = $user->subscriptions;
But query results to all subscriptions,
in other words, ignores the ->where('active', true) part (of scope method).
How can I make this work correctly?
A quick solution would be modifying the scopeWithActiveSubscriptions method to allow it to accept another optional parameter that tells it which additional relations should also be included and thus you don't loose your filtering.
public function scopeWithActiveSubscriptions($query, array $with = [])
{
// just merges hard coded subscription filtering with the supplied relations from $with parameter
$query->with(array_merge([
'subscriptions' => function ($query) {
$query->where('active', true);
}
], $with));
}
Now you can tell that scope which nested relations you want to include and you no longer need to call with to include them by yourself.
$user = User::where('id', 1)
->withActiveSubscriptions(['subscriptions.plan'])
// ->with('subscriptions.plan') // no longer needed as we're telling the scope to do that for us
->first();
$subscriptionList = $user->subscriptions;
With that you can pass custom relations to the scope something like (am improvising here just for demo purposes)
$user = User::where('id', 1)
->withActiveSubscriptions([
'subscriptions.plan' => fn($q) => $q->where('plans.type', 'GOLD')
])->first();
Learn more about Laravel's Eloquent Scopes.
Hope i have pushed you further.
Seems Laravel does not have yet any chainable (Builder-style) solution (for asked situation), and we ended up editing the scope filter.
Into something like:
public function scopeWithPendingSubscriptions(Builder $query, $subRelations = null)
{
$query->with([
'subscriptions' => function (HasMany $query) use ($subRelations) {
$query->where('active', '=', true);
if ($subRelations) {
$query->with($subRelations);
}
},
]);
}
Which allows me to do query like:
// ...
->withActiveSubscriptions('plan');
Instead of my old (not working) code, which was:
// ...
->withActiveSubscriptions()
->with('subscriptions.plan');
Note that even passing nested-filters is now possible, like:
// ...
->withActiveSubscriptions(['plan' => function ($query) {
$query->where('name');
}]);
(Basically same as Laravel's ->with(...) method.)
I am working on an API endpoint that returns a list of users that have all of the given services ID's.
In my case:
Users can have many services
Tables: 'users', 'services', 'service_user'
I am passing an array via Vue JS to my end point for example:
/endpoint/32,35,38
My query is currently:
$servicesArray = explode(',', $services);
$users = User::whereHas('services', function ($query) use ($servicesArray) {
foreach ($servicesArray as $key => $value) {
$query->where('id', $value);
}
})
->get();
The issue is that it seems to return now results, even if a user does have the correct services. My relationship is fine, and if I only pass one service to the endpoint it correctly returns a user that has that service assigned. I used whereIn before, but I need to only show users that have ALL of the services specified in the endpoint array.
Any obvious reason why what I have is not working as expected?
I would try something like this:
$q = User::query();
foreach ($servicesArray as $key => $value) {
$q->whereHas('services', function ($query) use ($value) {
$query->where('id', $value);
});
}
$users = $q->get();
You can also use laravel hasmany realationship function for getting multiple records from other table.
Example:
---In your Controller use query like.
$users = User::with('services')->where('id', $value)->get();
---And in your model's class use function services like this.
function services(){
return $this->hasMany('App\Service','user_id','id');
}
I have 2 routes with their methods written in same controller[LinkController]:
Route::get('/{country}/{category}', ['as' => 'tour.list', 'uses' => 'LinkController#tourlist']);
Route::get('/{category}/{slug}',['as' => 'single.tour', 'uses' => 'LinkController#singleTour']);
And my methods are:
public function tourlist($country, $category)
{
$tour = Tour::whereHas('category', function($q) use($category) {
$q->where('name','=', $category);
})
->whereHas('country', function($r) use($country) {
$r->where('name','=', $country);
})
->get();
return view('public.tours.list')->withTours($tour);
}
public function singleTour($slug,$category)
{
$tour = Tour::where('slug','=', $slug)
->whereHas('category', function($r) use($category) {
$r->where('name','=', $category);
})
->first();
return view('public.tours.show')->withTour($tour);
}
My code in view is:
{{$tour->title}}
The trouble i am having is the second route [single.tour] returns the view of the first route [tour.list]. I tried to return other view also in 2nd method but still it returns the view of first method. Does laravel have routing precedence ?
This is happening because, Laravel matches routes from the file, and the route which comes earlier and matches the pattern will execute first, you can use regex pattern technique to avoid this like:
Route::get('user/{name}', function ($name) {
//
})->where('name', '[A-Za-z]+'); // <------ define your regex here to differ the routes
See Laravel Routing Docs
Hope this helps!
Both your routes consist of two parameters in the same place. That means any url that matches route 1 will also match route 2. No matter in what order you put them in your routes definition, all requests will always go to the same route.
To avoid that you can specify restrictions on the parameters using regular expressions. For example, the country parameter may only accept two letter country codes, or the category parameter may have to be a numeric id.
Route::get('/{country}/{category}')
->where('country', '[A-Z]{2}')
->where('category', '[0-9]+');
https://laravel.com/docs/5.3/routing#parameters-regular-expression-constraints
I want to build a custom find function that retrieves bands for a given genre, i have tried this but the function can't access to the parameter $genre:
public function findGenre(Query $query, array $options)
{
$genre = $options['genre'];
$bands = $this->find()->contain([
'Genres' => function($q){
return $q->where(['Genres.id' => $genre]);
}
]);
return $bands;
}
I can access the $genre outside the contain() method, but not inside it.
My question is, how can i pass the $genre var to the function($q) inside the contain method.
I found where the problem is, i had to use the keyword use after the function($q), so that part of the code will look like this
$bands = $this->Bands->find()->contain('Genres', function($q) use ($genre){
return $q->where(['Genres.name'=>$genre]);
});
Also,the contain() method returns all the data even if the bands don't belong to a genre, but when i replaced it with matching() it worked just fine.
I hope this will help anyone who is having a similar problem in the future.
I was facing same issue but now it's resolved. I will explain you step by step:
My tables are:
articles: id,name,status,created
tags:id,name,status,created
articles_tags: id,article_id, tag_id
my query is this:
I want to pass my $tag_data['slug'] in matching variable but
directly this variable is not working in query. So I put in simple
$uses variable and now it's working properly.
$uses = $tag_data['slug'];
$contain_article = ['Tags'];
$query = $this->Articles->find('All')
->where(['Articles.status' => '1'])
->contain($contain_article)
->matching('Tags', function ($q) use ($uses) {
return $q->where(['Tags.slug' => $uses]);
});
Please try this :-)
I'm currently facing a small problem. I want to return a model only if a relation with certain conditions exists. That's working fine with the whereHas()-method.
$m = Model
::whereHas(
'programs',
function($q) {
$q->active();
}
);
However, calling the relation as a property like this will give me all (not filtered results).
$m->programs;
So basically what I'm doing now is this:
$m = Model
::whereHas(
'programs',
function($q) {
$q->active();
}
)
->with(array('programs' => function($q) {
$q->active();
}))
;
That's working fine but I feel very bad about doing the same thing again. That can't be the right way. How can I achieve this without kind of duplicating the code?
If a concept of an "active program" is important in your application, consider creating a separate relation just for active programs (in this case I'm presuming you have a HasMany relation):
class Model
{
public function activePrograms()
{
return $this->hasMany(Program::class)->active();
}
}
Then you can simplify your query to:
Model::with('activePrograms')->has('activePrograms')->get();
In Laravel 9.17 withWhereHas
Example:
$a= Model::withWhereHas('programs', function ($query) {
$query->active();
})->get();
Check out the documentation for more information.