You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

非Symfony环境下Doctrine ORM无法加载实体元数据问题

问题:Doctrine ORM无法加载实体元数据(无Symfony框架环境)

场景说明

我正在用Doctrine ORM开发一个Docker化的PHP API,因客观限制无法使用完整的Symfony套件。当前Composer依赖如下:

"require": {
        "bramus/router": "~1.6",
        "ramsey/uuid": "^4.7",
        "firebase/php-jwt": "^6.10",
        "ext-pdo": "*",
        "doctrine/orm": "^3.3",
        "ramsey/uuid-doctrine": "^2.1",
        "doctrine/dbal": "^4.2",
        "creof/doctrine2-spatial": "^1.2",
        "symfony/validator": "^7.2",
      },

自动加载配置正确,所有类均可正常引用。

问题描述

已完成Doctrine ORM初始化并创建实体类,现在需要生成数据库Schema(类似Java Hibernate的更新功能)。尝试用CLI命令生成Schema时(已安装symfony/cache),Docker容器提示命令不存在:

# orm:schema-tool:create
/bin/sh: 1: orm:schema-tool:create: not found
# $ php bin/doctrine orm:schema-tool:update
/bin/sh: 2: $: not found
# doctrine orm:validate-schema
/bin/sh: 3: doctrine: not found

查阅相关资料后发现多数案例基于框架,少数无框架案例仅涉及路径问题,但我的路径已验证正确。因此尝试在index.php中临时生成Schema,后续导出备用。

Doctrine初始化类(含调试代码)

<?php

namespace Config;

use Doctrine\DBAL\DriverManager;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\ORMSetup;

class DoctrineInitializer
{
    public static function getEntityManager(): EntityManager
    {
        // 实体类路径
        $paths = [
            __DIR__ . '/../Api/AccountApi/Model',
            __DIR__ . '/../Api/MediaApi/Model',
            __DIR__ . '/../Api/ProfileAPI/Model',
            __DIR__ . '/../Api/TripAPI/Model',
            __DIR__ . '/../Api/TripEntryAPI/Model',
        ];

        foreach ($paths as $path) {
            echo "Checking path: $path\n";
            if (!is_dir($path)) {
                echo "Invalid path: $path\n";
            }
        }

        echo "Class exists: " . (class_exists('AccountApi\\Model\\Account') ? 'Yes' : 'No') . "\n";

        // 数据库配置
        $dbParams = [
            'dbname'   => getenv('DB_DATABASE'),
            'user'     => getenv('DB_USERNAME'),
            'password' => getenv('DB_PASSWORD'),
            'host'     => 'mysql',
            'driver'   => 'pdo_mysql',
        ];

        $isDevMode = true;

        $config = ORMSetup::createAttributeMetadataConfiguration($paths, $isDevMode);
        $connection = DriverManager::getConnection($dbParams, $config);

        return new EntityManager($connection, $config);
    }
}

实体类示例

<?php

namespace AccountApi\Model;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Ramsey\Uuid\Doctrine\UuidGenerator;

/**
 * @ORM\Entity
 * @ORM\Table(name="accounts")
 */
class Account
{
    /**
     * @ORM\Id
     * @ORM\Column(type="uuid", unique=true)
     * @ORM\GeneratedValue(strategy="CUSTOM")
     * @ORM\CustomIdGenerator(class=UuidGenerator::class)
     */
    private $id;

    /**
     * @ORM\Column(type="string", unique=true)
     */
    private $email;

    /**
     * @ORM\Column(type="string")
     */
    private $password;

    /**
     * @ORM\OneToOne(targetEntity="Profile", mappedBy="account", cascade={"persist", "remove"})
     */
    private $profile;

    public function __construct($id, $email, $password, $profile)
    {
        $this->id = $id;
        $this->email = $email;
        $this->password = $password;
        $this->profile = $profile;
    }
    
    /**
     Getters and setters
    */

临时index.php代码

<?php
require_once __DIR__ . '/vendor/autoload.php';

use Config\DoctrineInitializer;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Tools\SchemaValidator;
use RequestRouter\RequestRouter;
use SecurityConfig\SecurityConfiguration;

// 应用安全配置(会话、过滤等),这是每个请求的第一步
SecurityConfiguration::applyConfig();

// 获取EntityManager
$entityManager = DoctrineInitializer::getEntityManager();

echo "Connected to database: " . getenv('DB_DATABASE') . "\n";

// 获取所有元数据
$metadata = $entityManager->getMetadataFactory()->getAllMetadata();

if (empty($metadata)) {
    echo "No metadata found. Ensure your entities are properly defined and loaded.\n";
    exit;
}

echo "Total entities found: " . count($metadata) . "\n";

foreach ($metadata as $meta) {
    /** @var ClassMetadata $meta */
    echo "Entity: " . $meta->getName() . "\n";
    echo "Table: " . $meta->getTableName() . "\n";
    echo "Fields:\n";
    foreach ($meta->getFieldNames() as $field) {
        echo "  - $field (type: " . $meta->getTypeOfField($field) . ")\n";
    }
    echo "Associations:\n";
    foreach ($meta->getAssociationNames() as $assoc) {
        echo "  - $assoc (target: " . $meta->getAssociationTargetClass($assoc) . ")\n";
    }
    echo "---------------------------------------\n";
}

// 验证Schema
$validator = new SchemaValidator($entityManager);
$violations = $validator->validateMapping();

if (empty($violations)) {
    echo "No schema violations detected. The database schema might already match the entities.\n";
} else {
    echo "Total schema violations: " . count($violations) . "\n";
    foreach ($violations as $violation) {
        echo "Violation: " . $violation->getMessage() . "\n";
    }
}

// 生成Schema
$tool = new \Doctrine\ORM\Tools\SchemaTool($entityManager);

$queries = $tool->getCreateSchemaSql($metadata);

echo "Total schema queries: " . count($queries) . "\n";

foreach ($queries as $query) {
    echo "Query: $query\n";
}

if (empty($queries)) {
    echo "No schema changes detected. The database schema might already match the entities.\n";
}

// 配置路由
RequestRouter::applyRoutes();

执行输出

Checking path: /app/Backend/Config/../Api/AccountApi/Model 
Checking path: /app/Backend/Config/../Api/MediaApi/Model 
Checking path: /app/Backend/Config/../Api/ProfileAPI/Model 
Checking path: /app/Backend/Config/../Api/TripAPI/Model 
Checking path: /app/Backend/Config/../Api/TripEntryAPI/Model 

Class exists: Yes 
Connected to database: database

No metadata found. Ensure your entities are properly defined and loaded.

疑问

为何Doctrine无法加载实体元数据?

解决方案

问题根源在于PHP 8属性注解的使用不匹配:

  • 初始化代码中调用了ORMSetup::createAttributeMetadataConfiguration(),该方法仅支持PHP 8的属性注解(如#[ORM\Entity])
  • 但实体类中仍在使用传统的注释注解(如/** @ORM\Entity */)

修复方法二选一:

  1. 将实体类的注释注解改为PHP 8属性格式:
    #[ORM\Entity]
    #[ORM\Table(name: "accounts")]
    class Account
    {
        #[ORM\Id]
        #[ORM\Column(type: "uuid", unique: true)]
        #[ORM\GeneratedValue(strategy: "CUSTOM")]
        #[ORM\CustomIdGenerator(class: UuidGenerator::class)]
        private $id;
        // ... 其他属性同理修改
    }
    
  2. 改用支持注释注解的初始化方法:将ORMSetup::createAttributeMetadataConfiguration()替换为ORMSetup::createAnnotationMetadataConfiguration(),同时确保已安装doctrine/annotations依赖(执行composer require doctrine/annotations)

内容的提问来源于stack exchange,提问作者user29224699

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 21:39:49