Sort collection in alphabetic order - php

I'm trying to print my collection sorted alphabeticall. Here's what I've tried inside my controller:
public function listForCategories(Category $category)
{
return $category->subcategories->sortBy('title');
}
But It's not sorting my output :/ Please help!

$category->subcategories->sortBy('title')->values()->all();
I don't know exact hierarchy but you can use the solution as per your needs:
The sortBy method sorts the collection by the given key. The sorted collection keeps the original array keys,
so in this example, we'll use the values method to reset the keys to consecutively numbered indexes:
Here is an example :
$category = collect([
['title' => 'Desk', 'price' => 200],
['title' => 'Chair', 'price' => 100],
['title' => 'Bookcase', 'price' => 150],
]);
$sorted = $category->sortBy('title')->values()->all();
Result-:
[
['title' => 'Bookcase', 'price' => 150],
['title' => 'Chair', 'price' => 100],
['title' => 'Desk', 'price' => 200],
]

try return $category->subcategories->orderBy('title');

The sortBy method sorts the internal fields, however, it preserves the original keys, therefore, if you want to have the sorted values, you should call the values() method after you've sorted the collection. That way you get the sorted collection back.
return $category->subcategories->sortBy('title')->values()->all();

Try using orderBy when you retrieve them from the database (I'm assuming you do)
public function listForCategories(Category $category)
{
return $category->subcategories()->orderBy('title')->get();
}

Related

Collection query

I have a collection which contains these values
'sales marketing|telemarketing',
what I'm trying to do is query/filter the items in collection but just based on the individual type so the for example value of 'telemarketing'. I have tried
$results = $data->where('Department', 'contains', $type); and also tried LIKE but because of the format with the pipe it's not picking the type/value.
This might be a dumb question but any ideas would be great!
The where-method also can handle only two Parameters. For example:
$data= collect([
['Department' => 'sales', 'price' => 200],
['Department' => 'marketing', 'price' => 100],
['Department' => 'telemarketing', 'price' => 150],
['Department' => 'marketing', 'price' => 100],
]);
$departmentName = "marketing";
$results = $data->where('Department', $departmentName);
dd($results);
Given your example:
[
"Employee" => "Some Company",
"Name" => "John Something",
"Usages" => "sales marketing|telemarketing",
"StartDate" => "1st Mar 2021",
"EndDate" => ""
]
The main issue is that the "Usage" property is a string containing multiple values, with the pipe character acting as a separator.
One solution to filter by one of those values is by mapping your original collection to transform the string in an array with the explode method and then use the filter method to filter based on the Usages you're interested in.
The resulting code might look like this:
$mappedCollection = $collection->map(function($el) {
$el['Usages'] = explode('|', $el['Usages']); // Transform the string into an array
return $el;
});
$result = $mappedCollection->filter(function($el) {
return in_array('sales marketing',$el['Usages']); // Change 'sales marketing' with the desired Usage
});

Create array of key => value thanks to "helper" functions

I have an 2 dimensional array with this values :
[
'id' => 12,
'title' => 'the title', //and a few other key => value
],
[
'id' => 13,
'title' => 'the title 13', // and a few other key => value
],...
In the end, I need to have a multidimensional array only with id and title
[ $item['id'] => $item['title'], ...]
Usually, I'm doing a simple foreach to achieve this, but I want to use php function now. I've done this, but is there a proper way to do this?
$list = array_combine(array_column($list_forms, 'id'), array_column($list_forms, 'title'));
With third argumenf of array_column it is:
$list = array_column($list_forms, 'title', 'id');

Eloquent recursive relation

I have an issue where I'm trying to get all descendants of an object and keep only those with a specific property.
I have these relations:
public function getChildren()
{
return $this->hasMany(self::class, 'parent_id', 'id');
}
public function allChildren()
{
return $this->getChildren()->with('allChildren');
}
And I get this type of array for example:
$array = [
0 => ['name' => 'aaa', 'type' => 0, 'parent' => null, 'children' => [
1 => ['name' => 'bbb', 'type' => 1, 'parent' => null, 'children' => []],
2 => ['name' => 'ccc', 'type' => 0, 'parent' => null, 'children' => [
3 => ['name' => 'ddd', 'type' => 1, 'parent' => 2, 'children' => []]
]]
]],
4 => ['name' => 'eee', 'type' => 0, 'parent' => null, 'children' => []]
];
For this example, I would like to remove all objects that are of type 1 and get a clean array without those only.
I don't really understand why it is possible to get all descendats of an object but not be able to pass conditions.
Thanks in advance.
A collection only solution would be something like this (place the custom macro in a Service Provider of your application):
Collection::macro('whereDeep', function ($column, $operator, $value, $nested) {
return $this->where($column, $operator, $value)->map(function ($x) use ($column, $operator, $value, $nested) {
return $x->put($nested, $x->get($nested)->whereDeep($column, $operator, $value, $nested));
});
});
Then where needed call:
$yourArray->whereDeep('type', '!=', 1, 'children');
On your example, the macro works like this:
Filter all the elements where: type != 1
(the outer array will beuntouched as both items has type => 0)
For each element of the current array:
Retrive the children property and apply the same filtering to this subarray starting with the first point of this instructions.
Replace the children property with the new children property just filtered.
Anyways, you should try to deep dive into why the relation filtering doesn't work. That solution would be more efficient if optimized correctly.
I found a great solution where there is no need of all this recursion or any of these relationship calls so I share it:
Using: "gazsp/baum"
// get your object with roots method
$contents = Content::roots()->get();
// and simply run through the object and get whatever you need
// thanks to getDescendantsAndSelf method
$myArray = [];
foreach($contents as $content) {
$myArray[] = $content->getDescendantsAndSelf()->where('type', '!=', 1)->toHierarchy();
}
return $myArray;
This works for me the same way as the other method above.

Laravel sync Relation with optional parameters

I use the sync function for syncing a belongsToMany Relation:
$model->products()->sync($productIds);
In the $productIds array there is flat array with some Id's -
something like this:
$productIds = [1,3,5,6];
What I want:
The pivot table has also additional columns like "created_by" and "updated_by".
But how can I add these fields to my array WITHOUT doing a foreach loop?
Is there a shorter way to do this?
I need an array like this:
$productIds = [1 => [
'created_by' => 1,
'updated_by' => 1
],3 => [
'created_by' => 1,
'updated_by' => 1
],5 => [
'created_by' => 1,
'updated_by' => 1
],6 => [
'created_by' => 1,
'updated_by' => 1
]];
Yes I know I can do it with foreach and add the columns while I loop through the array. But I want do it shorter.. is there a way to do it shorter (perhaps with laravel)?
It should be enough to pass what you have set in $productIds in your code example to sync().
This method works not only with array of integers. You can also pass an array where key is the synced ID and value is the array of pivot attributes that should be set for given ID.
This should do the trick:
$productIds = [
1 => [
'created_by' => 1,
'updated_by' => 1
]
//rest of array
];
$model->products()->sync($productIds);
Just make sure you have defined those fields as pivot fields in your relation definition.
In order to generate such table based on a list of IDs in $productIds you can do the following:
$productIds = array_fill_keys($productIds, array(
'created_by' => 1,
'updated_by' => 1,
));

How to make associative array using PHP for loop to use in Yii 2 array map()?

I would like to make an associative array using PHP for loop to use in Yii2 map() method.
The array will look like in bellow format-
$listArray = [
['id' => '1', 'name' => 'Peter/5'],
['id' => '2', 'name' => 'John/7'],
['id' => '3', 'name' => 'Kamel/9'],
];
The id and name will be changed through each iteration of the loop. Here, the name will always hold customized value after some calculation inside the loop.
Finally, the list will be used in map() method like as following
$listData=ArrayHelper::map($listArray,'id','name');
I can use map() method directly after using the Active Record to find the list array and then use that in map() method. But it does not a give me way to use custom value for the name attribute.
$listArray = UserList::find()
->where(['status' => 1])
->orderBy('name')
->all();
$listData=ArrayHelper::map($listArray,'id','name');
How can achieve this? Direct source code example would be really great for me.
Thanks in advance.
I'm assuming you want to query an ActiveRecord for data then transfer the data into a simple array.
$listData = [];
$listArray = UserList::find()
->where(['status' => 1])
->orderBy('name')
->all();
foreach($listArray as $user){
$customName = $user->name . $this->someCalculation();
$listData[] = ["id" => $user->id, "name" => $customName];
}
Or you could use the ArrayHelper class like this:
$listArray = UserList::find()
->where(['status' => 1])
->orderBy('name')
->all();
$listData = ArrayHelper::toArray($listArray , [
'app\models\UserList' => [
'id',
'name' => function ($listArray ) {
return $listArray->word . strlen($listArray->word); // custom code here
},
],
]);
I think the preferred way of doing this by defining custom calculation rule in UserList model as:
public function getCustomRuleForUser(){
// Do what ever you want to do with your user name.
return $this->name.'Your custom rule for name';
}
And use as:
$userList = UserList::find()->all();
$listData=ArrayHelper::map($userList,'id','customRuleForUser');
Now, you have your custom rule for username list in $listData.
$model_userprofile = UserProfile::find()->where(['user_id' => Yii::$app->user->id])->one();
$model_userprofile1 = UserProfile::find()
->select('user_id')
->where(['group_id' => $model_userprofile->group_id])->all();
$listData = [];
foreach($model_userprofile1 as $user){
$id = $user->user_id;
$listData[] = ["id" => $id];
}
$dataProvider = new ActiveDataProvider
([
'query' => User::find()
->select('id,username,email')
->Where(['id' => $listData])
->orderBy(['id' => SORT_DESC]),
'pagination' => ['pagesize' => 15]]);
return $this->render('index',['dataProvider'=> $dataProvider]);

Categories