zendframework/zend-validator

RecordExists and NoRecordExists is not reusable for validate different values

AndrejAndb opened this issue · 3 comments

Custom modification in method for debug: https://github.com/zendframework/zend-validator/blob/master/src/Db/AbstractDb.php#L321

    protected function query($value)
    {
        $sql = new Sql($this->getAdapter());
        $select = $this->getSelect();
        $statement = $sql->prepareStatementForSqlObject($select);
        $parameters = $statement->getParameterContainer();
        $parameters['where1'] = $value; // <- PROBLEM
        echo $statement->getSql() . "\n"; // <- DEBUG
        $result = $statement->execute();
        return $result->current();
    }

test case:

        $validator = new RecordExists([
            'table'   => 'tags',
            'field'   => 'id',
            'adapter' => $this->getEvent()->getApplication()->getServiceManager()->get('DBSiteAdapter')
        ]);
        print_r($validator->isValid(1)); echo "\n";
        print_r($validator->isValid(2)); echo "\n";

result:

SELECT "tags"."id" AS "id" FROM "tags" WHERE "id" = :where1
1
SELECT "tags"."id" AS "id" FROM "tags" WHERE "id" = :where2
PDO EXCEPTION: SQLSTATE[HY093]: Invalid parameter number: :where1

as we see, in next call we have :where2 instead :where1

Hm, I was found that problem occurs not for All PDO drivers. For sqlite: - all fine, but for pgsql: problem was present.

(Sorry, do not have time for continue analyze, I will fix it for me by implement alternative approach)

I will try to continue :)

source code of validator:

protected function query($value)
{
$sql = new Sql($this->getAdapter());
$select = $this->getSelect();
$statement = $sql->prepareStatementForSqlObject($select);
$parameters = $statement->getParameterContainer();
$parameters['where1'] = $value;
$result = $statement->execute();
return $result->current();
}

    protected function query($value)
    {
        $sql = new Sql($this->getAdapter());
        $select = $this->getSelect();
        $statement = $sql->prepareStatementForSqlObject($select);
        $parameters = $statement->getParameterContainer();
        $parameters['where1'] = $value;
        $result = $statement->execute()

source code of https://github.com/zendframework/zend-db/blob/b1c79192c76b817062c1fa4e81ef2dcf1afea73e/src/Sql/AbstractSql.php#L136

        if (! isset($this->instanceParameterIndex[$namedParameterPrefix])) {
            $this->instanceParameterIndex[$namedParameterPrefix] = 1;
        }
        $expressionParamIndex = &$this->instanceParameterIndex[$namedParameterPrefix];

        .....

        $name = $namedParameterPrefix . $expressionParamIndex++;

so, for Select Object we have ever-increased number postfix for named parameter markers: where1, where2, etc...

But for sqlite is Ok, because Zend\Db\Sql\Platform\Platform has Select decorator for sqlite, and Platform object was re-instantiated for each 'validation call', and in this case we have that $this->instanceParameterIndex reset each time

:)

I am not sure that it is must be fixed on zend-db side, looks like better implement some alternative approach for validator :)

This repository has been closed and moved to laminas/laminas-validator; a new issue has been opened at laminas/laminas-validator#16.