laravel-doctrine / orm

A drop-in Doctrine ORM 2 implementation for Laravel 5+ and Lumen

Home Page:http://laraveldoctrine.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[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?

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.

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! 😍

Confirming its working for me too.

Thanks @eigan