0

It's been weeks since I start learning Slim using Zend TableGateway from slim-api-skeleton.

It seems I can't run 2 consecutive query using TableGateway. It's always produce (not just UPDATE):

"Statement couldn't be produced with sql: UPDATE `users` SET `last_access` = NOW() WHERE `id` = ?"

Here's the code inside ZendUserRepository class:

public function __construct(array $config) {
    $adapter = new Adapter($config);
    $this->table = new TableGateway("users", $adapter);
}

...

public function footprint(int $id): void {
    $data = ['last_access' => new Predicate\Expression('NOW()')];
    $where = ['id' => $id];
    $this->table->update($data, $where);
}

public function authenticate(string $username, string $password): bool {
    $where = [
        'username' => $username,
        new Predicate\IsNotNull('roles')
    ];
    $rowset = $this->table->select($where);
    if (null === $row = $rowset->current()) {
        return false;
    }
    $data = (array) $row;
    if(password_verify($password, $data['password'])) {
        $this->footprint($data['id']);
        return true;
    }
    return false;
}

This frustrate me for days. Since the update function also use 2 consecutive query.

public function update(User $user): void {
    $data = $this->hydrator->extract($user);
    if (!$this->contains($user)) {
        throw new UserNotFoundException;
    }
    $where = ["id" => $user->getId()];
    $this->table->update($data, $where);
}

public function contains(User $user): bool {
    try {
        $this->get($user->getId());
    } catch (UserNotFoundException $exception) {
        return false;
    }
    return true;
}

Thank you.

1 Answers1

0

Using PHPUnit test, I got the following result:

Zend\Db\Adapter\Exception\InvalidQueryException: Statement couldn't be produced with sql: UPDATE `users` SET `last_access` = NOW() WHERE `id` = ?

/vagrant/vendor/zendframework/zend-db/src/Adapter/Driver/Mysqli/Statement.php:208
/vagrant/vendor/zendframework/zend-db/src/Adapter/Driver/Mysqli/Statement.php:229
/vagrant/vendor/zendframework/zend-db/src/TableGateway/AbstractTableGateway.php:391
/vagrant/vendor/zendframework/zend-db/src/TableGateway/AbstractTableGateway.php:349
/vagrant/src/Infrastructure/ZendUserRepository.php:90
/vagrant/src/Infrastructure/ZendUserRepository.php:104
/vagrant/src/Application/User/UserAuthenticationHandler.php:19
/vagrant/tests/Application/User/UserAuthenticationHandlerTest.php:41

Caused by
Zend\Db\Adapter\Exception\ErrorException: Commands out of sync; you can't run this command now

And from google lead to https://stackoverflow.com/a/614741/3164944

You can't have two simultaneous queries because mysqli uses unbuffered queries by default (for prepared statements; it's the opposite for vanilla mysql_query). You can either fetch the first one into an array and loop through that, or tell mysqli to buffer the queries (using $stmt->store_result()).


Solved with additional configuration:

[
    "driver" => "Mysqli",
    "database" => getenv("DB_NAME"),
    "username" => getenv("DB_USER"),
    "password" => getenv("DB_PASSWORD"),
    "hostname" => getenv("DB_HOST"),
    "charset" => "utf8",
    'options' => ['buffer_results' => true],
]

From https://stackoverflow.com/a/43863554/3164944