Проблема
У меня есть проблема, связанная с тем, как наилучшим образом реализовать бизнес-правила для таблицы, которые должны применяться к сущностям, создаваемым со знанием друг друга. Из моих исследований до сих пор, я подозреваю, что это идет вразрез с внутренней работой 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 лучше подходит в другом месте или использует другую функцию фреймворка?