Search On Custom Query Result-Collection With Algolia - Laravel - php

I have collection that created with complicated laravel query and this query's result is too big. So i think i must use algolia. As i know, algolia gets the model table data to itself as json and serve from there.
$result = User::search("UserName")->get();
It needs to some model configurations like searchAs etc.. all are related with existing model and you can make search from model with search method (above example). What i want to ask is, i have complicated query and result has too many attributes that come from another tables (joined). I want to make search on my custom query result. Is it possible ?
My example query :
$friendShips = Friend::
join("vp_users as users","users.id","=","friendships.friendID")
->leftJoin("vp_friendships as friendshipsForFriend",function($join) use ($request)
{
$join->on("friendships.friendID","=","friendshipsForFriend.userID");
$join->on("friendshipsForFriend.friendID","=",DB::raw($request->userID));
})
->leftJoin("vp_videos_friends as videosFromFriendMedias",function($join)
{
$join->on("videosFromFriendMedias.userID","=","friendships.friendID");
$join->on("videosFromFriendMedias.friendID", "=" ,"friendships.userID");
$join->on("videosFromFriendMedias.isCalled", "=" , DB::raw(self::CALLED));
})
->leftJoin("vp_videos_friends as videosToFriendMedias",function($join)
{
$join->on("videosToFriendMedias.userID", '=', "friendships.userID");
$join->on("videosToFriendMedias.friendID", '=', "friendships.friendID");
$join->on(function($join){
$join->on("videosToFriendMedias.isCalled", '=', DB::raw(self::CALLED));
$join->orOn("videosToFriendMedias.isActive", '=', DB::raw(self::ACTIVE));
});
})
->leftJoin("vp_videos_friends as
//some join rules too
})...

I believe the best way would be to use this request and chain the searchable() method. It will index the collection returned by the query to Algolia.
$friendShips = Friend::
join("vp_users as users","users.id","=","friendships.friendID")
->leftJoin("vp_friendships as friendshipsForFriend",function($join) use ($request) {
$join->on("friendships.friendID","=","friendshipsForFriend.userID");
$join->on("friendshipsForFriend.friendID","=",DB::raw($request->userID));
})
->searchable();

Related

With PHP Laravel, how can I make an Eloquent query that is conditional like a "when" statement, but dependent on the value of retrieved columns?

This question can probably be best asked in the form of an analogy.
Let's say I have a "table" model that has many "filters" - these filters have a column "type" which has to either be "color" or "make", and an "allowed" column which contains the array of allowed values for each. I want to use these tables to display a filtered list of "cars" (which have color/make columns), and if I then add a car to the DB, I want it to figure out the set of tables to which that car needs to be added depending on every table's filters for car and make. So that means I query tables, and I join filters - but where the filters are "color", they have to contain the color of the car, and where the filters are "make", they have to match the make of the car. In this way, the table would get a list of cars that matches all of its filters. In pseudocode, this would be something like:
Table::join('filters', 'filters.table_id', '=', 'tables.id')
->when('filters.type', '=', "color", function($query) use ($car) {
$query->whereJsonContains('filters.allowed', $car->type);
})
->orWhen('filters.type', '=', "make", function($query) use ($car) {
$query->whereJsonContains('filters.allowed', $car->make);
})
->get();
And I'm trying to work out what, if possible, the correct way of writing such a query would be. I had the following before:
Table::join('filters', 'filters.table_id', '=', 'tables.id')
>where(function ($query) use ($car) {
$query->where('filters.type', "color")
->whereJsonContains('filters.allowed', $car->color);
})->orWhere(function($query) use ($car) {
$query->where('filters.type', "make")
->whereJsonContains('filters.allowed', $car->make);
})->get();
But this would return all tables where the car matched any of the filters instead of all of them. If I make it a where instead of an orWhere, then I get conflicting conditions in where('filters.filter_type', "make") and where('filters.filter_type', "color"), which will then give me no results at all. So, is it possible to write conditional when clauses that depend upon the value of columns like in my pseudocode example? Thanks very much!
Figured it out! Wasn't actually as difficult as I thought, and didn't require any raw SQL. First, I created two extra relationships for the table in addition to the filters one:
public function filters()
{
return $this->hasMany(Filter::class);
}
public function colorFilters()
{
return $this->filters()->where('type', "color");
}
public function makeFilters()
{
return $this->filters()->where('type', "make");
}
Then I was able to make the query work by using whereHas and logical grouping:
Table::where(function ($query) use ($car) {
$query->whereHas('colorFilters', function($colorQuery) use ($car) {
$colorQuery->whereJsonContains('allowed', $car->color);
})
->orWhereDoesntHave('colorFilters');
})
->where(function ($query) use ($car) {
$query->whereHas('makeFilters', function($makeQuery) use ($car) {
$makeQuery->whereJsonContains('allowed', $car->make);
})
->orWhereDoesntHave('makeFilters');
})
->get();

Search through laravel relations with builder

I'm trying to work on a query builder in Laravel and want to search through a model's relations. So far my code looks like this:
$search = (new City)->newQuery();
// Search for a city based on its state.
if ($request->has('state')) {
$inquiry->whereHas('state', function ($query) use ($request) {
$query->whereState($request->state);
});
}
So I have a City model and a State model. The query is supposed to look through cities and then check each one's state relation and extract the model with the relevant states.
The code doesn't produce any errors, just an empty object.
Try this:
City::when(request()->has('state'), function($query){
$query->whereHas('state', function ($query){
$query->where('state', request()->input('state'));
});
})->get()

Laravel Eloquent - building 'where not' query with relationship

I have 5 database rows with the same client_id, 3 labelled completed, Yes.
This code pulls through 3 results as expected:
$indGoal = $client->indGoal()->where('completed','=','Yes')->get();
This code pulls through no results: I would expect 2.
$indGoal = $client->indGoal()->where('completed','!=','Yes')->get();
This question suggests adding ->orWhereNull('completed') - which works, but ignores the client_id relationship. The request brings through all non-Yes results, regardless of $client
My Client model for reference:
public function indGoal()
{
return $this->hasMany('App\Models\IndGoal');
}
You should group orWhere filters in a callback so they don't interfere with existing filters.
$indGoal = $client->indGoal()
->where(function ($query) {
$query->orWhere('completed', '!=', 'yes')
->orWhereNull('completed');
})
->get();
This way, the query builder knows any of the grouped conditions should be true and all other conditions are independent.

Laravel Pagination with Get request

I've followed the instructions on the Laravel documentation for pagination with appends([]) however I'm having a little trouble with the persistence of these parameters.
Say for example, I pass home?category=Cars&make=Tesla to my view. What is the best way to paginate with them Get requests?
Right now I've passed the category as a parameter to the view as (where category is the model i've grabbed findOrFail with the request('category');)
$category_name = $category_model->name;
And then in my view it's like so:
{{ $vehicles->appends(['category' => $category_name])->links() }}
But when I go between pages in the pagination, this $category_name value doesn't seem to persist. Whats the recommended way to achieve what I want?
Thanks.
You can append the query string in your controller when you paginate the result. I'm not sure if that was your only question or even regarding applying the query string as a condition. So here is a sample showing you how to do both. This should give you an idea of how to do it. I just assumed the column names in this example.
$category = request('category');
$make = request('make');
$vehicles = Vehicle::when($category, function ($query) use ($category) {
return $query->where('category', $category);
})
->when($make, function ($query) use ($make) {
return $query->where('make', $make);
})
->paginate(10);
$vehicles->appends(request()->query());
return view('someview', compact('vehicles'));

Searching API with query string

I am currently building an API, I want to be able to search the API via the query string. So for example http://api.dev/?q=12
I can get the value entered but how do I then use this to search the database?
if ($q = Input::get('q'))
{
return( ModelName::where('id', '=', $q));
}
This doesn't seem to change the search and the same data is just returned.
ID's are unique so it doesn't surprise me you're getting the same result.
For Laravel I find the query builder to be better at handling search queries instead of Eloquent.
E.g.
$users = DB::table('users')
->where('votes', '>', 100)
->orWhere('name', 'John')
->get();
Hope this helps.
To search from the db with Eloquent you can use both this ways:
ModelName::where('id', '=', $q)->get();
or
ModelName::find($q);
In the second example Laravel assumes that your Primary Key is id, so in case you have another field as your primary you have to overwrite it, by setting the property in the model.
class ModelName
{
...your props
private $primaryKey = 'yourPrimaryKey'
...
}

Categories