Может войдёшь?
Черновики Написать статью Профиль

Сводные таблицы или сводные модели

перевод

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

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

days:
    date
    temperature
    # больше информации
routes:
    gis_points
    public
    distance
    title
    # больше полей
day_route: # это будет наша сводная (pivot) таблица многие-ко-многим
    day_id
    routes_id
    laps

Это работает, но все станет более странным, когда вы захотите вычислить общую дистанцию за день. Что ж, вы можете сделать что-нибудь подобное (реализация на псевдо-PHP, используя Eloquent):

PHP
public function getTotalDistanceAttribute()
{
    
// Создает ассоциативный массив, в котором каждый $lap => $distance
    
$routes $this->routes()->list('laps''distance');
    
$total 0;
    foreach(
$routes as $laps => $distance) {
        
$total += ($laps $distance);
    }
    return 
$total;
}

Это работает, но похоже что PHPDay немного больше чем нужно. Например, что будет, если я захочу узнать общую дистанцию за день на одном из маршрутов? Вы можете добавить пользовательские методы доступа (accessors), но куда вы поместите эту логику? В модель маршрута? В пользовательскую службу (service)? Это кажется совсем странным.

У нас уже есть сводная таблица, и мы хотим применить логику к этой таблице, так не должно ли это быть частью модели? Рассмотрим такую стректуру БД вместо прежней:

days:
    date
    temperature
    # больше информации
routes:
    gis_points
    public
    distance
    title
    # больше полей
runs: # это была наша таблица day_route
    day_id
    routes_id
    lap_distance
    laps

Как вы видите, модель PHPRun — это просто переименованная сводная таблица с той же самой информацией! Теперь PHPRun будет знать свою общую дистанцию, которая действительно легкодоступна! И что еще лучше, наш метод доступа PHPtotalDistance тоже выигрывает от этого.

PHP
public function getTotalDistanceAttribute()
{
    
$sum 0;
    
$this->runs->each(function($run) use(&$sum) {
        
$sum += $run->distance;
    });
    return 
$sum;
}

На мой взгляд, это намного понятнее. PHPDay не должен заботиться о том, как посчитать дистанцию по конкретному маршруту за день, он просто знает, как суммировать расстояния. Теперь PHPRun готов заботиться обо всей его логике и в то же время сохранять дистанцию по маршруту, когда ему это потребуется (что, если пользователь позднее изменит маршрут, тогда все дистанции прошедших дней будут испорчены).

На этой неделе мы рассмотрим похожие решения и увидим, как они помогают нам повсюду, не только сэкономив нам одну строчку в функции PHPgetTotalDistanceAttribute.

Как вы считаете, полезен ли этот материал? Да Нет

Написать комментарий

Разметка: ? ?

Авторизуйся, чтобы прокомментировать.