Проверка формы Symfony2 исчерпала память

У меня сложная форма со многими полями выбора сущностей. Когда я не использую валидацию, добавить / изменить можно. Но когда я включаю проверку формы в /config/validation.yml, я больше не могу добавлять / редактировать.
Я проверил файлы лога php и увидел ошибку:

PHP Fatal error:  Allowed memory size of 536870912 bytes exhausted (tried to allocate 32 bytes) in ..\example.com\vendor\doctrine\dbal\lib\Doctrine\DBAL\Connection.php on line 694
PHP Stack trace:
PHP   1. {main}() ..\example.com\web\app_dev.php:0
PHP   2. Symfony\Component\HttpKernel\Kernel->handle() ..\example.com\web\app_dev.php:29
PHP   3. Symfony\Component\HttpKernel\DependencyInjection\ContainerAwareHttpKernel->handle() ..\example.com\var\bootstrap.php.cache:2377
PHP   4. Symfony\Component\HttpKernel\HttpKernel->handle() ..\example.com\var\bootstrap.php.cache:3133
PHP   5. Symfony\Component\HttpKernel\HttpKernel->handleRaw() ..\example.com\var\bootstrap.php.cache:2984
PHP   6. call_user_func_array:{..\example.com\var\bootstrap.php.cache:3022}() ..\example.com\var\bootstrap.php.cache:3022
PHP   7. DefaultBundle\Controller\PropertyHouseController->createAction() ..\example.com\var\bootstrap.php.cache:3022
PHP   8. Symfony\Component\Form\Form->createView() ..\example.com\src\DefaultBundle\Controller\PropertyHouseController.php:86
PHP   9. Symfony\Component\Form\Form->createView() ..\example.com\vendor\symfony\symfony\src\Symfony\Component\Form\Form.php:1061
PHP  10. Symfony\Component\Form\Extension\DataCollector\Proxy\ResolvedTypeDataCollectorProxy->buildView() ..\example.com\vendor\symfony\symfony\src\Symfony\Component\Form\Form.php:1058
PHP  11. Symfony\Component\Form\ResolvedFormType->buildView() ..\example.com\vendor\symfony\symfony\src\Symfony\Component\Form\Extension\DataCollector\Proxy\ResolvedTypeDataCollectorProxy.php:111
PHP  12. Symfony\Component\Form\Extension\DataCollector\Proxy\ResolvedTypeDataCollectorProxy->buildView() ..\example.com\vendor\symfony\symfony\src\Symfony\Component\Form\ResolvedFormType.php:159
PHP  13. Symfony\Component\Form\ResolvedFormType->buildView() ..\example.com\vendor\symfony\symfony\src\Symfony\Component\Form\Extension\DataCollector\Proxy\ResolvedTypeDataCollectorProxy.php:111
PHP  14. Symfony\Component\Form\Extension\Core\Type\ChoiceType->buildView() ..\example.com\vendor\symfony\symfony\src\Symfony\Component\Form\ResolvedFormType.php:162
PHP  15. Symfony\Bridge\Doctrine\Form\ChoiceList\EntityChoiceList->getPreferredViews() ..\example.com\vendor\symfony\symfony\src\Symfony\Component\Form\Extension\Core\Type\ChoiceType.php:101
PHP  16. Symfony\Bridge\Doctrine\Form\ChoiceList\EntityChoiceList->load() ..\example.com\vendor\symfony\symfony\src\Symfony\Bridge\Doctrine\Form\ChoiceList\EntityChoiceList.php:174
PHP  17. Symfony\Bridge\Doctrine\Form\ChoiceList\ORMQueryBuilderLoader->getEntities() ..\example.com\vendor\symfony\symfony\src\Symfony\Bridge\Doctrine\Form\ChoiceList\EntityChoiceList.php:430
PHP  18. Doctrine\ORM\AbstractQuery->execute() ..\example.com\vendor\symfony\symfony\src\Symfony\Bridge\Doctrine\Form\ChoiceList\ORMQueryBuilderLoader.php:71
PHP  19. Doctrine\ORM\Query->_doExecute() ..\example.com\vendor\doctrine\orm\lib\Doctrine\ORM\AbstractQuery.php:794
PHP  20. Doctrine\ORM\Query\Exec\SingleSelectExecutor->execute() ..\example.com\vendor\doctrine\orm\lib\Doctrine\ORM\Query.php:286
PHP  21. Doctrine\DBAL\Connection->executeQuery() ..\example.com\vendor\doctrine\orm\lib\Doctrine\ORM\Query\Exec\SingleSelectExecutor.php:50
PHP  22. PDOStatement->execute() ..\example.com\vendor\doctrine\dbal\lib\Doctrine\DBAL\Connection.php:694

Как исправить эту ошибку? Спасибо за помощь.

У меня сложная форма

public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('beds', 'choice', [
'choices' => [
'1' => '1',
'2' => '2',
'3' => '3',
'4' => '4',
'5' => '5',
'6' => '6',
'7' => '7',
'8' => '8',
'9' => '9+',
],
'placeholder' => '',
])
->add('baths', 'choice', [
'choices' => [
'1' => '1',
'2' => '2',
'3' => '3',
'4' => '4',
'5' => '5',
'6' => '6',
'7' => '7',
'8' => '8',
'9' => '9+',
],
'placeholder' => '',
])
->add('storey', 'choice', [
'choices' => [
'1' => '1',
'2' => '2',
'3' => '3',
'4' => '4',
'5' => '5',
'6' => '6',
'7' => '7',
'8' => '8',
'9' => '9+',
],
'placeholder' => '',
'required' => false,
])
->add('title')
->add('body')
->add('password', 'repeated', [
'type' => 'password',
'invalid_message' => 'The password fields must match.',
'options' => array('attr' => array('class' => 'password-field')),
'required' => true,
'first_options' => array('label' => 'Password'),
'second_options' => array('label' => 'Repeat Password'),
])
->add('province', 'entity', [
'class' => 'AppBundle:Province',
'property' => 'name',
'placeholder' => ''
])
->add('activity', 'entity', [
'class' => 'AppBundle:Activity',
'property' => 'name',
'placeholder' => ''
])
->add('unit', 'entity', [
'class' => 'AppBundle:Unit',
'property' => 'name',
'placeholder' => ''
])
->add('direction', 'entity', [
'class' => 'AppBundle:Direction',
'property' => 'name',
'placeholder' => '',
'required' => false
])
->add('legal', 'entity', [
'class' => 'AppBundle:Legal',
'property' => 'name',
'placeholder' => '',
'required' => false
])
->add('images', 'collection', [
'type' => new PropertyImageType(),
'allow_add' => true,
'allow_delete' => true
])
->add('amenities', 'entity', [
'class' => 'AppBundle:Amenity',
'property' => 'name',
'expanded' => true,
'multiple' => true,
'query_builder' => function (EntityRepository $repository) {
return $repository->createQueryBuilder('a')
->from('AppBundle:Amenity', 'amenity')
->where('a.type = 1');
}
]);

И я использую EventSubscriber, чтобы динамически добавить поле

$builder->addEventSubscriber(new AddDistrictFieldSubscriber())
->addEventSubscriber(new AddStreetFieldSubscriber())
->addEventSubscriber(new AddWardFieldSubscriber())
->addEventSubscriber(new AddProjectFieldSubscriber());

class AddDistrictFieldSubscriber implements EventSubscriberInterface
{

/**
* Returns an array of event names this subscriber wants to listen to.
*
* The array keys are event names and the value can be:
*
*  * The method name to call (priority defaults to 0)
*  * An array composed of the method name to call and the priority
*  * An array of arrays composed of the method names to call and respective
*    priorities, or 0 if unset
*
* For instance:
*
*  * array('eventName' => 'methodName')
*  * array('eventName' => array('methodName', $priority))
*  * array('eventName' => array(array('methodName1', $priority), array('methodName2'))
*
* @return array The event names to listen to
*
* @api
*/
public static function getSubscribedEvents()
{
return [
FormEvents::PRE_SET_DATA => 'preSetData',
FormEvents::PRE_SUBMIT => 'preSubmit',
];
}

public function preSetData(FormEvent $event)
{
$data = $event->getData();
$form = $event->getForm();

$province = $data->getProvince();
$districts = $province === null ? [] : $province->getDistricts();

$form->add('district', 'entity', [
'class' => 'AppBundle:District',
'property' => 'name',
'placeholder' => '',
'choices' => $districts,
]);
}

public function preSubmit(FormEvent $event)
{
$data = $event->getData();
$form = $event->getForm();

$province = array_key_exists('province', $data) ? $data['province'] : null;

$form->add('district', 'entity', [
'class' => 'AppBundle:District',
'property' => 'name',
'placeholder' => '',
'query_builder' => function (EntityRepository $repository) use ($province) {
return $repository->createQueryBuilder('d')
->from('AppBundle:District', 'district')
->where('district.province = :province')
->setParameter('province', $province);
}
]);
}
}

class AddStreetFieldSubscriber implements EventSubscriberInterface
{

/**
* Returns an array of event names this subscriber wants to listen to.
*
* The array keys are event names and the value can be:
*
*  * The method name to call (priority defaults to 0)
*  * An array composed of the method name to call and the priority
*  * An array of arrays composed of the method names to call and respective
*    priorities, or 0 if unset
*
* For instance:
*
*  * array('eventName' => 'methodName')
*  * array('eventName' => array('methodName', $priority))
*  * array('eventName' => array(array('methodName1', $priority), array('methodName2'))
*
* @return array The event names to listen to
*
* @api
*/
public static function getSubscribedEvents()
{
return [
FormEvents::PRE_SET_DATA => 'preSetData',
FormEvents::PRE_SUBMIT => 'preSubmit',
];
}

public function preSetData(FormEvent $event)
{
$data = $event->getData();
$form = $event->getForm();

$district = $data->getDistrict();
$streets = $district === null ? [] : $district->getStreets();

$form->add('street', 'entity', [
'class' => 'AppBundle:Street',
'property' => 'name',
'placeholder' => '',
'choices' => $streets,
'required' => false,
]);
}

public function preSubmit(FormEvent $event)
{
$data = $event->getData();
$form = $event->getForm();

$district = array_key_exists('district', $data) ? $data['district'] : null;

$form->add('street', 'entity', [
'class' => 'AppBundle:Street',
'property' => 'name',
'placeholder' => '',
'query_builder' => function (EntityRepository $repository) use ($district) {
return $repository->createQueryBuilder('s')
->from('AppBundle:Street', 'street')
->where('street.district = :district')
->setParameter('district', $district);
}
]);
}
}

Таблицы баз данных:
— провинция: id — имя (70 записей)
— район: id — провинция_id — префикс — имя (700 записей)
— улица: идентификатор — район_идентификатор — префикс — имя (17000 записей)
— ward: id — district_id — префикс — имя (11000 записей)
… и еще несколько таблиц

0

Решение

После отладки каждого поля в форме, наконец, я нашел проблему в построителе запросов в preSubmit ()

$form->add('district', 'entity', [
'class' => 'AppBundle:District',
'property' => 'name',
'placeholder' => '',
'query_builder' => function (EntityRepository $repository) use ($province) {
return $repository->createQueryBuilder('d')
->from('AppBundle:District', 'district')
->where('district.province = :province')
->setParameter('province', $province);
}
]);

$form->add('street', 'entity', [
'class' => 'AppBundle:Street',
'property' => 'name',
'placeholder' => '',
'query_builder' => function (EntityRepository $repository) use ($district) {
return $repository->createQueryBuilder('s')
->from('AppBundle:Street', 'street')
->where('street.district = :district')
->setParameter('district', $district);
}
]);

Я использую псевдоним различия, поэтому доктрина получит все записи в каждой таблице -> исчерпанная память.
Поэтому просто используйте тот же псевдоним или удалите из () в построителе запросов;)

$form->add('district', 'entity', [
'class' => 'AppBundle:District',
'property' => 'name',
'placeholder' => '',
'query_builder' => function (EntityRepository $repository) use ($province) {
return $repository->createQueryBuilder('district')
->where('district.province = :province')
->setParameter('province', $province);
}
]);
0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]