PHP Profi

GroupBy по нескольким значениям в Laravel Перевод

php Laravel collection groupBy

В Laravel начиная с версии 5.5.29 можно группировать коллекции по нескольким критериям. Давайте посмотрим, что это означает и как это работает.

Подготовка

Итак, эта статья о новой функциональности в фреймворке Laravel. Но прежде чем мы посмотрим как она работает сейчас, давайте посмотрим как она работала раньше. Метод groupBy является методом класса Collection. Для наших примеров я создам немного данных, с которыми мы будем работать. Students будет фабрикой состояний для передаваемого класса User.

// Default user factory which comes with Laravel
$factory->define(App\User::class, function (Faker $faker) {
    return [
        'name' => $faker->name,
        'email' => $faker->unique()->safeEmail,
        'password' => '$2y$10$TKh8H1.PfQx37YgCzwiKb.KjNyWgaHb9cbcoQgdIVFlYg7B77UdFm', // secret
        'remember_token' => str_random(10),
    ];
});

// Our new students state
$factory->state(App\User::class, 'students', function (Faker $faker) {
    return [
        'skilllevel' => collect(['beginner', 'intermediate', 'professional'])->random(),
        'teacher' => collect(['Peter', 'Markus', 'Chris'])->random(),
    ];
});

Добавленное состояние будет генерить для нас данные пользователей. У нас есть новые поля skilllevel и teacher. Для наших примеров мы будем использовать простой роутинг с обычным callback'ом. Таким образом, мы можем быстро и легко вернуть результат в браузер.

Route::get('/', function () {

    return $students = factory(User::class)
        ->times(3)
        ->states('students')
        ->make();

});

Примечание: мы используйте метод make вместо метода create, потому что у нас нет базы данных.

Этот код "накастует" нам тестовых данных, которые будут выглядит примерно так:

[
	{
		"name": "Jakayla Leffler",
		"email": "ocie70@example.com",
		"skilllevel": "professional",
		"teacher": "Peter"
	},
	{
		"name": "Gustave Cummings II",
		"email": "crona.alexandrea@example.net",
		"skilllevel": "intermediate",
		"teacher": "Markus"
	},
	{
		"name": "Ms. Ethelyn Bergnaum MD",
		"email": "deckow.kelvin@example.net",
		"skilllevel": "beginner",
		"teacher": "Peter"
	}
]

Простой пример

Я сказал "будут выглядит примерно так", потому что мы используем пакет Faker в нашей фабрике. Поэтому каждый результат будет выглядеть по-разному в силу того, что он генерирует случайные данные.

Далее, давайте используем метод groupBy, чтобы сгруппировать наши данные по skilllevel:

return $students->groupBy('skilllevel');

Вы увидите новые ключи для skilllevel в нашем результате:

{
	"professional": [
		{
			"name": "Jacquelyn Kilback",
			"email": "christopher55@example.net",
			"skilllevel": "professional",
			"teacher": "Chris"
		}
	],
	"beginner": [
		{
			"name": "Miss Ophelia Ryan Jr.",
			"email": "pollich.tristin@example.net",
			"skilllevel": "beginner",
			"teacher": "Chris"
		},
		{
			"name": "Furman Hahn",
			"email": "blowe@example.net",
			"skilllevel": "beginner",
			"teacher": "Markus"
		}
	]
}

Новый функционал в ::groupBy()

Пока здесь нет ничего действительно нового. Так что же это за новая функция, о которой я говорил? Patrizio T. сделал pull-запрос, так что теперь вы можете группировать коллекции на нескольких уровнях. Чтобы лучше понять, что это значит, давайте взглянем на пример:

return $students->groupBy(['skilllevel','teacher']);

Вместо строки, мы передаем массив, чтобы задать несколько уровней. Сначала коллекция students должна быть сгруппирована по skilllevel, а затем по полю teacher. Итак, вот что мы получили:

{
	"intermediate": {
		"Peter": [
			{
				"name": "Jana McClure III",
				"email": "oliver.pagac@example.com",
				"skilllevel": "intermediate",
				"teacher": "Peter"
			}
		],
		"Chris": [
			{
				"name": "Rosemarie Barrows",
				"email": "epurdy@example.com",
				"skilllevel": "intermediate",
				"teacher": "Chris"
			}
		]
	},
	"professional": {
		"Markus": [
			{
				"name": "Katrine Streich",
				"email": "carlee.koepp@example.com",
				"skilllevel": "professional",
				"teacher": "Markus"
			}
		]
	}
}

Эта группировка может быть полезна, когда вы хотите отобразить или сравнить данные. В этом примере только Маркус имеет профессионального студента. Может быть он является лучшим учителем?

Немного безбашенный пример

Это не имеет смысла для нашего примера, но мы также могли бы группировать студентов по их имени и адресу электронной почты:

return $students->groupBy(['skilllevel','teacher', 'name', 'email']);

Получится "немного" сумасшедшая вложенная структура, но это возможно smiley :

{
	"professional": {
		"Peter": {
			"Mrs. Ella McClure": {
				"forest.bernier@example.com": [
					{
						"name": "Mrs. Ella McClure",
						"email": "forest.bernier@example.com",
						"skilllevel": "professional",
						"teacher": "Peter"
					}
				]
			}
		},
		"Chris": {
			"Miss Assunta Predovic PhD": {
				"amari.klocko@example.com": [
					{
						"name": "Miss Assunta Predovic PhD",
						"email": "amari.klocko@example.com",
						"skilllevel": "professional",
						"teacher": "Chris"
					}
				]
			}
		}
	},
	"intermediate": {
		"Markus": {
			"Keshawn Crona DVM": {
				"vkilback@example.org": [
					{
						"name": "Keshawn Crona DVM",
						"email": "vkilback@example.org",
						"skilllevel": "intermediate",
						"teacher": "Markus"
					}
				]
			}
		}
	}
}

Заключение

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

2018-02-05 alek13 оригинал

Последние посты

Комментарии

авторизуйтесь или зарегистрируйтесь, чтобы оставить комментарий