How to fix Only attribute mapping is supported by make:entity error in Symfony

How to fix Only attribute mapping is supported by make:entity error in Symfony banner

To fix the Only attribute mapping is supported by make:entity error error in Symfony, you need to change your Doctrine Entity type in your config/packages/doctrine.yaml from annotation to attribute.

This error message is generated when you try to create a new entity with the maker bundle by running symfony console make:entity

$ symfony console make:entity

 Class name of the entity to create or update (e.g. AgreeablePizza):
 > TestEntity

 created: src/Entity/TestEntity.php
 created: src/Repository/TestEntityRepository.php


 [ERROR] Only attribute mapping is supported by make:entity, but the <info>App\Entity\TestEntity</info> class uses a
         different format. If you would like this command to generate the properties & getter/setter methods, add your mapping
         configuration, and then re-run this command with the <info>--regenerate</info> flag.

What is causing this error?

As of version v1.44.0, the maker-bundle drops support for PHP 7 and annotations - official release notes.

What are annotations in PHP?

Annotations in PHP refer to a form of metadata that can be added to various elements within the code, such as classes, methods, properties, and parameters. These annotations provide additional information or instructions to tools, libraries, or frameworks that can then use this information for various purposes.

// ..
class MyEntity
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;
// ..

The code above private $id; is annotation.

/**
* @var int
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/

These annotations are used by the Doctrine ORM doctrine-bundle to map your entities to your database schema.

What are attributes in PHP?

Attributes in PHP are a new feature introduced in PHP 8. Attributes provide a standardized way to attach metadata to classes, methods, functions, properties, and parameters. They are similar to annotations in other programming languages but integrated into the language itself, making them more consistent and structured.

// ..
#[ORM\Entity(repositoryClass: MyEntityRepository::class)]
class MyEntity
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;
// ..

In short, annotations (@..) are being replaced with attributes (#..) which are more capable and better integrated into the language. 

This incentivizes maintainers of different libraries (e.g. maker-bundle) to drop support for annotations in favor of attributes and drive the community to adopt the language's new features faster.

How to fix Only attribute mapping is supported by make:entity error error?

Since the maker-bundle no longer supports Doctrine entities with annotations. If you still want to use the full features of this command, you'll need to migrate your entities from annotations to attributes.

First, you need to tell Doctrine that your entities are mapped using attributes.

Change your Doctrine Entity type in your config/packages/doctrine.yaml from annotation to attribute. If you are using a newer version of Symfony >= 5.4, you can omit the type: attribute, because it's the default.

doctrine:
    # ..
    orm:
        auto_generate_proxy_classes: true
        naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
        auto_mapping: true
        mappings:
            App:
                is_bundle: false
                type: attribute # <<--
                dir: '%kernel.project_dir%/src/Entity'
                prefix: 'App\Entity'
                alias: App

How to migrate from annotations to attributes in Doctrine?

You have two options: manual or automatic.

The manual process involves going through each entity and changing the code.

The automatic process requires the Rector library, which does it all for you.

If you have a few small entities, I would recommend migrating them manually:

// ..
/**
 * Post
 *
 * @ORM\Table(name="post")
 * @ORM\Entity(repositoryClass="App\Repository\PostRepository")
 */
class Post
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
    * @ORM\Column(name="slug", type="string", length=255, unique=true)
    */
    private $slug;

    /**
    * @ORM\Column(name="title", type="string", length=255)
    */
    private $slug;
// ..

Needs to become

// ..
#[ORM\Entity(repositoryClass: PostRepository::class)]
class Post
{
    const READMORE_SPLIT_TAG = '';

    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\Column(length: 255, unique: true)]
    private ?string $slug = null;

    #[ORM\Column(length: 255)]
    private ?string $title = null;
// ..

Automatically convert from annotations to attributes using Rector

Rector is a powerful open-source PHP library and tool that helps developers automate and simplify the process of code refactoring. It is designed to assist in transforming PHP code, applying predefined rules to achieve specific goals, such as upgrading to a new PHP version, improving code quality, and implementing best practices.

The primary purpose of Rector is to make codebase maintenance and upgrading easier by providing a consistent way to apply code transformations across a project. It can handle a wide range of refactoring tasks, including PHP version updates, Coding standard fixes, code quality improvements, etc.

Here is how to use Rector to migrate the entities:

  1. Install Rector composer require --dev rector/rector.
  2. Create a file called rector.php in the root folder of your project with the following contents
    <?php
    
    declare(strict_types=1);
    
    use Rector\Config\RectorConfig;
    use Rector\Doctrine\Set\DoctrineSetList;
    
    return function (RectorConfig $rectorConfig): void {
        $rectorConfig->paths([
            __DIR__ . '/src/Entity',
        ]);
        $rectorConfig->sets([
            DoctrineSetList::ANNOTATIONS_TO_ATTRIBUTES,
        ]);
    };
  3. Run vendor/bin/rector
  4. The program outputs all the changed lines with diff.
  5. Optionally you can go through the changes and check if everything is correct.
    rector php output
  6. Uninstall Rector: composer remove rector/rector && rm rector.php

Conclusion

When new language features are released, this change cascades to the ecosystem of libraries, and stuff like this happens.

Change is a good thing, especially when it's for the better.

Happy coding!