13

I'm working on a CodeIgniter project in which I'm using Doctrine2 and the Symfony2 Validator component.

All my Doctrine2 entities use Doctrine\ORM\Mapping and the entity manager recognizes them. My entity annotation looks like this:

/**
 * @Entity(repositoryClass = "UserRepository")
 * @Table(name = "user")
 * @HasLifecycleCallbacks()
 */

At this point, I'm able to persist entities without any trouble. The first problem arises when I try to use the Symfony2 Validator component. When I try to validate a User object, I get this error:

[Semantical Error] The annotation "@Entity" in class Entity\User was never imported. Did you maybe forget to add a "use" statement for this annotation?

The only "fix" to this issue is through use Doctrine\Mapping\Entity, but I have to do that for every annotation being used by my entity (Table, Column, ManyToOne, etc.). I'm trying to figure out why I need to explicitely use each annotation class instead of them being automatically recognized (shouldn't use Doctrine\ORM\Mapping grant me access to all the classes within that namespace?).

So, I then tried use Doctrine\ORM\Mapping as ORM and prefacing all my annotations with ORM\. Ex: @ORM\Entity(). The Symfony2 validator stops complaining, but now Doctrine2 complains that Class Entity\User is not a valid entity or mapped super class. I have no idea why this method works for the Validator, but not Doctrine2. If I run the console command doctrine:orm:info, my User entity is not recognized.

Because this is a CodeIgniter app, I'm autoloading the Symfony2 and Doctrine2 libraries. My autoload code is as follows:

# Symfony2 ClassLoader component
require_once __DIR__ . '/application/libraries/symfony/src/Symfony/Component/ClassLoader/UniversalClassLoader.php';
$loader = new \Symfony\Component\ClassLoader\UniversalClassLoader();
$loader->register();
$loader->registerNamespace('Symfony', __DIR__ . '/application/libraries/symfony/src');
$loader->registerNamespace('Doctrine', __DIR__ . '/application/libraries/doctrine/lib');

# Doctrine2 
require_once __DIR__ . '/application/libraries/doctrine/lib/Doctrine/Common/Annotations/AnnotationRegistry.php';
use Doctrine\Common\Annotations\AnnotationRegistry;
AnnotationRegistry::registerLoader(function($class) use ($loader) {
    $loader->loadClass($class);
    $classExists = class_exists($class, false);
    return $classExists;
});
AnnotationRegistry::registerFile(__DIR__ . '/application/libraries/doctrine/lib/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php');

I don't care if I have to preface everything with ORM\ or not, I just want to find a solution that the Symfony2 Validator and Doctrine2 will both work with. Any ideas?

Steven Mercatante
  • 24,757
  • 9
  • 65
  • 109

8 Answers8

24

I had a similar issue when using Silex, Doctrine2 and the Symfony-Validator.

The solution was to avoid using the SimpleAnnotationsReader and instead using the normal AnnotationReader (have a look at Doctrine\ORM\Configuration::newDefaultAnnotationDriver). You can then preface every entity with ORM\ (and of course inserting use Doctrine\ORM\Mapping as ORM; in every entity).

grim
  • 6,669
  • 11
  • 38
  • 57
user1825294
  • 356
  • 3
  • 4
  • 1
    What about the case where it worked without `ORM\ ` so we coded every entity that way, now all of a sudden it stops working for no reason and we're left with a maintenance nightmare? – Brandon Jan 23 '17 at 19:41
  • Just to answer Brandon's question and to save other people the time of finding it out themselves: if your codebase uses Doctrine annotations without importing the `Doctrine\ORM\Mapping` namespace, then you are married to Doctrine's SimpleAnnotationReader, which means you can't _just_ start using namespace-imported annotation and refactor your code incrementally. Well, at least not without hacking the AnnotationReader (which is the one that parses the `use` statements). – d-ph Aug 23 '18 at 08:53
14

I resolved this issue by adding the following to my entity file:

use Doctrine\ORM\Mapping as ORM;

So my file now looks like:

<?php

namespace Acme\CustomBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Example
 *
 * @ORM\Entity
 * @ORM\Table(name="example")
 *
 */
class Example
{
    /**
     * @ORM\Column(type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     *
     * @var integer
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=125)
     *
     * @var string
     */
    private $title;

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

    /**
     * Set title
     *
     * @param string $title
     *
     * @return Example
     */
    public function setTitle($title)
    {
        $this->title = $title;

        return $this;
    }

    /**
     * Get title
     *
     * @return string
     */
    public function gettitle()
    {
        return $this->title;
    }

}
ajtrichards
  • 29,723
  • 13
  • 94
  • 101
  • 1
    This didn't work for specifically needing the id annotation. I had to specify it individually as @Mostafa's answer was showing. – Jestep Oct 26 '17 at 19:33
  • My reference was https://www.doctrine-project.org/projects/doctrine-orm/en/2.7/reference/inheritance-mapping.html#single-table-inheritance, I just have to add `ORM\` so: /** * @ORM\Entity * @ORM\InheritanceType("SINGLE_TABLE") */ class Person – bcag2 Oct 13 '20 at 14:28
5

Add use statements for every annotation you have used in your entities. for example:

use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\Table;
use Doctrine\ORM\Mapping\Id;
use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\GeneratedValue;

But you may not interesting to use this method. You can write all use statements to one file and just include it in your entities.

Mostafa Lavaei
  • 1,960
  • 1
  • 18
  • 27
3

Had the same issue when php7 got upgraded to php8 during an ubuntu update. I didn't want to update all my project dependencies to php8, so instead I installed ondrej/php ppa and re-installed php7 in addition to php8.

marrco
  • 128
  • 7
1

I was getting the same error message "[Semantical Error] The annotation "@Entity" in class Entity\User was never imported. Did you maybe forget to add a "use" statement for this annotation?".

The problem was that I had alias for ORM and did not used it for the annotation.

I had this: @OneToOne(targetEntity="CompanyProduct")

And correct was this: @ORM\OneToOne(targetEntity="CompanyProduct")

Ales
  • 381
  • 6
  • 8
0

If you are testing and your tests fail because of this. Make sure you have the right autoload configured in your phpunit settings.

For a very specific scenario, my problem was upgrading my symfony version whereas before i had the bootstrap.cache.php file, but on a new version, it is app/autoload. I had to change my phpunit.xml config file and set my bootstrap option to that file bootstrap="autoload.php"

Luis Lopes
  • 506
  • 4
  • 14
0

My problem solved by adding:

use Doctrine\ORM\Mapping\HasLifecycleCallbacks;

Mostafa
  • 815
  • 1
  • 13
  • 23
0

Ugly solution

I am learning doctrine and what matters to me at this stage is that I can easily copy/paste examples from the website and use them without additional edits.

  • Set the namespace like this for all entities: namespace Doctrine\ORM\Mapping;
beppe9000
  • 1,056
  • 1
  • 13
  • 28