Cake PHP 3.x: Применение правил приложения к нескольким объектам - PullRequest
1 голос
/ 06 апреля 2020

Проблема

У меня есть проблема, связанная с тем, как наилучшим образом реализовать бизнес-правила для таблицы, которые должны применяться к сущностям, создаваемым со знанием друг друга. Из моих исследований до сих пор, я подозреваю, что это идет вразрез с внутренней работой Cake PHP, и вполне может быть еще одна особенность структуры, которую я пропустил, которая позволяет это.

Рассматриваемые сущности имеют ассоциацию hasMany, посредством которой сохраняются данные. Например, UsersTable и Questionnaires связаны через UsersQuestionnairesTable. Таким образом, я отмечаю, что buildRules метод UsersQuestionnairesTable запускается n раз, где n - количество создаваемых связанных сущностей.

Цель

Моя цель - применить правило построения, которое гарантирует, что одна (и только одна) из UsersQuestionnaire строк в данных запроса будет помечена как default: true, если другие UsersQuestionnairesTable записи существуют для пользователя.

Настоящий результат заключается в том, что при применении этого в UsersQuestionnairesTable::buildRules при попытке создать User с некоторыми Questionnaires, связанными с ним через UsersQuestionnairesTable, он пройдет проверку, только если первые данные строка полезной нагрузки, которую он выполняет в сущности, имеет default: true. Следовательно, он не работает для создания нескольких объектов, так как он потерпит неудачу для второй строки как default: false, таким образом, не создавая User.

Что я понимаю / попробовал

Как Я понимаю, что метод buildRules класса Table - это полезное место для описания правил логики приложений c, которые применяются к сущностям. Например, это электронное письмо является уникальным в базе данных.

С Cake PHP 3.x Кулинарная книга> Проверка данных> Применение правил приложения

Если проверка гарантирует правильность формы или синтаксиса ваших данных, правила направлены на сравнение данных с существующим состоянием вашего приложения и / или сети.

Эти типы правил часто называют «правилами домена» или «правилами приложения». Cake PHP раскрывает эту концепцию через «RulesCheckers», которые применяются до сохранения сущностей. Вот некоторые примеры правил домена:

  • Обеспечение уникальности электронной почты
  • Переходы между состояниями или шаги рабочего процесса (например, обновление статуса счета).
  • Предотвращение изменения софта удалено items.
  • Обеспечение ограничения использования / ограничения скорости.

Я хотел бы применить подобное правило к сущности во время создания, но со знанием других сущностей в запросе такие данные, что я могу получить доступ ко всем создаваемым объектам UsersQuestionnairesTable, чтобы проверить их значение deafult, и если ни один из них не будет признан true, произойдет сбой функции, и все объекты не будут созданы.

В настоящее время это условное правило, применяемое к каждому объекту в процессе создания, но перед сохранением (хотя и неверное) должно иллюстрировать желаемую конечную цель.

UsersQuestionnairesTable :

public function buildRules(RulesChecker $rules)
{
    $enforceFirstAsDefault = function ($entity) {
        $count = $this->find('all')
            ->where(['UserQuestionnaires.user_id' => $entity->user_id])
            ->andWhere(['Questionnaires.type_id' => 1])
            ->contain(['Questionnaires'])->count();

        if ($count == 0 && !$this->containsDefault($entity)) {
            return false;
        }

        return true;
    };

    $rules->add($enforceFirstAsDefault, [
        'errorField' => 'no_default_identified',
        'message' => 'A default questionnaire is required')
    ]);
}

...

private function containsDefault($entities): bool 
{
    foreach ($entities as $entity) {
        if ($entity->is_default) {
            return true;
        }
    }

    return false;
}

Из-за желания потерпеть неудачу перед созданием, buildRules на модели показалось наиболее подходящим местом для поиска этой логики c применять только к этой модели как:

  • Поведения больше подходят для общего поведения моделей
  • Хотя вы можете получить доступ к данным в beforeMarshal с помощью $event->getData(), я понимаю Метод больше подходит для манипулирования данными до сохранения и поэтому, скорее всего, не подходит для моих нужд.
  • Наличие этой функциональности во многих контроллерах, которые могут отвечать за создание UsersQuestionnaires записей, будь то напрямую или через ассоциации, чувствуется меньше DRY и SRP, так как для этого требуется Users::create (например), чтобы знать и действовать в зависимости от того, содержит ли строка в данных полезной нагрузки UsersQuestionnaires default: true, независимо от того, обернута ли она каким-либо помощником многократного использования.

Вопрос

Есть ли что-то, что мне не хватает в применении buildRules, которое позволит проверять все сущности, которые будут или были упорядочены как часть этого запроса, так что валидация завершится ошибкой или пройдет только после создания всех сущностей ?

Возможно, способ переопределить / перегрузить buildRules с дополнительным контекстом запроса? Или этот вид бизнес-логики c лучше подходит в другом месте или использует другую функцию фреймворка?

1 Ответ

1 голос
/ 06 апреля 2020

Ваши функции правил могут принимать второй параметр, который получает параметры, переданные функции save. Итак, в вашем контроллере

$this->UsersQuestionnaires->saveMany($entities, ['entities' => $entities]);

А затем в вашей таблице:

$enforceFirstAsDefault = function ($entity, $options) {
    // Use $options['entities'] here to access the set of entities being saved
}
...