Checking that element appears after another in a collection
Asked Answered
T

2

6

I have a collection returned from the database through a hasMany-relation.

$items = collect([
    [
        'ref' => 'efaef954',
        'children' => collect([
            [
                'ref' => 'wetk4',
                'order' => 1,
            ],
            [
                'ref' => 'wetk5',
                'order' => 2,
            ],
            [
                'ref' => 'wetk6',
                'order' => 3,
            ],
        ]),
    ],
    [
        'ref' => 'efgjlf954',
        'children' => collect([
            [
                'ref' => 'wetk5',
                'order' => 1,
            ],
            [
                'ref' => 'wetk6',
                'order' => 2,
            ],
            [
                'ref' => 'wetk4',
                'order' => 3,
            ],
        ]),
    ],
]);

This $items-collection can contain any number of items with children. These children has a specific order, which is random until they are sorted.

In my user interface I can input refs of the children to get parent items that qualify. Only parent-items which have the specific order of what I input e.g. wetk4 and wetk6 should be returned.

return $items->filter(fn ($item) => $item->children->contains('wetk4') && $item->children->contains('wetk6'))

This will correctly give me items with the children, but this does not take into account the fact that the order is important in which items would qualify, considering some items will have the same children.

I've yet to find an elegant solution to this, attempting to only use collection functions alone.

Tombstone answered 23/3, 2021 at 14:0 Comment(3)
Can you provide the desired output given the input is wetk4 and wetk6? (Q1) what is the desired output for wetk4 and wetk6?, (Q2) what is the desired output for wetk6 and then wetk4? (Q4) what is the desired output if you have a reference that doesn't exist. e.g. wetk4, wekt541 and wetk6?Croft
agree with @YahyaUddin , you need a new operation which is not clear, what it should done.Assurbanipal
The references are numbered by another column in a database, so wetk4 would in some cases have an order of for example 1, while wetk6 could in some cases have an order of for example 2 and vice versa. That could potentially be a way to make, preferably, an eloquent query.Tombstone
U
0

I think I would try to extend the laravel collections using a macro where you should implement your custom functionality. Afterwards that macro can be used on any laravel collection

More details here: https://laravel.com/docs/8.x/collections#extending-collections

Unobtrusive answered 23/3, 2021 at 14:27 Comment(1)
Stackoverflow is the place to find solutions not referencesRhizocarpous
D
0

I would probably use a macro here in conjunction with other collect functions. There is a mysql function called FIELD, which sounds similar to this. We can write a macro called FIELD.

use Illuminate\Support\Collection;

AppServiceProvider()
{
    public function boot()
    {
        Collection::macro('field', function ($key, array $order) {
            $ordering = collect();

            foreach($order as $searchValue) {
                $ordering = $ordering->concat($this->where($key,$searchValue));
            }

            $ordering = $ordering->concat($this->whereNotIn($key,$order));

            return $ordering;
        });
    }
}

From there you can use this macro to filter your results.

$ordering = ['wetk4','wetk5'];

return $items->filter(function($item) use($ordering){
    return count($item['children']->pluck('ref')->diffAssoc($item['children']->field('ref',$ordering)->pluck('ref'))) == 0;
});
Dendroid answered 15/4, 2021 at 20:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.