将 Doctrine 与 Slim 结合使用

这个食谱条目描述了如何从头开始将广泛使用的Doctrine ORM集成到 Slim 4 应用程序中。

将 Doctrine 添加到您的应用程序

第一步是使用composer将 Doctrine ORM 导入到你的项目中。

composer require doctrine/orm symfony/cache

doctrine/cache请注意,2021 年 4 月 30 日,Doctrine在发布 v2.0.0 版本时正式弃用,该版本从该库中删除了所有缓存实现。从那时起,他们建议改用symfony/cache符合 PSR-6 的实现。如果你想在生产中缓存 Doctrine 元数据,你只需要它,但这样做没有任何缺点,所以我们将展示如何设置它。

如果您还没有迁移到 PHP8 或者只是想继续使用传统的 PHPDoc 注释来注释您的实体,您还需要导入包,doctrine/annotations它曾经是 PHP8 的依赖项,doctrine/orm但由于 2.10.0 是可选的:

composer require doctrine/annotations

定义您的第一个实体

您可以跳过此步骤并改用您的实际 Doctrine 实体。以下只是一个例子。

请注意,它使用 PHP8 属性,如果需要,请将它们转换为 PHPDoc 注释。

<?php

// src/Domain/User.php

use DateTimeImmutable;
use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\GeneratedValue;
use Doctrine\ORM\Mapping\Id;
use Doctrine\ORM\Mapping\Table;

#[Entity, Table(name: 'users')]
final class User
{
    #[Id, Column(type: 'integer'), GeneratedValue(strategy: 'AUTO')]
    private int $id;

    #[Column(type: 'string', unique: true, nullable: false)]
    private string $email;

    #[Column(name: 'registered_at', type: 'datetimetz_immutable', nullable: false)]
    private DateTimeImmutable $registeredAt;

    public function __construct(string $email)
    {
        $this->email = $email;
        $this->registeredAt = new DateTimeImmutable('now');
    }

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

    public function getEmail(): string
    {
        return $this->email;
    }

    public function getRegisteredAt(): DateTimeImmutable
    {
        return $this->registeredAt;
    }
}
图 1:一个示例 Doctrine 实体。

提供数据库凭据

接下来,在您的 Slim 配置旁边添加 Doctrine 设置。

<?php

// settings.php

define('APP_ROOT', __DIR__);

return [
    'settings' => [
        'slim' => [
            // Returns a detailed HTML page with error details and
            // a stack trace. Should be disabled in production.
            'displayErrorDetails' => true,

            // Whether to display errors on the internal PHP log or not.
            'logErrors' => true,

            // If true, display full errors with message and stack trace on the PHP log.
            // If false, display only "Slim Application Error" on the PHP log.
            // Doesn't do anything when 'logErrors' is false.
            'logErrorDetails' => true,
        ],

        'doctrine' => [
            // Enables or disables Doctrine metadata caching
            // for either performance or convenience during development.
            'dev_mode' => true,

            // Path where Doctrine will cache the processed metadata
            // when 'dev_mode' is false.
            'cache_dir' => APP_ROOT . '/var/doctrine',

            // List of paths where Doctrine will search for metadata.
            // Metadata can be either YML/XML files or PHP classes annotated
            // with comments or PHP8 attributes.
            'metadata_dirs' => [APP_ROOT . '/src/Domain'],

            // The parameters Doctrine needs to connect to your database.
            // These parameters depend on the driver (for instance the 'pdo_sqlite' driver
            // needs a 'path' parameter and doesn't use most of the ones shown in this example).
            // Refer to the Doctrine documentation to see the full list
            // of valid parameters: https://www.doctrine-project.org/projects/doctrine-dbal/en/current/reference/configuration.html
            'connection' => [
                'driver' => 'pdo_mysql',
                'host' => 'localhost',
                'port' => 3306,
                'dbname' => 'mydb',
                'user' => 'user',
                'password' => 'secret',
                'charset' => 'utf-8'
            ]
        ]
    ]
];
图 2:Slim 设置数组。

定义 EntityManager 服务

现在我们定义EntityManager服务,它是您代码中与 ORM 交互的主要点。

Slim 4 要求您提供自己的 PSR-11 容器实现。本示例使用uma/dic, 一个简洁明了的 PSR-11 容器。使其适应您自己选择的容器。

传统上注解元数据读取器是最流行的,但从doctrine/orm2.10.0 开始他们将依赖设为doctrine/annotations可选,暗示该项目更愿意用户迁移到现代 PHP8 属性表示法。

这里我们展示了如何使用 PHP8 属性配置元数据读取器。如果您还没有迁移到 PHP8 或想使用传统的 PHPDoc 注释,您将需要使用doctrine/annotationsComposer 显式要求并调用,Setup::createAnnotationMetadataConfiguration(...)而不是像Setup::createAttributeMetadataConfiguration(...)下面的示例那样。

<?php

// bootstrap.php

use Doctrine\Common\Cache\Psr6\DoctrineProvider;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Tools\Setup;
use Psr\Container\ContainerInterface;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use UMA\DIC\Container;

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

$container = new Container(require __DIR__ . '/settings.php');

$container->set(EntityManager::class, static function (Container $c): EntityManager {
    /** @var array $settings */
    $settings = $c->get('settings');

    // Use the ArrayAdapter or the FilesystemAdapter depending on the value of the 'dev_mode' setting
    // You can substitute the FilesystemAdapter for any other cache you prefer from the symfony/cache library
    $cache = $settings['doctrine']['dev_mode'] ?
        DoctrineProvider::wrap(new ArrayAdapter()) :
        DoctrineProvider::wrap(new FilesystemAdapter(directory: $settings['doctrine']['cache_dir']));

    $config = Setup::createAttributeMetadataConfiguration(
        $settings['doctrine']['metadata_dirs'],
        $settings['doctrine']['dev_mode'],
        null,
        $cache
    );

    return EntityManager::create($settings['doctrine']['connection'], $config);
});

return $container;
图 3:定义 EntityManager 服务。

创建 Doctrine 控制台

要运行数据库迁移、验证类注释等,您将使用doctrine已经存在于vendor/bin. 但是为了工作这个脚本需要一个cli-config.php 位于项目根目录的文件告诉它如何找到EntityManager我们刚刚设置的。

我们cli-config.php只需要检索我们刚刚在容器中定义的 EntityManager 服务并将其传递给ConsoleRunner::createHelperSet().

<?php

// cli-config.php

use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Tools\Console\ConsoleRunner;
use Slim\Container;

/** @var Container $container */
$container = require_once __DIR__ . '/bootstrap.php';

return ConsoleRunner::createHelperSet($container->get(EntityManager::class));
图 4:启用 Doctrine 的控制台应用程序。

花点时间验证控制台应用程序是否正常工作。正确配置后,它的输出或多或少看起来像这样:

$ php vendor/bin/doctrine
Doctrine Command Line Interface 2.11.0

Usage:
  command [options] [arguments]

Options:
  -h, --help            Display help for the given command. When no command is given display help for the list command
  -q, --quiet           Do not output any message
  -V, --version         Display this application version
      --ansi|--no-ansi  Force (or disable --no-ansi) ANSI output
  -n, --no-interaction  Do not ask any interactive question
  -v|vv|vvv, --verbose  Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug

Available commands:
  completion                         Dump the shell completion script
  help                               Display help for a command
  list                               List commands
 dbal
  dbal:reserved-words                Checks if the current database contains identifiers that are reserved.
  dbal:run-sql                       Executes arbitrary SQL directly from the command line.
 orm
  orm:clear-cache:metadata           Clear all metadata cache of the various cache drivers
  orm:clear-cache:query              Clear all query cache of the various cache drivers
  orm:clear-cache:region:collection  Clear a second-level cache collection region
  orm:clear-cache:region:entity      Clear a second-level cache entity region
  orm:clear-cache:region:query       Clear a second-level cache query region
  orm:clear-cache:result             Clear all result cache of the various cache drivers
  orm:convert-d1-schema              [orm:convert:d1-schema] Converts Doctrine 1.x schema into a Doctrine 2.x schema
  orm:convert-mapping                [orm:convert:mapping] Convert mapping information between supported formats
  orm:ensure-production-settings     Verify that Doctrine is properly configured for a production environment
  orm:generate-entities              [orm:generate:entities] Generate entity classes and method stubs from your mapping information
  orm:generate-proxies               [orm:generate:proxies] Generates proxy classes for entity classes
  orm:generate-repositories          [orm:generate:repositories] Generate repository classes from your mapping information
  orm:info                           Show basic information about all mapped entities
  orm:mapping:describe               Display information about mapped objects
  orm:run-dql                        Executes arbitrary DQL directly from the command line
  orm:schema-tool:create             Processes the schema and either create it directly on EntityManager Storage Connection or generate the SQL output
  orm:schema-tool:drop               Drop the complete database schema of EntityManager Storage Connection or generate the corresponding SQL output
  orm:schema-tool:update             Executes (or dumps) the SQL needed to update the database schema to match the current mapping metadata
  orm:validate-schema                Validate the mapping files
图 5:完整性检查 Doctrine 的 CLI。

此时,您可以通过运行来初始化数据库并加载架构php vendor/bin/doctrine orm:schema-tool:create

在我们自己的代码中使用 EntityManager

恭喜!您现在可以从命令行管理数据库,并EntityManager在代码中需要的地方使用它。

// bootstrap.php

$container->set(UserService::class, static function (Container $c) {
    return new UserService($c->get(EntityManager::class));
});

// src/UserService.php

final class UserService
{
    private EntityManager $em;

    public function __construct(EntityManager $em)
    {
        $this->em = $em;
    }

    public function signUp(string $email): User
    {
        $newUser = new User($email);

        $this->em->persist($newUser);
        $this->em->flush();

        return $newUser;
    }
}
图 6:在您自己的代码中使用 EntityManager 服务。

其他资源