У меня сложная форма со многими полями выбора сущностей. Когда я не использую валидацию, добавить / изменить можно. Но когда я включаю проверку формы в /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 записей)
… и еще несколько таблиц
После отладки каждого поля в форме, наконец, я нашел проблему в построителе запросов в 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);
}
]);
Других решений пока нет …