Remove last two rows in a Laravel Collection Object - php

I am trying to remove the last two row in a Laravel Collection. The size of the Collection can vary, but I will always want to remove the last two. I managed it by doing this, but out of curiosity, do you think there is a better way to do this ?
Here is my way :
$results = $results->reverse()->slice(2)->reverse();
Thanks a lot
John

The Collection object's slice() method works similarly to array_slice(), allowing a negative value for the length argument, so you should be able to keep it simple and just do
$results = $results->slice(0, -2);

You can use the pop method twice.

Related

How to customize Laravel whereBetween clause to make upper limit unlimited?

I have been working on laravel using eloquent query builders. I have a situation in which I am filtering records based on search queries. I have an integer field, for which I want to filter data in ranges. User can select any of available ranges for example;
0-15, 15-30 and 30 and above.
For this purpose I found Query-builders whereBetween() clause very helping. But It becomes difficult for me for last option when I want to select for 30 and above.
I would really appreciate if someone could help me with some trick make this query
->whereBetween('time_taken', [$lower-limit,$uper_limt])
working for all cases.
I don't want to write an additional line for this case, at which I can use simple where clause
->where('time_taken','>=',$uper_limt).
The practical solution here is to just choose the appropriate SQL condition (I'm using a ternary operator here to keep it more compact):
$query = App\Operation::query();
(empty($upper_limit)) ? $query->where('time_taken','>=', $lower_limit)
: $query->whereBetween('time_taken', [$lower_limit, $upper_limit]);
$results = $query->get();
Sure it would be nice to have just one line:
$results = App\Operation::whereBetween('time_taken', [$lower_limit, $upper_limit])->get();
But that's not possible in this case, not unless you want to extend the Laravel Query Builder and modify the way it handles empty parameters in the range passed as the value.
Writing clean and concise code is something we all strive to achieve, but one line solutions are not always possible. So my advice is to stop fixating (something I sometimes do myself) on things like this, because in some cases it's a lost cause that just ends up wasting time.
You can try any of these:
Method 1:
->whereBetween('time_taken', [$lower-limit,ModelName::max('time_taken')])
Method 2:
->whereBetween('time_taken', [$lower-limit,DB::table('table_name')->max('time_taken')])
Method 3:
$max = ModelName::max('time_taken');
//or
$max = DB::table('table_name')->max('time_taken');
//then
->whereBetween('time_taken', [$lower-limit,$max])
max() returns the highest value from your corespondent column.

Laravel - Retrieve Entries Starting with "X"

I've been looking around and testing things for about 2 hours now, and I finally figured it's time to reach out for help.
Basically, I want to do an search on a catalog - but only return items starting with a specific letter. I've tried multiple things from raw queries, to trying to bend where() to my liking - but none of the existing methods to achieve this has worked for me yet.
The code is rather simple that I'm working with here.
$var = DB::('table')->where('field', 'LIKE', "%$argument")->get();
$argument is passed via URI (root.com/controller/sort-by/field/$arg). All URI segments print out correctly when dd()'ed. So the proper value is being passed to the query, I would assume? Also if I dd($var), then it populates with the table's entries when I drop out the where() statement.
I've attempted a lot of things here, and nothing is pulling the single entry that I have in the database at the moment...
So, am I'm extremely overlooking something here - or actually tackling this the wrong way?
I swapped my query to
$foo = MODEL::where('#FIELD#', 'LIKE', $arg . '%')->get();
Then I can access the values by enumerating through the returned array. So a foreach will be required, but in general terms.
{{ $foo[0]->field }}
Returns the field value.
Thanks all.

Array_unique on a laravel eloquent collection

Not sure if this is possible but im trying to run array_unique over a collection of items i have, to remove duplicates. Although i cannot get it working.
my controller logic:
// init models
$jobs = Job::search();
$countries = $jobs->get()->map(function( $job ) {
return $job->country;
});
$countries = array_unique( $countries->toArray() );
although this gets a "Array to string conversion" error
You could try the Unique method of the Collection class:
$countries = $countries->unique();
The Collection class has several wonderful methods. You could read about this in the Laravel API documentation.
I agree that sometimes it is more efficient to "query" on an existing Collection in memory (in stead of doing another query on the database using the Querybuilder class), like for example you first want to count and then filter. In .NET LINQ you can query almost equally on an IEnumerable (in-memory collection) as on a database, something I really enjoy.
I had similar issue and although time have passed since it may be useful to someone today.
The Problem I had was that when I called unique method on collection of items it didn't worked, that is probably the reason the first answer got accepted. So if you have models and you want to remove duplicates based on a specific field you can pass parameter to your unique method, in this case it would be:
$countries->unique('code');
that way you'll only have countries with unique codes. You may notice that only the first value stays, so if you develop a shopping cart application and want for some reason merge carts and only want to have recent items you can just reverse the collection and call unique and reverse it back:
$countries->reverse()->unique('code')->reverse(); // it doesn't really make sense in this example though
it is probably not the best option and it is better to do filtering on the database side but it is nice to have options.
You can have unique values in your DB results using distinct or group by in your select clause. But, if you really need to have unique values over an array of object you can do the following:
$uniques = array();
foreach ($countries as $c) {
$uniques[$c->code] = $c; // Get unique country by code.
}
dd($uniques);
You could try the filter method on eloquent collections if that's exactly what you want to do
http://laravel.com/docs/eloquent#collections

Loop in query function without "while"

Is it possible to show all rows with the properties from my query using only different last function. Something different from fetch_object();?
here is my query:
$dbo_training = $db->query("select * from tabela where id='$tr'")->fetch_object();
which is showing me only one row...
Not sure i completley understand you but if what you want is an array of all the results, the method fetch_object() only returns the first row by definition. try using fetch_assoc() to get an array containing all the results.
I guess you are using mysqli::fetch_object(). If so, you might want to have a look at mysqli::fetch_all which »Fetches all result rows as an associative array, a numeric array, or both« (but apparently not as array of objects…) If you need the objects, you'll probably have to stick to a while loop. (And there is nothing bad about a while loop per se)
I don't know what ORM you are using but with PDO (the PHP standard database accessor) you have to call fetchAll() to do that. If you are using your own library you should have a look to PDO which is very powerful!

how to stop a filter from continuing on a recordset or collection

So I have a variable and a recordset:
$firstRecordID = 1;
$records = Recordset::all();
I want to filter the recordset:
$filteredRecords = $records->find(function($record) use ($firstRecordID){
return ($record->id == $firstRecordID);
});
In this example, assuming the record id is a primary key, there will only be one row that will get returned, however, I think the filter will keep on going.
My question is, how do I force the filter to stop after a certain condition is met?
edit: I'll add another more complex example:
$filteredRecords = $records->find(function($record) use ($lastRecordID){
$conditions == $records->conditions;
// in here I would find some value
// based on some other unknown record based on the $conditions
// if the value matches any of the $conditions return the row
// if the value matches a specified stop condition
// (which is defined by the user) stop retrieving rows.
});
I think the solution is to use first($filter)
$filteredRecords = $records->first(function($record) use ($firstRecordID){
return ($record->id == $firstRecordID);
});
http://li3.me/docs/lithium/util/Collection::first
Short answer
Throw an exception inside the filter and catch it on the outside. You will probably have to collect the included items in an array yourself since you won't have access to find's return value.
Long answer
You are focusing too much on a particular tactic (stopping find using a filter) when it might do you some good to step back and consider what you are trying to accomplish.
It honestly sounds like you are trying to eat your cake and have it too: you want to be flexible and specify your search conditions in a function you can easily change, but you also want to be efficient and not pull more data out of the database than you have to.
The thing is, passing a filter function into find is already as inefficient as you can get it, because li3 will have to pull every record from the database before your filter is even called. That's where the inefficiency is. Stopping the filtering process once you hit 10 items or whatever won't make much of a difference (unless your filtering is also very expensive).
I would recommend thinking of the following:
Do you really need to allow any filter method at all? Is it possible to use declarative conditions? If so, you can supply limit options and let the database do all the work.
If you can't, consider using find to fetch a small batch of records and collect the ones you want to keep in an array. Repeat with another small batch until you've checked every item in the database or filled your array.

Categories