Search code examples
doctrinemezzio

nullable not being read in Doctrine


I have a Zend Expressive project from Skeleton app. Also, the database NOT NULL is set for each of the fields that I have set nullable on. I think it might have something to do with it not reading the annotations. I had issues getting the annotations working in the first place, especially for the cli-config.php

Here's the DoctrineFactory I created loosely based on one I found as an example. I changed the way it creates the entityManager to more closely represent the Doctrine docs config example.

public function __invoke(ContainerInterface $container)
{
    $config = $container->has('config') ? $container->get('config') : [];
    $proxyDir = (isset($config['doctrine']['orm']['proxy_dir'])) ?
        $config['doctrine']['orm']['proxy_dir'] : 'data/cache/EntityProxy';
    $proxyNamespace = (isset($config['doctrine']['orm']['proxy_namespace'])) ?
        $config['doctrine']['orm']['proxy_namespace'] : 'EntityProxy';
    $autoGenerateProxyClasses = (isset($config['doctrine']['orm']['auto_generate_proxy_classes'])) ?
        $config['doctrine']['orm']['auto_generate_proxy_classes'] : false;
    $underscoreNamingStrategy = (isset($config['doctrine']['orm']['underscore_naming_strategy'])) ?
        $config['doctrine']['orm']['underscore_naming_strategy'] : false;

    $paths = (isset($config['doctrine']['paths'])) ? $config['doctrine']['paths'] : [];
    $isDevMode = (isset($config['doctrine']['isDevMode'])) ? $config['doctrine']['isDevMode'] : false;

    $doctrine = Setup::createAnnotationMetadataConfiguration($paths, $isDevMode);

    // Doctrine ORM
    $doctrine->setProxyDir($proxyDir);
    $doctrine->setProxyNamespace($proxyNamespace);
    $doctrine->setAutoGenerateProxyClasses($autoGenerateProxyClasses);
    if ($underscoreNamingStrategy) {
        $doctrine->setNamingStrategy(new UnderscoreNamingStrategy());
    }

    // Cache
    $cache = $container->get(Cache::class);
    $doctrine->setQueryCacheImpl($cache);
    $doctrine->setResultCacheImpl($cache);
    $doctrine->setMetadataCacheImpl($cache);

    // EntityManager
    return EntityManager::create($config['doctrine']['connection']['orm_default'], $doctrine);
}

Config like so:

'doctrine' => [
    'orm'        => [
        'auto_generate_proxy_classes' => false,
        'proxy_dir'                   => 'data/cache/EntityProxy',
        'proxy_namespace'             => 'EntityProxy',
        'underscore_naming_strategy'  => true,
    ],
    'connection' => [
        // default connection
        'orm_default' => [
            'driver'   => 'pdo_mysql',
            'host'     => '127.0.0.1',
            'port'     => '3306',
            'dbname'   => 'users',
            'user'     => 'root',
            'password' => 'password',
            'charset'  => 'UTF8',
        ],
    ],
    'paths' => [
        __DIR__.'/../../vendor/plexus/user-lib/src/Entity'
    ],
    'isDevMode' => false,
    'cache'      => [
        'redis' => [
            'host' => '127.0.0.1',
            'port' => '6379',
        ],
    ],
],

Entity:

namespace Plexus\User\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 */
class User
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(name="id", type="int")
     * @var int
     */
    protected $id;

    /**
     * @ORM\Column(name="email", type="string", length=255)
     * @var string
     */
    protected $email;

    /**
     * @ORM\Column(name="unverifiedEmail", type="string", length=255, nullable=true)
     * @var string
     */
    protected $unverifiedEmail;

    /**
     * @ORM\Column(name="unverifiedEmailHash", type="string", length=255, nullable=true)
     * @var string
     */
    protected $verifyEmailHash;

    /**
     * @var string
     * At this time, http://php.net/manual/en/function.password-hash.php recommends using 255 length for hashes
     * @ORM\Column(name="passwordHash", type="string", length=255)
     */
    protected $passwordHash;

    /**
     * @var string
     * @ORM\Column(name="passwordResetHash", type="string", length=255, nullable=true)
     */
    protected $passwordResetHash;

    /**
     * @return mixed
     */
    public function getUnverifiedEmail()
    {
        return $this->unverifiedEmail;
    }

    /**
     * @param mixed $unverifiedEmail
     */
    public function setUnverifiedEmail($unverifiedEmail)
    {
        $this->unverifiedEmail = $unverifiedEmail;
    }

    /**
     * @return mixed
     */
    public function getVerifyEmailHash()
    {
        return $this->verifyEmailHash;
    }

    /**
     * @param mixed $verifyEmailHash
     */
    public function setVerifyEmailHash($verifyEmailHash)
    {
        $this->verifyEmailHash = $verifyEmailHash;
    }

    /**
     * @return string
     */
    public function getEmail()
    {
        return $this->email;
    }

    /**
     * @param string $email
     */
    public function setEmail($email)
    {
        $this->email = $email;
    }

    /**
     * @return string
     */
    public function getPasswordHash()
    {
        return $this->passwordHash;
    }

    /**
     * @param string $passwordHash
     */
    public function setPasswordHash($passwordHash)
    {
        $this->passwordHash = $passwordHash;
    }

    /**
     * @return string
     */
    public function getPasswordResetHash(): string
    {
        return $this->passwordResetHash;
    }

    /**
     * @param string $passwordResetHash
     */
    public function setPasswordResetHash(string $passwordResetHash)
    {
        $this->passwordResetHash = $passwordResetHash;
    }

    /**
     * @return mixed
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * @param mixed $id
     */
    public function setId($id)
    {
        $this->id = $id;
    }

    public function toArray()
    {
        return [
            'email' => $this->getEmail(),
        ];
    }
}

Error:

   Doctrine\DBAL\Exception\NotNullConstraintViolationException: An exception occurred while executing 'INSERT INTO user (unverifiedEmail, unverifiedEmailHash, passwordHash, passwordResetHash) VALUES (?, ?, ?, ?)' with params [null, null, "$2y$10$pRDv8NFXaCxF7\/ZUzL.ZuulsFqdwTs9IOycWTHYA.1Q0qpFu5uGXe", null]:

        SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'unverifiedEmail' cannot be null in file /var/www/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/AbstractMySQLDriver.php on line 118
    Stack trace:
  1. Doctrine\DBAL\Exception\NotNullConstraintViolationException->() /var/www/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/AbstractMySQLDriver.php:118
  2. Doctrine\DBAL\Driver\AbstractMySQLDriver->convertException() /var/www/vendor/doctrine/dbal/lib/Doctrine/DBAL/DBALException.php:176
  3. Doctrine\DBAL\DBALException->wrapException() /var/www/vendor/doctrine/dbal/lib/Doctrine/DBAL/DBALException.php:150
  4. Doctrine\DBAL\DBALException->driverExceptionDuringQuery() /var/www/vendor/doctrine/dbal/lib/Doctrine/DBAL/Statement.php:177
  5. Doctrine\DBAL\Driver\PDOException->() /var/www/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php:107
  6. PDOException->() /var/www/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php:105
  7. PDOStatement->execute() /var/www/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php:105
  8. Doctrine\DBAL\Driver\PDOStatement->execute() /var/www/vendor/doctrine/dbal/lib/Doctrine/DBAL/Statement.php:168
  9. Doctrine\DBAL\Statement->execute() /var/www/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php:283
 10. Doctrine\ORM\Persisters\Entity\BasicEntityPersister->executeInserts() /var/www/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php:1051
 11. Doctrine\ORM\UnitOfWork->executeInserts() /var/www/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php:386
 12. Doctrine\ORM\UnitOfWork->commit() /var/www/vendor/doctrine/orm/lib/Doctrine/ORM/EntityManager.php:358
 13. Doctrine\ORM\EntityManager->flush() /var/www/vendor/plexus/user-lib/src/Service/UserServiceDoctrine.php:53
 14. Plexus\User\Service\UserServiceDoctrine->saveUser() /var/www/vendor/plexus/user-lib/src/Service/UserService.php:27
 15. Plexus\User\Service\UserService->setPassword() /var/www/vendor/plexus/user-lib/src/Service/UserServiceDoctrine.php:43
 16. Plexus\User\Service\UserServiceDoctrine->createUser() /var/www/src/App/src/Action/CreateUserAction.php:39
 17. App\Action\CreateUserAction->process() /var/www/vendor/zendframework/zend-expressive/src/Middleware/LazyLoadingMiddleware.php:62
...

Any help would be greatly appreciated. I can't think of what would cause this.


Solution

  • So the issue, it turns out, is that Doctrine was caching my entities and probably had a hold of a stale entity. I figured this out because I added the id field but it wasn't showing up at all. I destroyed and recreated my Vagrant box, and it worked.

    So I added this if statement around the cache adapter:

    if (!$isDevMode) {
        // Cache
        $cache = $container->get(Cache::class);
        $doctrine->setQueryCacheImpl($cache);
        $doctrine->setResultCacheImpl($cache);
        $doctrine->setMetadataCacheImpl($cache);
    }
    

    and I set $isDevMode to true.