Я придумав таке рішення. Він працює надійно з останньою Symfony 2.4 .
Я спробую дати кілька пояснень.
Використання окремого валідатора
Я думаю, що погана ідея використовувати окрему перевірку для перевірки сутності та повернення повідомлень про порушення обмежень, як це пропонують інші автори.
Вам потрібно буде вручну перевірити всі сутності, вказати групи перевірки тощо. Складні ієрархічні форми взагалі не практичні і швидко вийдуть з рук.
Таким чином ви будете перевіряти форму двічі: один раз з формою та один раз з окремим валідатором. Це погана ідея з точки зору продуктивності.
Я пропоную рекурсивно повторювати тип форми разом із дітьми, щоб збирати повідомлення про помилки.
Використання деяких запропонованих методів з ексклюзивним оператором IF
Деякі відповіді, запропоновані іншими авторами, містять взаємовиключні твердження IF на зразок цього: if ($form->count() > 0)
або if ($form->hasChildren())
.
Наскільки я бачу, кожна форма може мати помилки, як і діти. Я не знаю компонента Symfony Forms , але на практиці ви не отримаєте помилок самої форми, як, наприклад, помилка захисту CSRF або додаткові поля . Я пропоную зняти це розділення.
Використання денормалізованої структури результатів
Деякі автори пропонують розмістити всі помилки у простому масиві. Таким чином, всі повідомлення про помилки самої форми та її дітей будуть додані до одного масиву з різними стратегіями індексації: на основі чисельності для власних помилок типу та на основі імен для помилок дітей. Я пропоную використовувати нормовану структуру даних форми:
errors:
- "Self error"
- "Another self error"
children
- "some_child":
errors:
- "Children error"
- "Another children error"
children
- "deeper_child":
errors:
- "Children error"
- "Another children error"
- "another_child":
errors:
- "Children error"
- "Another children error"
Таким чином результат можна легко повторити пізніше.
Моє рішення
Тож ось моє рішення цієї проблеми:
use Symfony\Component\Form\Form;
/**
* @param Form $form
* @return array
*/
protected function getFormErrors(Form $form)
{
$result = [];
// No need for further processing if form is valid.
if ($form->isValid()) {
return $result;
}
// Looking for own errors.
$errors = $form->getErrors();
if (count($errors)) {
$result['errors'] = [];
foreach ($errors as $error) {
$result['errors'][] = $error->getMessage();
}
}
// Looking for invalid children and collecting errors recursively.
if ($form->count()) {
$childErrors = [];
foreach ($form->all() as $child) {
if (!$child->isValid()) {
$childErrors[$child->getName()] = $this->getFormErrors($child);
}
}
if (count($childErrors)) {
$result['children'] = $childErrors;
}
}
return $result;
}
Я сподіваюся, що це комусь допоможе.