Laravel 5.8 pagination without Eloquent - laravel

I need a custom pagination but in my case, i do not use eloquent for fetching data. I use an API where i fetch data.
I've been dealing with Pagination class, but as far as i know, it takes a collection and paginate it. That's not what i need.
What i need is creating a paginate object based on a subset of records gotten by a search query. Let's say such query has a total of 10000 records and I only get an array of 50 items, so each paginate has 50 elements. So, i need to create the pagination links based on this info.
Is there any way of accomplish it?
EDIT:
$models = array('total' => $n_results,
'per_page' => 30,
'current_page' => 1,
'last_page' => ceil($n_results/30),
'next_page' => "******",
'prev_page' => "******",
'from' => 1,
'to' => 30,
'data' => $items);

Based on what I understood here what I would do:
1- if you cannot ask the limit and offset for each call of the API and the API provides all the results to you at once but you want to show them 50 at a time, then I would create a temp_table and insert the data to it and then it's like it's on my own database then I would be able to sort,limit and offset by myself.
2- if the total result is not that much (like less than 500) and you want the user to not be overwhelmed by all the results together and you wanna show it to them 50 results at a time or 20 results at a time you can load all the result in blade by hide their element. (it's not what I would recommend but it would do the trick if you don't want a temp_table)

Related

Yii2 cache of grid view

I have a relatively complex query across 8 tables which returns up to 10,000 records with 20 columns. These are then displayed in a GridView
The user repeatedly sorts and filters the GridView - causing a page reload - in order to rank the data. One column contains an Ajax “five star” rating function and the user then marks each row: one star to five stars
Naturally, this isn’t the fastest loading page so I was wondering if I could use caching to accelerate the page load but don’t know if this can be done considering the filtering and marking
Can caching be used in this example? The data in the 19 columns are always the same (the user cannot change the data) but the user constantly changes the rating in the 20th column
Can I cache the 19 columns and filter / sort after??
Can I cache the 19 columns and join the rating column thereafter??
Many thanks
You can easily use the PageCache filter behavior of yii2 to easily cache pages.
Just add the following code to your controller and fit the dependency and variation properties to your needs.
public function behaviors()
{
return [
'pageCache' => [
'class' => 'yii\filters\PageCache',
'only' => ['index'],
'duration' => 60,
'dependency' => [
'class' => 'yii\caching\DbDependency',
'sql' => 'SELECT COUNT(*) FROM post',
],
'variations' => [
\Yii::$app->language,
]
],
];
}

Comparing laravel collections

I have two collections: "Instructions" and "Known". Basically I am taking a new set of "Instructions" and checking whether anything is different to what is "Known".
So, the quantity is not massive. I retrieve the info:
$Instructions = Instruction::all();
$Knowns = Known::all();
Now, I'm looking for the differences, and I've tried each of these three methods:
$IssuesFound = $Instructions->diff($Knowns);
$IssuesFound = $Instructions->diffKeys($Knowns);
$IssuesFound = $Instructions->diffAssoc($Knowns);
The thing is, an "Instruction" or "Known" is an item with 17 attributes, and anyone of those attributes can be different. I want to compare the attributes of an "Instruction" with the matching attribute of a "Known". (Both items have the same keys, bot items have a Reference attribute to act as a unique identifier.
What I'm finding is that theese methods give me the item that is different, but doesn't tell me which individual attributes are the mismatch.
foreach ($IssuesFound as $issue)
{
dd($issue);
}
So a method like $IssuesFound = $Instructions->diffKeys($Knowns); will come up with item xxx being different, but I can't see how to find out which attribute of the item it is that is different. Not unless I start nesting loops and iterating through all the attributes - which I'm trying to avoid.
How do I do it?
Thanks in advance. (Laravel 5.6)
Straight from laravel docs, diffAssoc will return what you are asking:
$collection = collect([
'color' => 'orange',
'type' => 'fruit',
'remain' => 6
]);
$diff = $collection->diffAssoc([
'color' => 'yellow',
'type' => 'fruit',
'remain' => 3,
'used' => 6
]);
$diff->all();
// ['color' => 'orange', 'remain' => 6]
You get the attribute from the FIRST collection that is different on the SECOND collection, therefore if you get 3 attributes when calling $diff->all() you will know WHICH attributes ARE DIFFERENT, so you could access them or do whatever you want to, if you post more specific results of what you are getting and what you are trying we can help, but I think you are just not thinking how to use these methods

how to merge elasticsearch results into one field or how to explain which field results were found in

follow me on this one...
if i've got a db of movies and i want to search on multiple fields and return the results into a single field, how would i accomplish this?
let me set an example...
my documents have a title and artists.name (array). i want the user to be able to search in both title and artist at the same time so that the results are in the same field. this would be implemented in an 'autocomplete' search scenario where you get results as you type.
so if a user types 'mike' i want to be able to search for actors (artists.name) with the name mike and titles with the word mike in it. in this case, you might return 'magic mike' and 'mike meyers' in the same autocomplete result set. (imdb.com has this implementation)
i understand how to search both of those fields, but how do i return them into one? i believe i'd have to have some knowledge on where my 'hit' came from - title or artists.name. so maybe that's the larger question here - how do i tell which field the hit came from?
I don't think there are any direct ways to determine which field(s) a query matched on. I can think of a few "workaround" approaches that may do it for you- one is by using the multisearch api, and executing separate queries on each field. Another is using highlighting, which will return back the fields that a match was found in.
Example using multi search:
var response = client.MultiSearch(ms => ms
.Search<Artist>("name", s => s.Query(q => q.Match(m => m.OnField(a => a.Name).Query("mike"))))
.Search<Artist>("titles", s => s.Query(q => q.Match(m => m.OnField(a => a.Titles).Query("mike")))));
response.GetResponse<Artist>("name"); // <-- Contains search results from matching on Name
response.GetResponse<Artist>("titles"); // <-- Contains search results from matching on Titles
Example using highlighting:
var response = client.Search<Artist>(s => s
.Query(q => q
.MultiMatch(m => m
.OnFields(a => a.Name, a => a.Titles)
.Query("mike")))
.Highlight(h => h
.OnFields(fs => fs.OnField(a => a.Name),
fs => fs.OnField(a => a.Titles))));
You can then inspect the Highlights object of each hit, or the Highlights object of the response to determine what field the match came from.
There is also the explain api, and you can add explain to your query, but that will return a lot of irrelevant scoring info, which you would have to parse through. Probably too cumbersome for your needs.
As a side note- for autocomplete functionality, if possible I would really try to leverage the completion suggester instead of the above solutions. These are pre-computed suggestions that are created when you index your documents by building up FSTs, which will increase your indexing time as well as index size, but as a result will provide extremely fast suggestions.

Laravel attach pivot to table with multiple values

Background
I'm creating a database revolving around food allergies and I have a many to many relationship between foods and allergies. There is also a pivot value called severity which has a numerical number representing the severity of the allergy for that food item.
This link table looks like this;
food_id|allergy_id|severity
-------|----------|--------
1 | 1 | 3
1 | 4 | 1
2 | 2 | 1
The problem
When trying to update the link table with Eloquent (where $allergy_ids is an array)
$food->allergies()->attach($allergy_ids);
How would I go about adding multiple values to this pivot table at once along with the pivot values?
I can add all the allergy_id's for a particular food item in one go using the above line, but how can I also add in the severity column at the same time with an array of various severity values? Maybe something like
$food->allergies()->attach($allergy_ids, $severity_ids);
Edit: There could be between 0-20 allergies for a specific food item, and a severity rating from 0-4 for each allergy, if this helps at all.
You can.
From this example in Docs (4.2, 5.0):
$user->roles()->sync(array(1 => array('expires' => true)));
Hardcoded version for the first two rows:
$food = Food::find(1);
$food->allergies()->sync([1 => ['severity' => 3], 4 => ['severity' => 1]]);
Dynamically, with your arrays $allergy_ids and $severities in a compatible state (size and sort), you shall prepare your sync data before. Something like:
$sync_data = [];
for($i = 0; $i < count($allergy_ids); $i++))
$sync_data[$allergy_ids[$i]] = ['severity' => $severities[$i]];
$food->allergies()->sync($sync_data);
You can't do it like you' like so I suggest a simple loop:
foreach ($allergy_ids as $key => $id)
{
$food->allergies()->attach($id, array_get($severity_ids, $key));
// should you need a sensible default pass it as a 3rd parameter to the array_get()
}
workaround
However if you wanted to attach multiple allergies with single severity level/id then you could do this:
$food->allergies()->attach($allergy_ids, array('severity' => $singleSeverityValue));
From version 5.1 of Laravel (Currently in Laravel 9.x) onwards it is possible to pass an array as a second argument with all the additional parameters that need to be saved in the intermediate table.
As you can read in the documentation
When attaching a relationship to a model, you may also pass an array of additional data to be inserted into the intermediate table:
$user->roles()->attach($roleId, ['expires' => $expires]);
For convenience, attach and detach also accept arrays of IDs as input:
$user->roles()->attach([1 => ['expires' => $expires], 2, 3]);
Then you can simply do
$food->allergies()->attach([1 => ['severity' => 3], 4 => ['severity' => 1]]);
So, on Laravel 9, passing the ids in the array worked for me. Likeso,
$user->roles()->attach([$a->id,$b->id,$c->id]); and so on.
I guess instead of passing the string. We can pass just the id or else convert the string into array.
Easiest indeed is to attach with the extra data, like so:
$retailer->paymentmethods()->attach($paymentmethod, array('currency' => $paymentmethod->currency));
change out the values for food allergy severity, but you get the hint... :-)

Maintain the natural sort of overall results, but sort a subfield array within each result in elasticsearch?

Our defined Type is something like this:
'title' => ... ,
'body' => ... ,
'links' => 'type'=>'object', 'properties'=> array
'link' => ... ,
'locations' => 'type'=>'object', 'properties'=> array
'label' => ... ,
'pin' => ...
)
The records/documents represent businesses that reside in one or more categories, and so the links array will contain all of the potential links to a business, i.e.
[0] => '/Businesses/Hotels/My-Business/',
[1] => '/Businesses/Resorts/My-Business/',
[2] => '/Businesses/Fractional-Ownership/My-Business/'
So when we run a query on the terms Business Resort this listing is included in the result set. At the moment though, we don't know which link would be most appropriate to display on the results page, so we just default to the first, in this case the one with ../Hotels/.. in the path.
Is it possible to order the links according to their own score/relevancy within the search so that the link order on the returned result would instead be:
[0] => '/Businesses/Resorts/My-Business/',
[1] => '/Businesses/Hotels/My-Business/',
[2] => '/Businesses/Fractional-Ownership/My-Business/'
The order of the links should not have any influence on the order of natural results from the overall query.
EDIT : The second use case which I've added above is, we also store locations for each business, and would like to order the location list for each resulting business by their proximity to a set of coordinates. We know how to order the entire result set by _geo_distance but need to know how to do it on a specific field, and like above, without affecting the overall result order.
Script based sorting will give you exactly what you want to sort on. But track_scores seems it will do what you're looking for, sorting doesn't use scores by default.
And for ordering geo distance sorting by a specific field you could do so client side, providing the specific field value of the selected field? I'm not sure this answers your second question.

Resources