# Связывание через таблицу связи в PHP

Пусть теперь юзер был в разных городах. В этом случае таблица с юзерами могла бы иметь следующий вид:

users
id | name | city
--- | --- | ---
1 | user1 | city1, city2, city3
2 | user2 | city1, city2
3 | user3 | city2, city3
4 | user4 | city1

Понятно, что так хранить данные неправильно - города нужно вынести в отдельную таблицу. Вот она:

cities
id | name
--- | ---
1 | city1
2 | city2
3 | city3

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

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

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

Вот наша таблица связи:

users_cities
id | user_id | city_id
--- | --- | ---
1 | 1 | 1
2 | 1 | 2
3 | 1 | 3
4 | 2 | 1
5 | 2 | 2
6 | 3 | 2
7 | 3 | 3
8 | 4 | 1

Таблица с юзерами будет хранить только имена юзеров, без связей:

users
id | name
--- | ---
1 | user1
2 | user2
3 | user3
4 | user4
5 | user5

## Запросы

Давайте сделаем запрос, с помощью которого вытащим юзеров вместе с их городами. Для этого нам понадобится сделать два джоина: первый джоин присоединит к юзерам таблицу связи, а второй джоин по связям присоединит города:

`SELECT users.name as user_name, cities.name as city_name FROM users LEFT JOIN users_cities ON users_cities.user_id=users.id LEFT JOIN cities ON users_cities.city_id=cities.id`

## Результат запроса

Результат нашего запроса в PHP будет содержать имя каждого юзера столько раз, со скольки городами он связан:

`<?php $arr = [ ['user_name' => 'user1', 'city_name' => 'city1'], ['user_name' => 'user1', 'city_name' => 'city2'], ['user_name' => 'user1', 'city_name' => 'city3'], ['user_name' => 'user2', 'city_name' => 'city1'], ['user_name' => 'user2', 'city_name' => 'city2'], ['user_name' => 'user3', 'city_name' => 'city2'], ['user_name' => 'user3', 'city_name' => 'city3'], ['user_name' => 'user4', 'city_name' => 'city1'], ]; ?>`

Удобнее было бы переконвертировать такой массив и превратить его в следующий:

`<?php $res = [ ['user1' => ['city1', 'city2', 'city3']], ['user2' => ['city1', 'city2']], ['user3' => ['city2', 'city3']], ['user4' => ['city1']], ]; ?>`

Напишем код, выполняющий такую конвертацию:

`<?php $res = []; foreach ($data as $elem) { $res[$elem['user_name']][] = $elem['city_name']; } var_dump($res); ?>`

## Практические задачи

Пусть товар может принадлежать нескольким категориям. Распишите структуру хранения.

Напишите запрос, который достанет товары вместе с их категориями.

Выведите полученные данные в виде списка `ul` так, чтобы в каждой `li` вначале стояло имя продукта, а после двоеточия через запятую перечислялись категории этого продукта. Примерно так:

`<ul> <li>product1: category1, category2, category3</li> <li>product2: category1, category3</li> <li>product3: category1</li> </ul>`
←→
↑