Трюки с коллекциями в laravel

10 June 2015
#Laravel#Collections

Коллекции бывают очень полезными но о них часто забывают. В этой статье я дам несколько советов по их применению.

Вольный перевод. Оригинальная статья http://codebyjeff.com/blog/2015/05/stupid-collection-tricks-in-laravel

Внимание:

Это не страница "лучшей практики", я всего лишь дам несколько советов которые могут быть полезны в нужном месте кода.

Начнём с того, что создадим таблицу people и пустой класс Eloquent модели с именем Person:

    CREATE TABLE `people` (
            `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
            `first_name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
            `last_name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
            `type` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
            PRIMARY KEY (`id`)
    ) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
    
    INSERT INTO `people` (`id`, `first_name`, `last_name`, `type`) VALUES
            (1, 'Jeff', 'Madsen', 'programmer'),
            (2, 'Mickey', 'Mouse', 'engineer'),
            (3, 'Daffy', 'Duck', 'critic'),
            (4, 'Mighty', 'Mouse', 'programmer');	

Трюк #1: find()

Что? find? Да я давно всё знаю о нём. Серьёзно? Проверим?

     // Возвратит одну строку как Коллекцию
    $collection = App\People::find([1]);
    dd($collection);
    

    // Возвратит несколько строк как Коллекции
    $collection = App\Person::find([1, 2, 3]);
    dd($collection);

С помощью коллекций иногда действительно приятней работать, мы всегда знаем, что возвращается коллекция.

Трюк #2: $collection->where()

Сколько запросов к базе данных вы бы произвели, что бы получить в отдельном массиве всех программистов, инженеров и критиков? Хотите сказать три? Да ни за что в жизни! Один!

    // Получаем всех
    $collection = App\Person::all();
    
    // фильтруем
    $programmers =  $collection->where('type', 'programmer');
    $critic =  $collection->where('type', 'critic');
    $engineer =  $collection->where('type', 'engineer');
    
    dd($engineer);	

Трюк #3: where() & lists()

Возвратит массив с именами всех инженеров

Внимание:

lists в Laravel 5.2 был переименован в pluck

    $collection = App\Person::all();
    
    $engineer =  $collection->where('type', 'engineer')->lists('first_name'); // ->pluck('first_name') для laravel старше  5.1
    dd($engineer);

В WP вы вероятно сделали бы что-то вроде этого:

Внимание:

следующий код написан по памяти и не проверен

    // Получаем все метаданные для пользователя с ID  = 1
    $collection = App\WP_Meta::whereUserId(1)->get();
    
    // Мне нужны значения имени и фамилии
    $first_name =  $collection->where('meta_key', 'first_name')->lists('value')[0];	
    $last_name  =  $collection->where('meta_key', 'last_name')->lists('value')[0];
    ...любые другие поля, которые вам нужны

Трюк #4: $collection->implode()

Полезный метод (аналогичен php implode), объединит в строку указанный атрибут коллекции с нужным разделителем

    $collection = App\Person::all();
    $names = $collection->implode('first_name', ',');
    echo $names;

Трюк #5: $collection->groupBy()

Мне вас жаль, если вы делали отчёты и не знали этого...

    $collection = App\Person::all();
    $grouped = $collection->groupBy('type');
    dd($grouped);	
    
    // Результат
    Collection {#152 ▼
      #items: array:3 [▼
        "programmer" => array:2 [0 => Person {#166 ▶}
          1 => Person {#169 ▶}
        ]
        "engineer" => array:1 [0 => Person {#167 ▶}
        ]
        "critic" => array:1 [0 => Person {#168 ▶}
        ]
      ]
    }

Трюк #6: Объединение

Несколько слов о коде. В примере мы будем использовать одну модель, но на самом деле предполагается это использовать для разных моделей.

    use Illuminate\Support\Collection;
    
    ...
    
    // Задача в том, что бы объединить результат из различных моделей	
    $programmers =  \App\Person::where('type', 'programmer')->get();
    $critic      =  \App\Person::where('type', 'critic')->get();
    $engineer    =  \App\Person::where('type', 'engineer')->get();
    
    $collection  = new Collection;
    $all = $collection->merge($programmers)->merge($critic)->merge($engineer);
    dd($all);

Теперь предостережения: Будьте осторожны с выбором что делать с результатом. Если вы будете делать циклы при сочетании экземпляров различных классов, то вас могут ожидать сюрпризы, так как некоторые поля данных не всегда могут присутствовать, или могут быть мутаторы в одной из моделей, либо и то и другое вместе. Причём сегодня это может работать нормально, а завтра кто-то придёт и добавит мутатор в модель. По этому прежде всего хорошенько рассчитайте всё.

Надеюсь, что статья Вам помогла!