[BUG] Semantic Error on annotations after upgrading to Laravel 9
akalongman opened this issue · comments
Package version, Laravel version
Laravel 9
beberlei/doctrineextensions v1.3.0
doctrine/annotations 1.14.2
doctrine/cache 1.13.0
doctrine/collections 1.8.0
doctrine/common 3.4.3
doctrine/data-fixtures 1.6.3
doctrine/dbal 2.13.9
doctrine/deprecations v0.5.3
doctrine/event-manager 1.2.0
doctrine/inflector 2.0.6
doctrine/instantiator 1.5.0
doctrine/lexer 1.2.3
doctrine/migrations 3.4.2
doctrine/orm 2.14.0
doctrine/persistence 2.5.6
gedmo/doctrine-extensions v3.10.0
laravel-doctrine/extensions 1.5.1
laravel-doctrine/migrations 3.x-dev b096637
laravel-doctrine/orm 1.8.1
ramsey/uuid-doctrine 1.8.2
PHP Version:
PHP 8.1.14 (cli) (built: Jan 6 2023 15:22:56) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.1.14, Copyright (c) Zend Technologies
with Zend OPcache v8.1.14, Copyright (c), by Zend Technologies
with Xdebug v3.2.0, Copyright (c) 2002-2022, by Derick Rethans
Expected behaviour
It was working on Laravel 8
Actual behaviour
When I run anything related to Entities, I am getting this error: Doctrine\Common\Annotations\AnnotationException : [Semantical Error] The annotation "@Doctrine\ORM\Mapping\Entity" in class App\Domain\Models\Identity\User was never imported. Did you maybe forget to add a "use" statement for this annotation?
For example php artisan doctrine:info
Steps to reproduce the behaviour
My Entity looks like:
<?php
declare(strict_types=1);
namespace App\Domain\Models\Identity;
use App;
use App\Domain\Entity;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Illuminate\Auth\Authenticatable;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Ramsey\Uuid\UuidInterface;
/**
* @ORM\Entity
* @ORM\Table(
* name="users",
* indexes={
* @ORM\Index(name="idx_email", columns={"email"}),
* @ORM\Index(name="idx_type", columns={"type"}),
* },
* )
* @Gedmo\Loggable
*/
class User extends Entity implements AuthenticatableContract
{
use Authenticatable;
/**
* @ORM\Id
* @ORM\Column(type="uuid_binary")
*/
protected UuidInterface $id;
/**
* @Gedmo\Versioned
* @ORM\Column(type="string")
*/
protected string $email;
/**
* @Gedmo\Versioned
* @ORM\Column(type="string")
*/
protected string $type;
public function id(): UuidInterface
{
return $this->id;
}
}
could you also detail php version, and what command/request is generating the error
@dpslwk I've updated the post, thank you
one last thing can you add the same package version as up had them in Laravel 8 (assuming that was unto date composer update
@dpslwk sure. Versions before upgrade:
beberlei/doctrineextensions v1.3.0
doctrine/annotations 1.13.2
doctrine/cache 1.12.1
doctrine/collections 1.6.8
doctrine/common 3.2.2
doctrine/data-fixtures 1.5.2
doctrine/dbal 2.13.7
doctrine/deprecations v0.5.3
doctrine/event-manager 1.1.1
doctrine/inflector 1.4.4
doctrine/instantiator 1.4.0
doctrine/lexer 1.2.3
doctrine/migrations 2.3.5
doctrine/orm 2.11.1
doctrine/persistence 2.3.0
gedmo/doctrine-extensions v3.5.0
laravel-doctrine/extensions 1.5.0
laravel-doctrine/migrations 2.3.1
laravel-doctrine/orm 1.7.13
ramsey/uuid-doctrine 1.8.1
do you also have laravel-doctrine/acl
??
cause I'm able to reproduce this error on a l8 test project
@dpslwk no, I have not laravel-doctrine/acl
package
@akalongman Did you figure out something after using xdebug?
@eigan not yet :(
ok I have two possible sources of issue
laravel-doctrine/acl
gedmo/doctrine-extensions
something todo with doctrine/annotations
and the use of AnnotationRegistry
or AnnotationLoader
doctrine/annotations
is now at v2.0 and has remove AnnotationRegistry, it was already deprecated in favour or autoloading
With php 8+ introduction native attributes that is now preferred over annotations for doctrine mappings
From a laravel-doctrine project point of view, I think we have some work to do adding attribute mapping support into ACL and Extensions, then updating the docs to show attributes not annotations in the example
Unfortunately my project that uses Laravel-dcotrine is using yaml mappings so its not an issue I hit and I think @eigan uses xml in his projects
@dpslwk what could you suggest to me for now? Can I use PHP8 annotations instead of doc-blocks? Or I can use YAML/XML mappings? I should upgrade the project to Laravel 9, so I am searching the possible solutions
We do not use XML but annotations.
I have tried to add the laravel-doctrine/extensions package but still not able to reproduce. If you could reproduce this in a new project, please submit it to github or similar so I can use xdebug to trace it down.
This is my env:
beberlei/doctrineextensions v1.3.0
doctrine/annotations 1.14.2
doctrine/cache 1.13.0
doctrine/collections 1.8.0
doctrine/common 3.4.3
doctrine/dbal 2.13.9
doctrine/deprecations v0.5.3
doctrine/event-manager 1.2.0
doctrine/inflector 2.0.6
doctrine/instantiator 1.5.0
doctrine/lexer 1.2.3
doctrine/migrations 3.4.2
doctrine/orm 2.13.4
doctrine/persistence 2.5.6
gedmo/doctrine-extensions v3.10.0
laravel-doctrine/extensions 1.5.1
laravel-doctrine/migrations 3.x-dev b096637
laravel-doctrine/orm 1.8.1
Noticed you are a bit behind on doctrine/orm, try upgrade? Nope, you are not. Read wrong dependency list.
EDIT: I have updated to doctrine/orm 2.14, no issue here either.
@dpslwk what could you suggest to me for now? Can I use PHP8 annotations instead of doc-blocks? Or I can use YAML/XML mappings? I should upgrade the project to Laravel 9, so I am searching the possible solutions
I ran into the same problem recently and worked around it by providing my own loader
\App\Providers\AnnotationsServiceProvider::register
AnnotationRegistry::registerLoader([
new DoctrineAnnotationLoader(),
'loadClass',
]);
AnnotationRegistry::loadAnnotationClass(Entity::class);
\App\Doctrine\Mappings\DoctrineAnnotationLoader
namespace App\Doctrine\Mappings;
/**
* Autoloader for Doctrine Annotations
* @note This should not be necessary
* @deprecated Laravel-Doctrine _should_ provide autoloading at some point
*/
class DoctrineAnnotationLoader
{
/**
* @const
*/
const ANNOTATION_NAMESPACE = 'Doctrine\\ORM\\Mapping\\';
/**
* @const
*/
const ANNOTATION_PATH = 'vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/';
/**
* @param $class
*
* @return mixed
*/
public function loadClass($class)
{
if (strpos($class, self::ANNOTATION_NAMESPACE) === 0) {
$class = str_replace(self::ANNOTATION_NAMESPACE, '', $class);
$file = base_path(self::ANNOTATION_PATH) . $class . '.php';
if (file_exists($file)) {
require_once $file;
return true;
}
}
}
}
Also encountered this issue when upgrading from laravel 8 / laravel-doctrine 1.7 to laravel 9 laravel-doctrine-orm 1.8.
In my config the problem only occurs when some extensions are enabled in the doctrine.php config file:
'extensions' => [
LaravelDoctrine\Extensions\Timestamps\TimestampableExtension::class,
LaravelDoctrine\Extensions\SoftDeletes\SoftDeleteableExtension::class,
],
No more errors after disabling the extensions. I did no do any further testing, so I'm not sure what causes the problem. I hope you can do some further debugging with this information @eigan.
Composer
"php": "^8.0.2",
"gedmo/doctrine-extensions": "^3.0",
"guzzlehttp/guzzle": "^7.2",
"laravel-doctrine/extensions": "1.5.*",
"laravel-doctrine/migrations": "*",
"laravel-doctrine/orm": "~1.8",
"laravel/framework": "^9.0",
Example class
<?php
namespace App\Models;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\Table(name="tests")
* @ORM\Entity(repositoryClass="App\Repositories\TestRepository")
*/
class Test
{
/**
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
* @ORM\Column(type="integer")
*/
protected int $id;
/**
* @var string
* @ORM\Column(type="string")
*/
protected string $name;
}
I think this issue occurs with PHP 8.1 and a conflict with annotations vs attributes. I just started a new Laravel 9 project and was served up a sail system with PHP 8.1. Laravel says it prefers ^8.0.2.
I notice laravel-doctrine/orm is using a quite old version of doctrine/annotations, 1.14.2 and I am unsure if this supports PHP attributes. When I use attributes, the error disappears, but my entities are not detected.
So the solution may be to use PHP 8.0. But I think I'll have a look at what @whizzrd suggested above: #537 (comment)
Confirming the solution proposed by @whizzrd did solve the problem.
Thank you Joris.
After some xdebugging I found the problem.
Gedmo uses the AnnotationRegistry::registerFile
which toggles the bool AnnotationRegistry$registerFileUsed
. This causes AnnotationRegistry::loadAnnotationClass()
to go into a mode where it expects all annotations to be loaded in a different manner, and not autoloaded. This behaviour from Gedmo was changed here doctrine-extensions/DoctrineExtensions#2558
To fix this on our side should we copy the latest version of Gedmo\DoctrineExtensions
until they release a new version whith these changes?
we use AnnotationRegistry::registerLoader
in laravel-doctrine/acl/src/AclServiceProvider.php
so I'm sure ACL is also to be effected by the changes in doctrine/annotations
An easier solution would be to just add class_exists
loader like this:
AnnotationRegistry::registerLoader('class_exists');
This can replace your loader @whizzrd.
Should we wait for fixes from https://github.com/doctrine-extensions/DoctrineExtensions ?
I have released new versions for both extensions and acl libs. Please see if that fixes it for you.
@eigan Works for me 🫶
beberlei/doctrineextensions v1.3.0
doctrine/annotations 1.14.2
doctrine/cache 1.13.0
doctrine/collections 1.8.0
doctrine/common 3.4.3
doctrine/dbal 2.13.9
doctrine/deprecations v0.5.3
doctrine/event-manager 1.2.0
doctrine/inflector 2.0.6
doctrine/instantiator 1.5.0
doctrine/lexer 1.2.3
doctrine/migrations 3.4.2
doctrine/orm 2.14.0
doctrine/persistence 2.5.6
gedmo/doctrine-extensions v3.10.0
laravel-doctrine/acl 1.6.1
laravel-doctrine/extensions 1.5.2
laravel-doctrine/migrations 3.x-dev b096637
laravel-doctrine/orm 1.8.1
It looks like it's working now! 😍