JWTRefreshTokenBundle icon indicating copy to clipboard operation
JWTRefreshTokenBundle copied to clipboard

No identifier/primary key specified for Entity "App\Entity\RefreshToken"

Open edebertJurisoft opened this issue 3 years ago • 11 comments

Hello,

I have a mistake about property in id in RefreshToken : No identifier/primary key specified for Entity "App\Entity\RefreshToken" sub class of "Gesdinet\JWTRefreshTokenBundle\Entity\RefreshToken". Every Entity must have an identifier/primary key.

This mistake is not there all time.

I try overload id in my Entity RefreshToken. Do you have a solution ?

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use Gesdinet\JWTRefreshTokenBundle\Entity\RefreshToken as BaseRefreshToken;

/**
 * @ORM\Entity
 * @ORM\Table("refresh_tokens")
 */
class RefreshToken extends BaseRefreshToken
{

   protected $id;


    public function getId()
    {
        return $this->id;
    }
}

Configuration Php version : 8.0.22 Symfony : 5.4 jwt-refresh-token-bundle : 1.1.1 lexik/jwt-authentication-bundle: 2.16.0 I don't use attributes php8.

edebertJurisoft avatar Aug 22 '22 10:08 edebertJurisoft

Got the same issue here.

It happens when the cache is clearing with the following command:

php bin/console cache:clear

I also tried to override the id attribute and give him annotations to define it as a primary key

#[ ORM\Id, ORM\GeneratedValue, ORM\Column(type:"integer") ] protected $id;

But then I get the following issue:

Duplicate definition of column 'id' on entity 'App\Entity\RefreshToken' in a field or discriminator column mapping.

I guess it means that somehow, somewhere, the id attribute is defined as the primary key of the entity, but the doctrine mapping doesn't get it. This probably means that we need to define it with the other attributes elsewhere, in the doctrine yaml ?

Configuration : Php version: 8.1.5 Symfony: 6.1 gesdinet/jwt-refresh-token-bundle: ^v1.1.1 lexik/jwt-authentication-bundle: 2.8

vico-gs avatar Aug 22 '22 14:08 vico-gs

Ok, I've found a solution, I believe it's temporary but it works, I create a custom entity extended on AbstractRefreshToken with all attributes clearly described:

namespace App\Entity;

use App\Repository\RefreshTokenRepository;
use DateTimeInterface;
use Doctrine\ORM\Mapping as ORM;
use Gesdinet\JWTRefreshTokenBundle\Model\AbstractRefreshToken;

#[
    ORM\Entity(repositoryClass: RefreshTokenRepository::class),
    ORM\Table(name: 'jwt_refresh_tokens')
]
class JwtRefreshToken extends AbstractRefreshToken
{
    #[
        ORM\Id,
        ORM\GeneratedValue,
        ORM\Column(type:"integer")
    ]
    protected $id;

    #[
        ORM\Column(type: "string", length: 128, nullable: true)
    ]
    protected $refreshToken;

    #[
        ORM\Column(type:"string", length: 255, nullable: true)
    ]
    protected $username;

    #[
        ORM\Column(type:"datetime", nullable: true)
    ]
    protected $valid;
}

I also binded the entity with a repository that implements the RefreshTokenRepositoryInterface and add to it the needed methods. And to change in the gesdinet_jwt_refresh_token.yml:

gesdinet_jwt_refresh_token:
  refresh_token_class: App\Entity\JwtRefreshToken

vico-gs avatar Aug 23 '22 08:08 vico-gs

the same issue here!

eerison avatar Nov 11 '22 14:11 eerison

Could someone help me somehow here :/

it's my exception

{
  "type": "https://tools.ietf.org/html/rfc2616#section-10",
  "title": "An error occurred",
  "status": 500,
  "detail": "Attempted to call an undefined method named \"getId\" of class \"Symfony\\Component\\Security\\Core\\User\\User\".",
  "class": "Symfony\\Component\\ErrorHandler\\Error\\UndefinedMethodError",
  "trace": [
    {
      "namespace": "",
      "short_class": "",
      "class": "",
      "type": "",
      "function": "",
      "file": "/usr/src/app/src/EventListener/JWTCreatedListener.php",
      "line": 13,
      "args": []
    },
    {
      "namespace": "App\\EventListener",
      "short_class": "JWTCreatedListener",
      "class": "App\\EventListener\\JWTCreatedListener",
      "type": "->",
      "function": "onJWTCreated",
      "file": "/usr/src/app/vendor/symfony/event-dispatcher/Debug/WrappedListener.php",
      "line": 126,
      "args": [
        [
          "object",
          "Lexik\\Bundle\\JWTAuthenticationBundle\\Event\\JWTCreatedEvent"
        ],
        [
          "string",
          "lexik_jwt_authentication.on_jwt_created"
        ],
        [
          "object",
          "Symfony\\Component\\HttpKernel\\Debug\\TraceableEventDispatcher"
        ]
      ]
    },
    {
      "namespace": "Symfony\\Component\\EventDispatcher\\Debug",
      "short_class": "WrappedListener",
      "class": "Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener",
      "type": "->",
      "function": "__invoke",
      "file": "/usr/src/app/vendor/symfony/event-dispatcher/EventDispatcher.php",
      "line": 251,
      "args": [
        [
          "object",
          "Lexik\\Bundle\\JWTAuthenticationBundle\\Event\\JWTCreatedEvent"
        ],
        [
          "string",
          "lexik_jwt_authentication.on_jwt_created"
        ],
        [
          "object",
          "Symfony\\Component\\HttpKernel\\Debug\\TraceableEventDispatcher"
        ]
      ]
    },
    {
      "namespace": "Symfony\\Component\\EventDispatcher",
      "short_class": "EventDispatcher",
      "class": "Symfony\\Component\\EventDispatcher\\EventDispatcher",
      "type": "->",
      "function": "callListeners",
      "file": "/usr/src/app/vendor/symfony/event-dispatcher/EventDispatcher.php",
      "line": 73,
      "args": [
        [
          "array",
          [
            [
              "object",
              "Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"
            ]
          ]
        ],
        [
          "string",
          "lexik_jwt_authentication.on_jwt_created"
        ],
        [
          "object",
          "Lexik\\Bundle\\JWTAuthenticationBundle\\Event\\JWTCreatedEvent"
        ]
      ]
    },
    {
      "namespace": "Symfony\\Component\\EventDispatcher",
      "short_class": "EventDispatcher",
      "class": "Symfony\\Component\\EventDispatcher\\EventDispatcher",
      "type": "->",
      "function": "dispatch",
      "file": "/usr/src/app/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php",
      "line": 168,
      "args": [
        [
          "object",
          "Lexik\\Bundle\\JWTAuthenticationBundle\\Event\\JWTCreatedEvent"
        ],
        [
          "string",
          "lexik_jwt_authentication.on_jwt_created"
        ]
      ]
    },
    {
      "namespace": "Symfony\\Component\\EventDispatcher\\Debug",
      "short_class": "TraceableEventDispatcher",
      "class": "Symfony\\Component\\EventDispatcher\\Debug\\TraceableEventDispatcher",
      "type": "->",
      "function": "dispatch",
      "file": "/usr/src/app/vendor/lexik/jwt-authentication-bundle/Services/JWTManager.php",
      "line": 87,
      "args": [
        [
          "object",
          "Lexik\\Bundle\\JWTAuthenticationBundle\\Event\\JWTCreatedEvent"
        ],
        [
          "string",
          "lexik_jwt_authentication.on_jwt_created"
        ]
      ]
    },
    {
      "namespace": "Lexik\\Bundle\\JWTAuthenticationBundle\\Services",
      "short_class": "JWTManager",
      "class": "Lexik\\Bundle\\JWTAuthenticationBundle\\Services\\JWTManager",
      "type": "->",
      "function": "generateJwtStringAndDispatchEvents",
      "file": "/usr/src/app/vendor/lexik/jwt-authentication-bundle/Services/JWTManager.php",
      "line": 67,
      "args": [
        [
          "object",
          "Symfony\\Component\\Security\\Core\\User\\User"
        ],
        [
          "array",
          {
            "roles": [
              "array",
              [
                [
                  "string",
                  "ROLE_USER"
                ]
              ]
            ],
            "email": [
              "string",
              "[email protected]"
            ]
          }
        ]
      ]
    },
    {
      "namespace": "Lexik\\Bundle\\JWTAuthenticationBundle\\Services",
      "short_class": "JWTManager",
      "class": "Lexik\\Bundle\\JWTAuthenticationBundle\\Services\\JWTManager",
      "type": "->",
      "function": "create",
      "file": "/usr/src/app/vendor/lexik/jwt-authentication-bundle/Security/Http/Authentication/AuthenticationSuccessHandler.php",
      "line": 58,
      "args": [
        [
          "object",
          "Symfony\\Component\\Security\\Core\\User\\User"
        ]
      ]
    },
    {
      "namespace": "Lexik\\Bundle\\JWTAuthenticationBundle\\Security\\Http\\Authentication",
      "short_class": "AuthenticationSuccessHandler",
      "class": "Lexik\\Bundle\\JWTAuthenticationBundle\\Security\\Http\\Authentication\\AuthenticationSuccessHandler",
      "type": "->",
      "function": "handleAuthenticationSuccess",
      "file": "/usr/src/app/vendor/lexik/jwt-authentication-bundle/Security/Http/Authentication/AuthenticationSuccessHandler.php",
      "line": 49,
      "args": [
        [
          "object",
          "Symfony\\Component\\Security\\Core\\User\\User"
        ]
      ]
    },
    {
      "namespace": "Lexik\\Bundle\\JWTAuthenticationBundle\\Security\\Http\\Authentication",
      "short_class": "AuthenticationSuccessHandler",
      "class": "Lexik\\Bundle\\JWTAuthenticationBundle\\Security\\Http\\Authentication\\AuthenticationSuccessHandler",
      "type": "->",
      "function": "onAuthenticationSuccess",
      "file": "/usr/src/app/vendor/gesdinet/jwt-refresh-token-bundle/Service/RefreshToken.php",
      "line": 120,
      "args": [
        [
          "object",
          "Symfony\\Component\\HttpFoundation\\Request"
        ],
        [
          "object",
          "Symfony\\Component\\Security\\Guard\\Token\\PostAuthenticationGuardToken"
        ]
      ]
    },
    {
      "namespace": "Gesdinet\\JWTRefreshTokenBundle\\Service",
      "short_class": "RefreshToken",
      "class": "Gesdinet\\JWTRefreshTokenBundle\\Service\\RefreshToken",
      "type": "->",
      "function": "refresh",
      "file": "/usr/src/app/vendor/symfony/http-kernel/HttpKernel.php",
      "line": 169,
      "args": [
        [
          "object",
          "Symfony\\Component\\HttpFoundation\\Request"
        ]
      ]
    },
    {
      "namespace": "Symfony\\Component\\HttpKernel",
      "short_class": "HttpKernel",
      "class": "Symfony\\Component\\HttpKernel\\HttpKernel",
      "type": "->",
      "function": "handleRaw",
      "file": "/usr/src/app/vendor/symfony/http-kernel/HttpKernel.php",
      "line": 81,
      "args": [
        [
          "object",
          "Symfony\\Component\\HttpFoundation\\Request"
        ],
        [
          "integer",
          1
        ]
      ]
    },
    {
      "namespace": "Symfony\\Component\\HttpKernel",
      "short_class": "HttpKernel",
      "class": "Symfony\\Component\\HttpKernel\\HttpKernel",
      "type": "->",
      "function": "handle",
      "file": "/usr/src/app/vendor/symfony/http-kernel/Kernel.php",
      "line": 201,
      "args": [
        [
          "object",
          "Symfony\\Component\\HttpFoundation\\Request"
        ],
        [
          "integer",
          1
        ],
        [
          "boolean",
          true
        ]
      ]
    },
    {
      "namespace": "Symfony\\Component\\HttpKernel",
      "short_class": "Kernel",
      "class": "Symfony\\Component\\HttpKernel\\Kernel",
      "type": "->",
      "function": "handle",
      "file": "/usr/src/app/public/index.php",
      "line": 32,
      "args": [
        [
          "object",
          "Symfony\\Component\\HttpFoundation\\Request"
        ]
      ]
    }
  ]
}
lexik/jwt-authentication-bundle v2.16.0 This bundle provides JWT authentication for your Symfony REST API
gesdinet/jwt-refresh-token-bundle v1.1.1 Implements a refresh token system over Json Web Tokens in Symfony
symfony/framework-bundle           v4.4.47 Provides a tight integration between Symfony components and the Symfony full-stack framework
symfony/http-client                v4.4.47 Provides powerful methods to fetch HTTP resources synchronously or asynchronously
symfony/http-client-contracts      v2.5.2  Generic abstractions related to HTTP clients
symfony/http-foundation            v4.4.48 Defines an object-oriented layer for the HTTP specification
symfony/http-kernel                v4.4.48 Provides a structured process for converting a Request into a Response

eerison avatar Nov 11 '22 16:11 eerison

Ok I solved it adding a new service provider

gesdinet_jwt_refresh_token:
  user_identity_field: username
  refresh_token_class: App\Entity\RefreshToken
  user_provider: fos_user.user_provider.username_email

eerison avatar Nov 11 '22 18:11 eerison

If you have doctrines auto_mapping set to false, you need to add the vendors mapping to your own:

<?php

declare(strict_types=1);

use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;

return static function (ContainerConfigurator $containerConfigurator): void {
    $containerConfigurator->extension('doctrine', [
        'orm' => [
            'auto_mapping' => false,
            'mappings' => [
                ...
                'VendorRefreshToken' => [
                    'type' => 'xml',
                    'dir' => '%kernel.project_dir%/vendor/gesdinet/jwt-refresh-token-bundle/Resources/config/doctrine',
                    'prefix' => 'Gesdinet\JWTRefreshTokenBundle\Entity',
                ],
            ],
        ],
    ]);
};

(maybe also when auto_mapping is true, I don't know, its false in my project)

darthf1 avatar Dec 13 '22 08:12 darthf1

I just had a headache with this issue.

@darthf1 's solution is by far the cleanest I can think of. Thank you, I was not sure how to configure a second mapping entry inside my main EntityManager. This works like a charm 👍

Here's the same but with yaml :

# [...]
mappings:
    main:
        # [...]
    refresh_token:
        type: xml
        dir: '%kernel.project_dir%/vendor/gesdinet/jwt-refresh-token-bundle/Resources/config/doctrine'
        prefix: 'Gesdinet\JWTRefreshTokenBundle\Entity'

jtrepagne avatar Feb 28 '23 10:02 jtrepagne

Hi, i have same error with symfony 6.2 and gesdinet/jwt-refresh-token-bundle 1.1.3. For fix this, i override abstract fields like this :

<?php

namespace App\Entity;

use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Gesdinet\JWTRefreshTokenBundle\Entity\RefreshTokenRepository;
use Gesdinet\JWTRefreshTokenBundle\Model\AbstractRefreshToken as BaseAbstractRefreshToken;

#[
    ORM\Entity(
        repositoryClass: RefreshTokenRepository::class,
    ),
    ORM\Table('refresh_tokens')
]
class RefreshToken extends BaseAbstractRefreshToken
{
    #[
        ORM\Id,
        ORM\Column(
            name: 'id',
            type: Types::INTEGER,
            nullable: false,
        ),
        ORM\GeneratedValue(strategy: 'AUTO'),
    ]
    protected $id;

    #[
        ORM\Column(
            name: 'refresh_token',
            type: Types::STRING,
            nullable: false,
        )
    ]
    protected $refreshToken;

    #[
        ORM\Column(
            name: 'username',
            type: Types::STRING,
            nullable: false,
        ),
    ]
    protected $username;

    #[
        ORM\Column(
            name: 'valid',
            type: Types::DATETIME_MUTABLE,
            nullable: false,
        )
    ]
    protected $valid;
}

loicngr avatar Oct 05 '23 07:10 loicngr

Seems to be a bit of a false positive somewhere tbh. When you straight up delete the deprecated class locally and run tests it'll work fine and without deprecation

KDederichs avatar Nov 13 '23 11:11 KDederichs

Hi, i have same error with symfony 6.2 and gesdinet/jwt-refresh-token-bundle 1.1.3. For fix this, i override abstract fields like this :

<?php

namespace App\Entity;

…

class RefreshToken extends BaseAbstractRefreshToken
{

…

    #[
        ORM\Column(
            name: 'refresh_token',
            type: Types::STRING,
            nullable: false,
        )
    ]
    protected $refreshToken;
 …
}

You have to be careful, the original ORM mapping of the package has the $refreshToken property (refresh_token column) field mapped as unique and 128 characters long. My mapping looks like this and is not triggering a database change when creating a new migration:

#[
    ORM\Column(
        name: 'refresh_token',
        type: Types::STRING,
        length: 128,
        unique: true,
        nullable: false,
    )
]
protected $refreshToken;

felixrupp avatar Feb 14 '24 14:02 felixrupp

Same mistake occurred with Symfony version 7.0.3. I opted for the method proposed by @loicngr. If there is another way to do it I am interested.

Skewmos avatar Mar 13 '24 06:03 Skewmos