SQL 在 PHP 从 5.6.30 升级到 7.0.20 后,Symfony 2.8 上的复杂表单问题

SQL problems with complex forms on Symfony 2.8 after PHP upgrade from 5.6.30 to 7.0.20

我在 Symfony 2.8 和 PHP 5.6 中成功使用了一个应用程序。在我升级到 PHP 7.0.20 后,我遇到了 bind/submit 具有一对多关系的复杂表单的问题。

产生的错误是:

request.CRITICAL: Uncaught PHP Exception Doctrine\ORM\Query\QueryException: "[Syntax Error] line 0, col 63: Error: Expected Literal, got 'ORDER'" at ..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query/QueryException.php line 44 {"exception":"[object] (Doctrine\ORM\Query\QueryException(code: 0): [Syntax Error] line 0, col 63: Error: Expected Literal, got 'ORDER' at ..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query/QueryException.php:44, Doctrine\ORM\Query\QueryException(code: 0): SELECT s1 FROM Prfuk\WebquotaBundle\Entity\Workplace s1 WHERE ORDER BY s1.nazev ASC at ..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query/QueryException.php:39)"} []

WHEREORDER BY之间有缺失的部分。奇怪的是列表数据是好的,填充表单字段来编辑记录也是好的,问题只是在将 POST 请求与当前表单数据合并时,我想 SQL 的缺失部分由学说生成。

与其他表格无关的简单表格也能正常工作。

我是最新的2.8.x Symfony 版本,我能够通过composer 更新的最新Doctrine 是2.3.6-dev,它很旧,但它似乎是最新的supported/compatible.

这是一个已知问题吗? Symfony 2.8 与 PHP 7.0 兼容吗? 你能给我一些解决这个问题的建议吗?

我的表格类型:

$qb = array(
    'class' => 'Prfuk\WebquotaBundle\Entity\Workplace',
    'property' => 'nazev',
    'query_builder' => function(\Prfuk\WebquotaBundle\Entity\WorkplaceRepository $repository) {
        return $repository
            ->createQueryBuilder('s1')
            ->add('orderBy', 's1.nazev ASC');
    },
    'attr' => array(
        "class" => "input_text_nazev"),
        'label' => "Pracoviště",
    );
$builder->add('pracoviste', 'entity', $qb);

我的控制器:

$form = $this->createForm(new FolderType($this->getDoctrine()->getEntityManager()), $folder);
if ($request->isMethod('POST')) {
    //print_r($form->getData()); // works here
    $form->bind($request); // throws an exception

ORM:

Prfuk\WebquotaBundle\Entity\Folder:
    type: entity
    table: null
    repositoryClass: Prfuk\WebquotaBundle\Entity\FolderRepository
    fields:
        id:
            type: integer
            id: true
            generator:
                strategy: AUTO
        nazev:
            type: string
            length: '255'
        cesta:
            type: string
            length: '255'
        kvota:
            type: integer
        uzivatel:
            type: string
            length: '255'
        poznamka:
            type: text
        vyuziti_mb:
            type: integer
            options:
                default: 0
    manyToOne:
        pracoviste:
            targetEntity: Workplace
            inversedBy: pracoviste
            joinColumn:
                name: pracoviste
                referencedColumnName: id
        db:
            targetEntity: DatabaseInfo
            inversedBy: db
            joinColumn:
                name: db
                referencedColumnName: id
        skupina:
            targetEntity: GroupInfo
            inversedBy: skupina
            joinColumn:
                name: skupina
                referencedColumnName: id
        webhost:
            targetEntity: WebhostInfo
            inversedBy: webhost
            joinColumn:
                name: webhost
                referencedColumnName: id
    lifecycleCallbacks: {  }

编辑:堆栈跟踪(已编辑文件路径):

[1] Doctrine\ORM\Query\QueryException: [Syntax Error] line 0, col 63: Error: Expected Literal, got 'ORDER'
    at n/a
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query/QueryException.php line 44

    at Doctrine\ORM\Query\QueryException::syntaxError('line 0, col 63: Error: Expected Literal, got 'ORDER'', object(QueryException))
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Parser.php line 396

    at Doctrine\ORM\Query\Parser->syntaxError('Literal')
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Parser.php line 2363

    at Doctrine\ORM\Query\Parser->Literal()
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Parser.php line 2550

    at Doctrine\ORM\Query\Parser->ArithmeticPrimary()
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Parser.php line 2485

    at Doctrine\ORM\Query\Parser->ArithmeticFactor()
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Parser.php line 2453

    at Doctrine\ORM\Query\Parser->ArithmeticTerm()
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Parser.php line 2427

    at Doctrine\ORM\Query\Parser->SimpleArithmeticExpression()
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Parser.php line 2414

    at Doctrine\ORM\Query\Parser->ArithmeticExpression()
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Parser.php line 2749

    at Doctrine\ORM\Query\Parser->ComparisonExpression()
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Parser.php line 2277

    at Doctrine\ORM\Query\Parser->SimpleConditionalExpression()
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Parser.php line 2177

    at Doctrine\ORM\Query\Parser->ConditionalPrimary()
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Parser.php line 2153

    at Doctrine\ORM\Query\Parser->ConditionalFactor()
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Parser.php line 2121

    at Doctrine\ORM\Query\Parser->ConditionalTerm()
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Parser.php line 2096

    at Doctrine\ORM\Query\Parser->ConditionalExpression()
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Parser.php line 1209

    at Doctrine\ORM\Query\Parser->WhereClause()
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Parser.php line 759

    at Doctrine\ORM\Query\Parser->SelectStatement()
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Parser.php line 726

    at Doctrine\ORM\Query\Parser->QueryLanguage()
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Parser.php line 229

    at Doctrine\ORM\Query\Parser->getAST()
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Parser.php line 304

    at Doctrine\ORM\Query\Parser->parse()
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query.php line 233

    at Doctrine\ORM\Query->_parse()
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query.php line 245

    at Doctrine\ORM\Query->_doExecute()
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/AbstractQuery.php line 753

    at Doctrine\ORM\AbstractQuery->execute(null, '1')
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/AbstractQuery.php line 542

    at Doctrine\ORM\AbstractQuery->getResult()
        in /..../Symfony/vendor/symfony/symfony/src/Symfony/Bridge/Doctrine/Form/ChoiceList/ORMQueryBuilderLoader.php line 126

    at Symfony\Bridge\Doctrine\Form\ChoiceList\ORMQueryBuilderLoader->getEntitiesByIds('id', array('27'))
        in /..../Symfony/vendor/symfony/symfony/src/Symfony/Bridge/Doctrine/Form/ChoiceList/DoctrineChoiceLoader.php line 153

    at Symfony\Bridge\Doctrine\Form\ChoiceList\DoctrineChoiceLoader->loadChoicesForValues(array('27'), array(object(IdReader), 'getIdValue'))
        in /..../Symfony/vendor/symfony/symfony/src/Symfony/Component/Form/ChoiceList/LazyChoiceList.php line 122

    at Symfony\Component\Form\ChoiceList\LazyChoiceList->getChoicesForValues(array('27'))
        in /..../Symfony/vendor/symfony/symfony/src/Symfony/Component/Form/Extension/Core/DataTransformer/ChoiceToValueTransformer.php line 46

    at Symfony\Component\Form\Extension\Core\DataTransformer\ChoiceToValueTransformer->reverseTransform('27')
        in /..../Symfony/vendor/symfony/symfony/src/Symfony/Component/Form/Form.php line 1190

    at Symfony\Component\Form\Form->viewToNorm('27')
        in /..../Symfony/vendor/symfony/symfony/src/Symfony/Component/Form/Form.php line 639

    at Symfony\Component\Form\Form->submit('27', true)
        in /..../Symfony/vendor/symfony/symfony/src/Symfony/Component/Form/Form.php line 579

    at Symfony\Component\Form\Form->submit(array('pracoviste' => '27', 'cesta' => 'simonju_botazah', 'kvota' => '100', 'uzivatel' => 'simonju', 'skupina' => '', 'poznamka' => 'fake záznam pro člena skupiny www-botazah', 'db' => '', 'webhost' => '', 'vyuziti_mb' => '0'))
        in /..../Symfony/vendor/symfony/symfony/src/Symfony/Component/Form/Form.php line 692

    at Symfony\Component\Form\Form->bind(object(Request))
        in /..../Symfony/src/Prfuk/WebquotaBundle/Controller/FolderController.php line 90

    at Prfuk\WebquotaBundle\Controller\FolderController->editAction(object(Request), '650')
        in  line 

    at call_user_func_array(array(object(FolderController), 'editAction'), array(object(Request), '650'))
        in /..../Symfony/app/bootstrap.php.cache line 3247

    at Symfony\Component\HttpKernel\HttpKernel->handleRaw(object(Request), '1')
        in /..../Symfony/app/bootstrap.php.cache line 3206

    at Symfony\Component\HttpKernel\HttpKernel->handle(object(Request), '1', true)
        in /..../Symfony/app/bootstrap.php.cache line 3360

    at Symfony\Component\HttpKernel\DependencyInjection\ContainerAwareHttpKernel->handle(object(Request), '1', true)
        in /..../Symfony/app/bootstrap.php.cache line 2562

    at Symfony\Component\HttpKernel\Kernel->handle(object(Request))
        in /..../Symfony/web/app_dev.php line 28

[2] Doctrine\ORM\Query\QueryException: SELECT s1 FROM Prfuk\WebquotaBundle\Entity\Workplace s1 WHERE  ORDER BY s1.nazev ASC
    at n/a
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query/QueryException.php line 39

    at Doctrine\ORM\Query\QueryException::dqlError('SELECT s1 FROM Prfuk\WebquotaBundle\Entity\Workplace s1 WHERE  ORDER BY s1.nazev ASC')
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Parser.php line 396

    at Doctrine\ORM\Query\Parser->syntaxError('Literal')
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Parser.php line 2363

    at Doctrine\ORM\Query\Parser->Literal()
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Parser.php line 2550

    at Doctrine\ORM\Query\Parser->ArithmeticPrimary()
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Parser.php line 2485

    at Doctrine\ORM\Query\Parser->ArithmeticFactor()
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Parser.php line 2453

    at Doctrine\ORM\Query\Parser->ArithmeticTerm()
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Parser.php line 2427

    at Doctrine\ORM\Query\Parser->SimpleArithmeticExpression()
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Parser.php line 2414

    at Doctrine\ORM\Query\Parser->ArithmeticExpression()
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Parser.php line 2749

    at Doctrine\ORM\Query\Parser->ComparisonExpression()
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Parser.php line 2277

    at Doctrine\ORM\Query\Parser->SimpleConditionalExpression()
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Parser.php line 2177

    at Doctrine\ORM\Query\Parser->ConditionalPrimary()
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Parser.php line 2153

    at Doctrine\ORM\Query\Parser->ConditionalFactor()
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Parser.php line 2121

    at Doctrine\ORM\Query\Parser->ConditionalTerm()
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Parser.php line 2096

    at Doctrine\ORM\Query\Parser->ConditionalExpression()
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Parser.php line 1209

    at Doctrine\ORM\Query\Parser->WhereClause()
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Parser.php line 759

    at Doctrine\ORM\Query\Parser->SelectStatement()
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Parser.php line 726

    at Doctrine\ORM\Query\Parser->QueryLanguage()
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Parser.php line 229

    at Doctrine\ORM\Query\Parser->getAST()
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Parser.php line 304

    at Doctrine\ORM\Query\Parser->parse()
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query.php line 233

    at Doctrine\ORM\Query->_parse()
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query.php line 245

    at Doctrine\ORM\Query->_doExecute()
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/AbstractQuery.php line 753

    at Doctrine\ORM\AbstractQuery->execute(null, '1')
        in /..../Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/AbstractQuery.php line 542

    at Doctrine\ORM\AbstractQuery->getResult()
        in /..../Symfony/vendor/symfony/symfony/src/Symfony/Bridge/Doctrine/Form/ChoiceList/ORMQueryBuilderLoader.php line 126

    at Symfony\Bridge\Doctrine\Form\ChoiceList\ORMQueryBuilderLoader->getEntitiesByIds('id', array('27'))
        in /..../Symfony/vendor/symfony/symfony/src/Symfony/Bridge/Doctrine/Form/ChoiceList/DoctrineChoiceLoader.php line 153

    at Symfony\Bridge\Doctrine\Form\ChoiceList\DoctrineChoiceLoader->loadChoicesForValues(array('27'), array(object(IdReader), 'getIdValue'))
        in /..../Symfony/vendor/symfony/symfony/src/Symfony/Component/Form/ChoiceList/LazyChoiceList.php line 122

    at Symfony\Component\Form\ChoiceList\LazyChoiceList->getChoicesForValues(array('27'))
        in /..../Symfony/vendor/symfony/symfony/src/Symfony/Component/Form/Extension/Core/DataTransformer/ChoiceToValueTransformer.php line 46

    at Symfony\Component\Form\Extension\Core\DataTransformer\ChoiceToValueTransformer->reverseTransform('27')
        in /..../Symfony/vendor/symfony/symfony/src/Symfony/Component/Form/Form.php line 1190

    at Symfony\Component\Form\Form->viewToNorm('27')
        in /..../Symfony/vendor/symfony/symfony/src/Symfony/Component/Form/Form.php line 639

    at Symfony\Component\Form\Form->submit('27', true)
        in /..../Symfony/vendor/symfony/symfony/src/Symfony/Component/Form/Form.php line 579

    at Symfony\Component\Form\Form->submit(array('pracoviste' => '27', 'cesta' => 'simonju_botazah', 'kvota' => '100', 'uzivatel' => 'simonju', 'skupina' => '', 'poznamka' => 'fake záznam pro člena skupiny www-botazah', 'db' => '', 'webhost' => '', 'vyuziti_mb' => '0'))
        in /..../Symfony/vendor/symfony/symfony/src/Symfony/Component/Form/Form.php line 692

    at Symfony\Component\Form\Form->bind(object(Request))
        in /..../Symfony/src/Prfuk/WebquotaBundle/Controller/FolderController.php line 90

    at Prfuk\WebquotaBundle\Controller\FolderController->editAction(object(Request), '650')
        in  line 

    at call_user_func_array(array(object(FolderController), 'editAction'), array(object(Request), '650'))
        in /..../Symfony/app/bootstrap.php.cache line 3247

    at Symfony\Component\HttpKernel\HttpKernel->handleRaw(object(Request), '1')
        in /..../Symfony/app/bootstrap.php.cache line 3206

    at Symfony\Component\HttpKernel\HttpKernel->handle(object(Request), '1', true)
        in /..../Symfony/app/bootstrap.php.cache line 3360

    at Symfony\Component\HttpKernel\DependencyInjection\ContainerAwareHttpKernel->handle(object(Request), '1', true)
        in /..../Symfony/app/bootstrap.php.cache line 2562

    at Symfony\Component\HttpKernel\Kernel->handle(object(Request))
        in /..../Symfony/web/app_dev.php line 28

试试这个:

'query_builder' => function(\Prfuk\WebquotaBundle\Entity\WorkplaceRepository $repository) {
        return $repository
            ->createQueryBuilder('s1')
            ->orderBy('s1.nazev','ASC');
    },

我终于解决了问题:

  1. 旧学说包 (2.3.x) 由于某种原因在 2 月份我将 Symfony 升级到 2.8 时没有更新(我什至不知道作曲家是快乐)。

  2. 借助 app_dev.php 生成的回溯,我将错误缩小到 Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/QueryBuilder 的 andWhere() 方法。php:

    public function andWhere($where)
    {
        $where = $this->getDQLPart('where');
        $args  = func_get_args();
        if ($where instanceof Expr\Andx) {
            $where->addMultiple($args);
        } else {
            array_unshift($args, $where);
            $where = new Expr\Andx($args);
        }
        return $this->add('where', $where, true);
    }
    

自 PHP 7.0.0:

以来,func_get_args() 的行为发生了变化

This function returns a copy of the passed arguments only, and does not account for default (non-passed) arguments.

If the arguments are passed by reference, any changes to the arguments will be reflected in the values returned by this function. As of PHP 7 the current values will also be returned if the arguments are passed by value.

短期解决方案是交换此方法中的前两行代码。但是代码中有更多地方使用相同的逻辑模式,所以我迫切需要找到一种升级学说的方法。

  1. 升级学说对我来说是一个艰巨的任务,但我成功了。这是我现在的最终 composer.json:

    {
        "name": "symfony/framework-standard-edition",
        "license": "MIT",
        "type": "project",
        "description": "The \"Symfony Standard Edition\" distribution",
        "autoload": {
            "psr-0": { "": "src/" }
        },
        "require": {
            "php": ">=5.3.9",
            "symfony/symfony": "2.8.*",
            "doctrine/common": "2.5.*",
            "doctrine/dbal": "2.5.*",
            "doctrine/orm": "~2.5.0",
            "doctrine/doctrine-bundle": "~1.4.0",
            "twig/extensions": "1.0.*",
            "symfony/assetic-bundle": "2.3.*",
            "symfony/swiftmailer-bundle": "2.3.*",
            "symfony/monolog-bundle": "2.3.*",
            "sensio/distribution-bundle": "4.0.*",
            "sensio/framework-extra-bundle": "3.0.*",
            "sensio/generator-bundle": "2.4.*",
            "jms/security-extra-bundle": "1.6.*",
            "jms/di-extra-bundle": "1.4.*",
            "incenteev/composer-parameter-handler": "~2.0"
        },
        "minimum-stability": "stable",
        "scripts": {
            "post-install-cmd": [
                "Incenteev\ParameterHandler       \ScriptHandler::buildParameters",
                "Sensio\Bundle\DistributionBundle\Composer\ScriptHandler::buildBootstrap",
                "Sensio\Bundle\DistributionBundle\Composer\ScriptHandler::clearCache",
                "Sensio\Bundle\DistributionBundle\Composer\ScriptHandler::installAssets",
                "Sensio\Bundle\DistributionBundle\Composer\ScriptHandler::installRequirementsFile"
            ],
            "post-update-cmd": [
                "Incenteev\ParameterHandler\ScriptHandler::buildParameters",
                "Sensio\Bundle\DistributionBundle\Composer\ScriptHandler::buildBootstrap",
                "Sensio\Bundle\DistributionBundle\Composer\ScriptHandler::clearCache",
                "Sensio\Bundle\DistributionBundle\Composer\ScriptHandler::installAssets",
                "Sensio\Bundle\DistributionBundle\Composer\ScriptHandler::installRequirementsFile"
            ]
        },
        "config": {
            "bin-dir": "bin"
        },
        "extra": {
            "symfony-app-dir": "app",
            "symfony-web-dir": "web",
            "incenteev-parameters": {
                 "file": "app/config/parameters.yml"
            }
        }
    }
    
  2. 有了新知识,我很高兴在网上找到更多相关信息,即 https://github.com/doctrine/doctrine2/issues/4712

感谢所有回复的人。