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
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.
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.
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!
In the first you can get the kernel
After using the kernel to get service validator.
For example : $validator = $kernel->getContainer()->get('validator');
Related
Is there a way to tell Doctrine the name of a number of entities and it creates their related tables (incl. foreign keys etc.)?
My scenario:
I want to have annotations at my Doctrine entities as the only source for my database schema. Which means, that for instance for tests, i don't want to maintain a copy of these information in a SQL file or something.
To be clear, i mean annotations in entity classes like the following:
<?php
namespace App\Entity;
/**
* #ORM\Entity(repositoryClass="App\Repository\UserRepository")
* #UniqueEntity(fields={"email"}, message="There is already an account with this email")
*
* #ORM\Table(
* uniqueConstraints={
* #ORM\UniqueConstraint(name="email", columns={"email"})
* }
* )
*/
class User
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=180, nullable=false)
*/
private $email;
// ...
}
What i would like to do:
In my tests i would like to create the table for, lets say User, like:
<?php
namespace App\Test;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
class SomeTestCase extends KernelTestCase
{
public function setUp()
{
// ...
$this->entityManager = $kernel->getContainer()
->get('doctrine')
->getManager();
}
public function test1()
{
// Is there a function available which has this functionality?
$this->entityManager->createTableForEntity('App\Entity\User'); // <---------
// ...
}
}
Is that possible? If not, even creating all tables at once is fine for me.
Is there another way to achieve it?
I use the following to create all the tables in my tests:
use Doctrine\ORM\Tools\SchemaTool;
$metadatas = $this->entityManager->getMetadataFactory()->getAllMetadata();
$schemaTool = new SchemaTool($this->entityManager);
$schemaTool->updateSchema($metadatas);
There is a method getMetadataFactory() on the MetadataFactory class so I guess the following should work as well if you want to create just one table.
$metadata = $this->entityManager->getMetadataFactory()->getMetadataFor('App\Entity\User');
$schemaTool = new SchemaTool($this->entityManager);
$schemaTool->updateSchema($metadata);
Before starting, the usual disclaimer : I am aware of dozens of questions here on SE from people encountering identical-looking problems, I have browsed them and unless I missed something, the combination of all the fixes proposed does not solve my particular problem.
In particular :
This question is about duplicated
and inherited entities, which I don't have.
This answer is about
invalid annotation format (missing asterisks), which I don't have in my entity definition (see file content below).
In this question, the problem
comes from a #todo somewhere, which I don't use
In this question, the problem
comes from using eAccelerator which I'm not using at this point
I get the following error message in Symfony :
Doctrine\ORM\Mapping\MappingException: Class "AppBundle\Entity\User" is not a valid entity or mapped super class.
Yet, other commands tell me everything is fine :
$ php bin/console doctrine:mapping:info
Found 6 mapped entities:
[OK] AppBundle\Entity\Category
[OK] AppBundle\Entity\Comment
[OK] AppBundle\Entity\Post
[OK] AppBundle\Entity\Section
[OK] AppBundle\Entity\User
[OK] AppBundle\Entity\World
I also tried
try {
$entityManager->getConnection()->connect();
} catch (\Exception $e) {
echo 'Connection failed !';
}
in my code to see if the connection worked. I also tried "registering noop annotation autoloader" as
suggested in this SO answer
the content of my test file below reflects this ;
<?php
error_reporting(E_ALL|E_STRICT);
require 'app/autoload.php';
xdebug_break();
use AppBundle\Entity;
use Doctrine\ORM\Tools\Setup;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Mapping\Driver\AnnotationDriver;
use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\Annotations\AnnotationRegistry;
$paths = array("src/AppBundle/Entity");
$isDevMode = true;
// the connection configuration
$dbParams = array(
'driver' => 'pdo_mysql',
'user' => 'root',
'password' => 'root',
'dbname' => 'asharis_database'
);
$config = Setup::createAnnotationMetadataConfiguration($paths, $isDevMode);
$driver = new AnnotationDriver(new AnnotationReader(), $paths);
// registering noop annotation autoloader - allow all annotations by default
AnnotationRegistry::registerLoader('class_exists');
$config->setMetadataDriverImpl($driver);
$entityManager = EntityManager::create($dbParams, $config);
try {
$entityManager->getConnection()->connect();
} catch (\Exception $e) {
echo 'Connection failed !';
}
$users=array();
$post=array();
for($u=1;$u<=3;$u++) {
$user=new AppBundle\Entity\User();
$users[]=$user;
try {
$entityManager->persist($user);
} catch (\Exception $e) {
var_dump($e);
}
And here is the content of User.php :
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validation\Constraints as Assert;
/**
* #ORM\Entity
* #ORM\Table(name="user")
*
**/
class User
{
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\OneToMany(
* targetEntity="Comment",
* mappedBy="post",
* orphanRemoval=true
* )
*
*/
private $comments;
/**
* #ORM\OneToMany(
* targetEntity="Post",
* mappedBy="post",
* orphanRemoval=true
* )
*
*/
private $posts;
/**
* Constructor
*/
public function __construct()
{
$this->comments = new \Doctrine\Common\Collections\ArrayCollection();
$this->posts = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Add comment
*
* #param \AppBundle\Entity\Comment $comment
*
* #return User
*/
public function addComment(\AppBundle\Entity\Comment $comment)
{
$this->comments[] = $comment;
return $this;
}
/**
* Remove comment
*
* #param \AppBundle\Entity\Comment $comment
*/
public function removeComment(\AppBundle\Entity\Comment $comment)
{
$this->comments->removeElement($comment);
}
/**
* Get comments
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getComments()
{
return $this->comments;
}
/**
* Add post
*
* #param \AppBundle\Entity\Posts $post
*
* #return User
*/
public function addPost(\AppBundle\Entity\Posts $post)
{
$this->posts[] = $post;
return $this;
}
/**
* Remove post
*
* #param \AppBundle\Entity\Posts $post
*/
public function removePost(\AppBundle\Entity\Posts $post)
{
$this->posts->removeElement($post);
}
/**
* Get posts
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getPosts()
{
return $this->posts;
}
}
Any help appreciated.
"user" is a reserved key word in most database systems.
But that's why you don't see issues when validating your scheme but get issues later on.
I personally had the case that I was able to even create my schema, but when I used DQL I got some issues.
So you have to avoid or handle the "reserved key word". You have two options:
1)
Rename your class or at least give it a different database table name by:
/**
* #ORM\Entity
* #ORM\Table(name="myapp_user")
*
**/
2)
You could also use Doctrine's way to handle reserved keywords (see documentation):
/**
* #ORM\Entity
* #ORM\Table(name="'user'")
*
**/
But I personally don't recommend the second option.
See as well this section about known limitations in Doctrine around your issue here
Small note: I am assuming that you aren't using the FOS User Bundle - in that case your user would need to extend the BaseUser class additionally.
I am using VichUploader to upload files within a symfony project. In configuration i use (copied from documentation):
service: vich_uploader.namer_property
options: { property: 'slug'}
In my entity i generate the slugs automatically with Gedmo/Sluggable:
/**
* #Gedmo\Slug(fields={"title"}, updatable=false)
* #ORM\Column(type="string", length=100, nullable=false)
*/
protected $slug;
But when trying to save the entity i get the following error 500:
File name could not be generated: property slug is empty.
If i set the property to 'title' it works. Did i forget a configuration parameter or something else to get it working with the Gedmo slug?
I'm having the same issue at the moment, as a workaround, I've slightly changed the slug getter in the entity class:
use Gedmo\Sluggable\Util\Urlizer;
class Event
{
// ...
/**
* #var string
*
* #Gedmo\Slug(fields={"name"})
* #ORM\Column(name="slug", type="string", length=128, unique=true)
*/
private $slug;
// ...
public function getSlug()
{
if (!$this->slug) {
return Urlizer::urlize($this->getName());
}
return $this->slug;
}
}
That did the trick.
Unfortunately, there're a couple of drawbacks:
If you ever want to update sluggable behaviour in the annotation to include additional properties, you'll have to update the getter as well.
This method lacks a check against the database: if there's already a record in the database with the same name urlizer in the getter won't be able to add an increment to the file name, previously saved file may be overwritten! As a workaround, you can add unique=true to sluggable properties.
VichUploader listens to the prePersist and preUpdate events, whereas Sluggable listens to the onFlush event. Because prePersist and preUpdate are called before onFlush, it isn't possible to do this purely using configuration.
However, if your file field is nullable, you can work around it by changing your controller code. When you receive the submitted form with the file, remove the file, save the entity, then re-add the file and save the entity again. On the second save, the slug will already be set, so VichUploader will be able to save the file fine.
if ($form->isSubmitted() && $form->isValid()) {
if ($file = $entity->getFile()) {
$entity->setFile(null);
}
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
if ($file) {
$entity->setFile($file);
$em->persist($entity);
$em->flush();
}
// ...
}
This only works when adding a new file. If you subsequently change the slug and resave the entity without uploading a new file, the filename is not updated.
I was having the same problem uploading a document for which I needed the fileName to be the slug.
I was using Gedmo annotations to generate the slug, however this only triggers on flush and the vichUploader namer is triggered upon persist.
The easiest way for me to get this working was to not use the Gedmo\Sluggable annotation but rather create a prePersist listener on my Document object and use the Cocur\Slugify library.
So here is the code.
My Document Entity:
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Timestampable\Traits\TimestampableEntity;
use Symfony\Component\HttpFoundation\File\File;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
/**
* #ORM\Entity(repositoryClass="App\Repository\DocumentRepository")
* #Vich\Uploadable
* #ORM\EntityListeners({"App\Listeners\DocumentListener"})
*/
class Document
{
use TimestampableEntity;
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=100, nullable=false)
*/
private $fileName;
/**
* #Vich\UploadableField(mapping="document", fileNameProperty="fileName")
* #var File
*/
private $documentFile;
/**
* #ORM\Column(type="string", length=100, unique=true)
*/
private $slug;
/**
*/
public function getDocumentFile(): ?File
{
return $this->documentFile;
}
/**
* #param File $documentFile
* #return Document
* #throws \Exception
*/
public function setDocumentFile(File $documentFile = null): Document
{
$this->documentFile = $documentFile;
if($documentFile){
$this->updatedAt = new \DateTimeImmutable();
}
return $this;
}
public function getId(): ?int
{
return $this->id;
}
public function getSlug(): ?string
{
return $this->slug;
}
public function setSlug(string $slug): self
{
$this->slug = $slug;
return $this;
}
/**
* #return mixed
*/
public function getFileName()
{
return $this->fileName;
}
/**
* #param mixed $fileName
*/
public function setFileName($fileName): void
{
$this->fileName = $fileName;
}
}
And the listener :
namespace App\Listeners;
use App\Entity\Document;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Cocur\Slugify\Slugify;
class DocumentListener
{
public function prePersist(Document $document, LifecycleEventArgs $args)
{
$slugify = new Slugify();
if(!empty($document->getDocumentFile())){
$originalName = pathinfo($document->getDocumentFile()->getClientOriginalName(), PATHINFO_FILENAME);
$slug = $slugify->slugify($originalName);
$document->setSlug($slug);
}
}
}
So far I have not had any problems.
Let me know if this works for you
By default the doctrine extensions bundle does not attach any listener:
http://symfony.com/doc/current/bundles/StofDoctrineExtensionsBundle/index.html#activate-the-extensions-you-want
You should configure it to get sluggable working:
stof_doctrine_extensions:
orm:
default:
sluggable: true
I use Doctrine with Gedmo extension in standalone noframework application.
Autoloading is done via composer, composer.json content:
{
"autoload": {
"psr-0": {
"App": "src"
}
},
"require": {
"doctrine/orm": "^2.5",
"gedmo/doctrine-extensions": "^2.4"
}
}
App core classes are placed in /src directory, composer files are placed in /vendor
Doctrine is configured via factory, its main code is below:
<?php
namespace App\Factory;
use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\Annotations\AnnotationRegistry;
use Doctrine\Common\Annotations\CachedReader;
use Doctrine\Common\Cache\CacheProvider;
use Doctrine\Common\Cache\FileCache;
use Doctrine\Common\EventManager;
use Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain;
use Doctrine\ORM\Configuration;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Mapping\Driver\AnnotationDriver;
class DoctrineFactory implements FactoryInterface
{
/**
* #param ContainerInterface $c
* #return mixed
*/
public function __invoke(ContainerInterface $c)
{
// Set up caches
$cache = new FileCache('runtime/cache/doctrine');
// Annotation reader
$annotationReader = new AnnotationReader;
$cachedAnnotationReader = new CachedReader($annotationReader, $cache);
AnnotationRegistry::registerLoader(array(require 'vendor/autoload.php', 'loadClass'));
// Add Gedmo extensions
$driverChain = new MappingDriverChain();
\Gedmo\DoctrineExtensions::registerAbstractMappingIntoDriverChainORM($driverChain, $cachedAnnotationReader);
// Set up driver to read annotations from entities
$annotationDriver = new AnnotationDriver($cachedAnnotationReader, 'src'));
$driverChain->addDriver($annotationDriver, 'App\Entity');
// General doctrine configuration
$doctrineConfig = new Configuration;
$doctrineConfig->setProxyDir(sys_get_temp_dir()));
$doctrineConfig->setProxyNamespace('App\Entity\Proxy');
$doctrineConfig->setAutoGenerateProxyClasses(false);
$doctrineConfig->setMetadataDriverImpl($driverChain);
$doctrineConfig->setMetadataCacheImpl($cache);
$doctrineConfig->setQueryCacheImpl($cache);
// Event manager to hook extensions
$evm = new EventManager();
// Tree extension
$treeListener = new \Gedmo\Tree\TreeListener;
$treeListener->setAnnotationReader($cachedAnnotationReader);
$evm->addEventSubscriber($treeListener);
// Create EntityManager
// $config['conn'] is connection credentials
return EntityManager::create($config['conn'], $doctrineConfig, $evm);
}
}
My entity is:
<?php
namespace App\Entity;
use \Doctrine\ORM\Mapping as ORM;
use \Gedmo\Mapping\Annotation as Gedmo;
/**
* Class ProductCategory2
* #package App\Entity
*
* #Gedmo\Tree(type="nested")
* #ORM\Entity(repositoryClass="Gedmo\Tree\Entity\Repository\NestedTreeRepository")
*/
class ProductCategory2
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue
*/
private $id;
/**
* #ORM\Column(type="string", length=50)
*/
private $name;
/**
* #Gedmo\TreeLeft
* #ORM\Column(type="integer")
*/
private $lft;
/**
* #Gedmo\TreeLevel
* #ORM\Column(type="integer")
*/
private $lvl;
/**
* #Gedmo\TreeRight
* #ORM\Column(type="integer")
*/
private $rgt;
/**
* #Gedmo\TreeRoot
* #ORM\Column(type="integer", nullable=true)
* #var
*/
private $root;
/**
* #Gedmo\TreeParent
* #ORM\ManyToOne(targetEntity="ProductCategory2", inversedBy="children")
*/
private $parent;
}
My cli-config.php is configured properly.
I run doctrine cli tool to generate entities boilerplate code via command:
“vendor/bin/doctrine” orm:generate-entities src
It answers me:
Processing entity
“Gedmo\Translatable\Entity\MappedSuperclass\AbstractPersonal\Translation”
Processing entity
“Gedmo\Translatable\Entity\MappedSuperclass\AbstractTranslation”
Processing entity “Gedmo\Loggable\Entity\MappedSuperclass\AbstractLogEntry”
Processing entity “Gedmo\Tree\Entity\MappedSuperclass\AbstractClosure”
Processing entity “App\Entity\ProductCategory2”
Entity’s working fine, but command adds extra files into my src folder:
src\Gedmo
├───Loggable
│ └───Entity
│ └───MappedSuperclass/AbstractLogEntry.php
├───Translatable
│ └───Entity
│ └───MappedSuperclass/AbstractTranslation.php
└───Tree
└───Entity
└───MappedSuperclass/AbstractClosure.php
If I generate entities one more time via aforementioned command, I get error.
PHP Fatal error: Cannot redeclare class
Gedmo\Loggable\Entity\MappedSuperclass\AbstractLogEntry in
\src\Gedmo\Loggable\Entity\MappedSuperclass\AbstractLogEntry.php
on line 9
To fix it, I need remove <ROOT>/src/Gedmo dir before.
May anybody help to find a bug in config to prevent this annoying extra files to be appeared?
Thank for help
I've added hack to clear annoying directory after doctrine generate-entities command. Complete listing of cli-config.php is below:
<?php
use Doctrine\ORM\Tools\Console\ConsoleRunner;
use Interop\Container\ContainerInterface;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\ConsoleEvents;
use Symfony\Component\Console\Event\ConsoleTerminateEvent;
use Symfony\Component\EventDispatcher\EventDispatcher;
require "vendor/autoload.php";
/** #var ContainerInterface $container */
$container = require 'app/bootstrap.php';
$dispatcher = new EventDispatcher();
// Post terminate cli command listener
$dispatcher->addListener(ConsoleEvents::TERMINATE, function(ConsoleTerminateEvent $event) {
$commandName = $event->getCommand()->getName();
switch($commandName) {
case 'orm:generate-entities':
// clear /src/Gedmo dir
\App\Utils\FilesystemUtils::removeDir('src/Gedmo');
break;
}
});
// Create doctrine cli environment via helper
$helperSet = ConsoleRunner::createHelperSet($container->get(\Doctrine\ORM\EntityManager::class));
// Wrap it into Symfony Console App and add some extra commands
$app = new Application('Doctrine Command Line Interface', \Doctrine\ORM\Version::VERSION);
$app->setDispatcher($dispatcher);
$app->setCatchExceptions(true);
$app->setHelperSet($helperSet);
// add default commands
ConsoleRunner::addCommands($app);
// here you may add extra commadts via $app->add(..)
$app->run();
Official docs:
How to wrap doctrine cli command into symfony console app
How to inject event system into symfony console app
I would like to ask, if anybody obtained such error before. Since I am stuck for 2 hours fixing bugs with doctrine already. So any kind of of help would be appreciate.
To the point. I am fighting with doctrine Entity Manager I can't make it work.
I created entity and doctrine class to work with, but I am getting an error all the time:
Fatal error: Uncaught exception 'Doctrine\ORM\Mapping\MappingException' with message 'Class "MSP\Model\Entity\Category" is not a valid entity or mapped super class.' in /home/dariss/www/dom/php/MenuSiteProject/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/MappingException.php:216 Stack trace: #0 /home/dariss/www/dom/php/MenuSiteProject/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php(87): Doctrine\ORM\Mapping\MappingException::classIsNotAValidEntityOrMappedSuperClass('MSP\Model\Entit...') #1 /home/dariss/www/dom/php/MenuSiteProject/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php(113): Doctrine\ORM\Mapping\Driver\AnnotationDriver->loadMetadataForClass('MSP\Model\Entit...', Object(Doctrine\ORM\Mapping\ClassMetadata)) #2 /home/dariss/www/dom/php/MenuSiteProject/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/AbstractClassMetadataFactory.php(318): Doctrine\ORM\Mapping\ClassMetadataFactory->doLoadMetadata(Object(Doctrine\ORM\Mapping\ClassMetadata), NULL, false, Array) in /home/dariss/www/dom/php/MenuSiteProject/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/MappingException.php on line 216
My entity class.
namespace MSP\Model\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Category
*
* #ORM\Entity
* #ORM\Table(name="category")
*/
class Category {
/**
* #var integer $id
*
* #ORM\Column(name="id", type="int", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="SEQUENCE")
* #ORM\SequenceGenerator(sequenceName="category_id_seq", allocationSize=1, initialValue=1)
*/
private $id;
/**
* #var String $name
*
* #ORM\Column(name="name", type"string", length=50, nullable=true)
*/
private $name;
/**
* #var integer $parent
*
* #ORM\Column(name="parent", type="int", nullable=true)
*/
private $parent;
/**
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* #param $name
* #return Category
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* #return String
*/
public function getName()
{
return $this->name;
}
/**
* #param int $parent
* #return Category
*/
public function setParent($parent)
{
$this->parent = $parent;
return $this;
}
/**
* #return int
*/
public function getParent()
{
return $this->parent;
}
Doctrine class:
namespace MSP\Helper;
use Doctrine\Common\ClassLoader,
Doctrine\ORM\Configuration,
Doctrine\ORM\EntityManager,
Doctrine\Common\Cache\ArrayCache,
Doctrine\DBAL\Logging\EchoSQLLogger;
class Doctrine{
public $em = null;
public function __construct()
{
require_once __DIR__.'/../../../vendor/doctrine/common/lib/Doctrine/Common/ClassLoader.php';
$doctrineClassLoader = new ClassLoader('Doctrine', '/');
$doctrineClassLoader->register();
$entitiesClassLoader = new ClassLoader('MSP\Model\Entity', '/../Model/Entity');
$entitiesClassLoader->register();
$proxiesClassLoader = new ClassLoader('Proxies', '/../Proxies/');
$proxiesClassLoader->register();
// Set up caches
$config = new Configuration;
$cache = new ArrayCache;
$config->setMetadataCacheImpl($cache);
$driverImpl = $config->newDefaultAnnotationDriver(array('/../Model/Entity'), true);
$config->setMetadataDriverImpl($driverImpl);
$config->setQueryCacheImpl($cache);
$config->setQueryCacheImpl($cache);
// Proxy configuration
$config->setProxyDir('/proxies');
$config->setProxyNamespace('Proxies');
// Set up logger
$logger = new EchoSQLLogger;
//$config->setSQLLogger($logger);
$config->setAutoGenerateProxyClasses( TRUE );
$iniParser = new \MSP\Helper\IniParser();
$configuration = $iniParser->getConfig();
// Database connection information
$connectionOptions = array(
'driver' => $configuration['driver'],
'user' => $configuration['username'],
'password' => $configuration['password'],
'dbname' => $configuration['dbname'],
'host' => $configuration['host']
);
// Create EntityManager
$this->em = EntityManager::create($connectionOptions, $config);
}
}
Test file:
$doctrine = new MSP\Helper\Doctrine();
$doctrine->em->find('MSP\Model\Entity\Category', 1);
You need to drop the #ORM prefixes when you annotate the entities.
But I followed the example in the Symfony 2 documentation? Yep. For Symfony 2 you need to use #ORM. But your test cases uses "pure" doctrine which means no #ORM.
If you really need to run your stuff using pure doctrine then consider using yaml notation.
Why does S2 use #ORM? It's a long sad story but basically it introduced the #ORM prefix so other annotations would not clash with Doctrine.
Can you tweak the Doctrine configuration to allow the user of #ORM? Yep. But I forget how. You can search for it.
Bottom line: Consider just using the Symfony 2 Doctrine service. It's easier.
You set an absolute path /../Model/Entity.
You need to set ./../Model/Entity