Symfony2表单验证耗尽内存

时间:2015-03-14 07:02:05

标签: php validation symfony out-of-memory

我有一个复杂的表单,有很多实体选择字段。当我不使用验证时,添加/编辑是可以的。但是当我在/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条记录) - district:id - province_id - prefix - name(700条记录) - street:id - district_id - prefix - name(17000条记录) - ward:id - district_id - prefix - name(11000条记录) ......还有一些表

1 个答案:

答案 0 :(得分: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);
    }
]);

我使用差异别名,因此doctrine将获取每个表中的所有记录 - >精疲力竭的记忆。 因此,只需在查询构建器中使用相同的别名或从()中删除;)

$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);
    }
]);
相关问题