Laravel lists function prepend value - php

Laravel lists function used to return an array so I could prepend a value. However it now is an object. What I would like to do is generate a list for a dropdown but add an extra value to the front that says something like:
['select a value.', '0']
How should I prepend data to the new Laravel lists function?

lists() returns a Collection object. To add an item to the beginning of the collection, you can use the prepend method:
$statusCollection = \App\Status::lists('name', 'id');
$statusCollection->prepend('select a value', 0);
Make sure you pass in a non-null key as the second parameter to prepend, otherwise this method will end up renumbering your numeric keys. If you don't provide a key, or pass in null, the underlying logic will use array_shift, which will renumber the keys. If you do provide a key, it uses an array union (+), which should preserve the keys.
For another option, you can get the underlying item array using the all() method and just do what you did before:
$statusCollection = \App\Status::lists('name', 'id');
$statusArray = $statusCollection->all();
// if you want to renumber the keys, use array_shift
array_unshift($statusArray, 'select a value');
// if you want to preserve the keys, use an array union
$statusArray = [0 => 'select a value'] + $statusArray;

If you are ok with the numeric keys being reindexed, then the accepted answer of using array_unshift() works. If you want to maintain the original numeric keys (for example, if the keys correspond to the id of your table entries), then you could do as follows:
$statusCollection = \App\Status::lists('name', 'id');
$statusArray = $statusCollection->all();
$finalArray = array('0' => 'Select a value') + $statusArray;

Related

Filtering collection of key/value pairs. How can I access the key?

I am filtering through a collection of key/value pairs. While I am filtering, how can I access the key?
Keys are:
title
body
active
button
button-2
How can I return fields whose key starts with "button"?
In this case, I would only like to get the button and button-2 field.
$fields = (stuff in picture)
// Pseudocode of what I'm trying to do
$button_fields = collect($fields)->filter(function($field){
// I imagine getting the key should be something like this?
if($field->key->beginsWith('button')) {
return;
}
});
On most collection methods the second parameter is the $key. This can be done, because you loop over an associative array, therefor the key is not indexed but a value. Secondly strings in PHP does not have methods, there for you should use the Str helper from Laravel, which takes two parameters the haystack first and the needle secondly.
$buttonFields = collect($fields)->filter(function($field, $key){
if(Str::startsWith($key, 'button')) {
return;
}
});

sortBy returns object instead of array

I have this code
$list = Elements::where('list_id', $id)->with('visitors')->get()->sortBy(function($t)
{
return $t->visitors->count();
});
return json_encode($list);
This code returns object, not array. How I can change it?
You should add ->values() if you want an actual JSON array in the end.
As you might add other manipulations like filters and transforms, I'd call ->values() at the very last moment:
return json_encode($list->values());
The reason for using ->values() over other options is that it resets the array keys. If you try returning some associative array (like ['name' => 'Roman'] or even [1 => 'item', 0 => 'other']), it will always get encoded as an object. You need to have a plain array (with sequential integer keys starting at 0) to avoid unexpected things that filtering and sorting will do.
You just need to call the ->all() Collection method, so
$list = Elements::where('list_id', $id)->with('visitors')->get()->sortBy(function($t)
{
return $t->visitors->count();
}
)->all();
this differs to the ->toArray() method because it will also cast to array also the object inside the collection, and not only the colletion itself (actually ->all() won't cast anything, it will just return the elements inside the collection)
$list = Elements::where('list_id', $id)->with('visitors')->get();;
This code return Collection Instance. $collection->sortBy(...); also is Collection instance. For get array in Collection you must be use or ->toArray(), or ->all()
In your case you can use
$list = Elements::where('list_id', $id)->with('visitors')->get()->sortBy(function($t) {
return $t->visitors->count();
})->toArray();

Laravel's array_sort helper DESC e ASC

I want to sort a multidimensionl array by one or more keys using the Laravel helper array_sort.
array(
array('firstname_1','lastname_1'),
array('firstname_2','lastnmae_2')
)
I want to order it first by firstname and then by lastname.
I also want to do this in DESC or ASC order. How can I achieve this?
There are functions aivalable in the internet to do this but I would like to understand how to use the Laravel helper. The doc for array_sort (http://laravel.com/docs/helpers#arrays) I don't find comprehensive.
The array_sort() helper function is a very thin wrapper around the default Illuminate\Support\Collection::sortBy() method. Excluding comments, this is all that it does:
function array_sort($array, Closure $callback)
{
return \Illuminate\Support\Collection::make($array)->sortBy($callback)->all();
}
While handy, it is limiting in its sorting capabilities. Similarly, the Collection class will allow you to change sort direction, but not much else.
In my opinion, you have two options:
Skip a Laravel-only solution and use some normal PHP and array_multisort(). As #Jon commented, there's some great details in this SO question.
Use a combination of grouping and sorting in a Collection object to achieve the results you want.
I'd just stick with #1.
Just as an example how to sort by first name and then by last name with the sort helper of Laravel.
First define some more example data:
$array = array(
array('firstname_1','lastname_1'),
array('firstname_2','lastname_3'),
array('firstname_2','lastname_2'),
array('firstname_3','lastname_3'),
);
In our closure we want to sort by first name first, and then by last name. Laravel will sort by the returned values of the closure. So in your case the trick is to concatenate both strings:
$array = array_sort($array, function($value) {
return sprintf('%s,%s', $value[0], $value[1]);
});
Internally Laravel will now sort the contents of this intermediate array:
$intermediateArray = array(
'firstname_1,lastname_1',
'firstname_2,lastname_3',
'firstname_2,lastname_2',
'firstname_3,lastname_3',
);
This will result in an array which is sorted by first name and than by last name in ascending order.
To use descending order you need first sort the array and than reverse it:
$array = array_reverse(array_sort($array, function($value) {
return sprintf('%s,%s', $value[0], $value[1]);
}));

Reference an arrays key in its value

I know this seems like something that should be averted by design, but let's just say it is bitterly needed:
Is it possible to reference the key belonging to a value while it is being initialized?
Here is what I imagine it to be (not exactly the case in which I need it, but the key is primitive as well):
$array = array(25 => "My key is " . $this->key);
I need this because the array key is used in each value. Actually the value is another array which has a value in which the first array key is used. Like I said in the comments, I want to keep it DRY. Doing it is no problem, but I want to do it good ;)
If you are writing an array yourself you can just put key value to array value like:
$array = array(25 => "My key is 25");
If you are have an array already you can use a foreach and add all keys to it's values:
foreach($array as $key => $value) {
$array[$key] = sprintf('%s %s', $value, $key);
}
Or if you just want to have an array of keys of existing array you can use either array_flip if you want to maintain key=>value, but have keys and values flipped. Or you can use array_keys if you want just an array of keys.
To make what you want: initialize an array somewhere and do not add any keys to it's value you can implement ArrayAccess, Countable and have:
public function offsetGet($offset) {
return isset($this->container[$offset])
? $this->container[$offset] . ' ' . $offset
: null;
}
or something like this. But in this case you need to have a variable that contains this array to be an instance of your ArrayAccess implementation. And depending of usage of this class you probably will need to implement more interfaces.
No, there is no way to reference the key when defining the value. Except maybe writing a preprocessor that embeds it in the string. But that would only work for primitive values.

Use object property as array key

I have a PHP array of objects, say with two properties a and b. So for example I can do
$arr['a1']->a = $z;
$x = $arr['a1']->b;
The array is currently using the value of each object's a property as the array key, e.g.
$arr['a1']->a == 'a1'
This is so I can quickly look up the object by that property. I now need to quickly look up by b, and so want to switch the keys from being set to property a to being set to b (both are unique).
Is there an easy way to do this? In-place or into another array are both fine.
foreach($arr as $key => $object)
{
$arr2[$object->b] = $object;
}
This will create a new array that points to the same objects.
If you want them in one array, you can do as Joost suggested in the comments ($arr[$object->b] = $object; in the loop instead). However, that will only work if there are no duplicate keys between the two sets.

Categories