Class 'doctrine.orm.validator.unique' not

2019-07-21 00:25发布

So I am not sure what the issue is here, or how this class even gets loaded. But my model (or as their actually called, entity) looks like this:

<?php

namespace ImageUploader\Models;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;

/**
 * @ORM\Entity
 * @ORM\Table(name="users")
 * @UniqueEntity(fields="userName")
 * @UniqueEntity(fields="email")
 */
class User {

    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue
     */
    protected $id;

    /**
     * @ORM\Column(type="string", length=32, nullable=false)
     * @Assert\NotBlank()
     */
    protected $firstName;

    /**
     * @ORM\Column(type="string", length=32, nullable=false)
     * @Assert\NotBlank()
     */
    protected $lastName;

    /**
     * @ORM\Column(type="string", length=100, unique=true, nullable=false)
     * @Assert\NotBlank(
     *    message = "Username cannot be blank"
     * )
     */
    protected $userName;

    /**
     * @ORM\Column(type="string", length=100, unique=true, nullable=false)
     * @Assert\NotBlank()
     * @Assert\Email(
     *    message = "The email you entered is invalid.",
     *    checkMX = true
     * )
     */
    protected $email;

    /**
     * @ORM\Column(type="string", length=500, nullable=false)
     * @Assert\NotBlank(
     *  message = "The password field cannot be empty."
     * )
     */
    protected $password;

    /**
     * @ORM\Column(type="datetime", nullable=true)
     */
    protected $created_at;

    /**
     * @ORM\Column(type="datetime", nullable=true)
     */
    protected $updated_at;
}

In my I have an action called createAction that gets called when a user attempts to sign up. It looks like this:

public static function createAction($params){
  $postParams = $params->request()->post();

  if ($postParams['password'] !== $postParams['repassword']) {
    $flash = new Flash();
    $flash->createFlash('error', 'Your passwords do not match.');
    $params->redirect('/signup/error');
  }

  $user = new User();

  $user->setFirstName($postParams['firstname'])
       ->setLastName($postParams['lastname'])
       ->setUserName($postParams['username'])
       ->setEmail($postParams['email'])
       ->setPassword($postParams['password'])
       ->setCreatedAtTimeStamp();

  $validator = Validator::createValidatorBuilder();
  $validator->enableAnnotationMapping();

  $errors = $validator->getValidator()->validate($user);

  var_dump($errors);
}

When this action is called I get the following error:

Fatal error: Class 'doctrine.orm.validator.unique' not found in /var/www/html/image_upload_app/vendor/symfony/validator/ConstraintValidatorFactory.php on line 47

I am not sure how to resolve this issue. My composer file is as such:

{
  "require": {
    "doctrine/orm": "2.4.*",
    "doctrine/migrations": "1.0.*@dev",
    "symfony/validator": "2.8.*@dev",
    "symfony/doctrine-bridge": "2.8.*@dev",
    "slim/slim": "~2.6",
    "freya/freya-exception": "0.0.7",
    "freya/freya-loader": "0.2.2",
    "freya/freya-templates": "0.1.2",
    "freya/freya-factory": "0.0.8",
    "freya/freya-flash": "0.0.1"
  },
  "autoload": {
    "psr-4": {"": ""}
  }
}

So I am not sure if I am missing a package or if I am doing something wrong ....

My bootstrap.php file has the following contents in it:

require_once 'vendor/autoload.php';

$loader = require 'vendor/autoload.php';
\Doctrine\Common\Annotations\AnnotationRegistry::registerLoader(array($loader, 'loadClass'));

use Doctrine\ORM\Tools\Setup;
use Doctrine\ORM\EntityManager;

/**
 * Set up Doctrine.
 */
class DoctrineSetup {

    /**
     * @var array $paths - where the entities live.
     */
    protected $paths = array(APP_MODELS);

    /**
     * @var bool $isDevMode - Are we considered "in development."
     */
    protected $isDevMode = false;

    /**
     * @var array $dbParams - The database paramters.
     */
    protected $dbParams = null;

    /**
     * Constructor to set some core values.
     */
    public function __construct(){
        if (!file_exists('db_config.ini')) {
            throw new \Exception(
                'Missing db_config.ini. You can create this from the db_config_sample.ini'
            );
        }

        $this->dbParams = array(
            'driver' => 'pdo_mysql',
            'user' => parse_ini_file('db_config.ini')['DB_USER'],
            'password' => parse_ini_file('db_config.ini')['DB_PASSWORD'],
            'dbname' => parse_ini_file('db_config.ini')['DB_NAME']
        );
    }

    /**
     * Get the entity manager for use through out the app.
     *
     * @return EntityManager
     */
    public function getEntityManager() {
        $config = Setup::createAnnotationMetadataConfiguration($this->paths, $this->isDevMode, null, null, false);
        return EntityManager::create($this->dbParams, $config);
    }
}

/**
 * Function that can be called through out the app.
 *
 * @return EntityManager
 */
function getEntityManager() {
    $ds = new DoctrineSetup();
    return $ds->getEntityManager();
}

/**
 * Function that returns the conection to the database.
 */
function getConnection() {
    $ds = new DoctrineSetup();
    return $ds->getEntityManager()->getConnection();
}

Do I need to add something else to it to get this error to go away?

Update 1

So I went ahead and set up the AppKernel as I didn't have one before, and because I don't believe I need a config.yml (at least not yet). Everything seems to be working - kernel wise, but the error still persists.

namespace ImageUploader;

use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\Config\Loader\LoaderInterface;

class AppKernel extends Kernel {

    public function registerBundles() {
        $bundles = array(
            new \Doctrine\Bundle\DoctrineBundle\DoctrineBundle()
        );

        return $bundles;
    }

    public function registerContainerConfiguration(LoaderInterface $loader) {}
}

I then started the kernel in the bootstrap file, by adding:

use \ImageUploader\AppKernel;

$kernel = new AppKernel();
$kernel->boot();

Everything, from what I have read, is correct - minus the missing config file that shouldn't be an issue. But I still receive the error in question

3条回答
爱情/是我丢掉的垃圾
2楼-- · 2019-07-21 00:37

This is an old question but as I just stumbled upon it and find the chosen answer not entirely satisfying I would like to contribute a bit.

As I understood from the comments this is not about full-stack Symfony but only about the Symfony-validator component. Because the validator constraint UniqueEntity is based on Doctrine integration and hard-coding class names or the such is not recommended to prevent tight-coupling, Symfony uses a much used pattern called services (see service container).

This allows defining services through configuration which would then prevent hardcoding class names (and its dependencies!) into the Validator codebase. This allows dependencies between both project to be configurable (less compatibility-breaks) and optional.

This 'doctrine.orm.validator.unique' "class" that is being searched for is actually just a reference to an instance of the actual class. For it to be found one must add two things:

  • A service container, which resolves this service name to the class instance
  • And the actual configuration of this service, which defines the class to instantiate and its constructor parameters (dependencies).

Looking at your composer.json I think we need the Symfony DependencyInjection component, I don't think you need the AppKernel for this. The following code might work (not tested it) but in any case should give you roughly the idea of what we need:

use Symfony\Component\DependencyInjection\ContainerBuilder;

$container = new ContainerBuilder();
$container
    ->register('doctrine.orm.validator.unique', 'Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntityValidator')
    ->addArgument(new Reference('doctrine'));
# register doctrine here in the same way as we just registered the validator

So in conclusion, this answer will probably be a year or two too late for the OP but might be useful to others stumbling upon this. Cheers!

查看更多
ら.Afraid
3楼-- · 2019-07-21 00:39

How i worked around this:

First, created a custom ConstraintValidatorFactory that'd allow me to add validators

<?php
namespace My\App\Validator;

use Symfony\Component\Validator\ConstraintValidatorFactory as SymfonyConstraintValidatorFactory;
use Symfony\Component\Validator\ConstraintValidatorInterface;

/**
 * Class ConstraintValidatorFactory
 *
 * @package My\App\Validator
 */
class ConstraintValidatorFactory extends SymfonyConstraintValidatorFactory
{
    /**
     * @param string                       $className
     * @param ConstraintValidatorInterface $validator
     *
     * @return void
     */
    public function addValidator($className, $validator): void
    {
        $this->validators[$className] = $validator;
    }
}

Then i could do:

<?php
use My\App\Validator\ConstraintValidatorFactory;
use Symfony\Component\Validator\Validation;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntityValidator;

$factory = new ConstraintValidatorFactory();
$factory->addValidator('doctrine.orm.validator.unique', new UniqueEntityValidator($registry));

$builder = Validation::createValidatorBuilder();
$builder->setConstraintValidatorFactory($factory);
$builder->enableAnnotationMapping();

$validator = $builder->getValidator();
$violations = $validator->validate($entity);

This worked for me, using symfony components with zend service manager.

Bare in mind that Symfony's UniqueEntityValidator depends on \Doctrine\Common\Persistence\ManagerRegistry.

I use a single EntityManager for my project and had to wrap it in a ManagerRegistry class to make this work.

查看更多
叼着烟拽天下
4楼-- · 2019-07-21 00:47

You are missing the Doctrine bundle, which integrates doctrine into the Symfony framework. Install it with composer require doctrine/doctrine-bundle and then register it in your AppKernel.


Related to Update #1

You still need some configuration and set up the doctrine ORM. Without this configuration, ORM services (like the one missing here) are not loaded.

查看更多
登录 后发表回答