本食譜章節說明如何從基礎將廣泛使用的 Doctrine ORM 整合到 Slim 4 應用程式中。
首先,使用 composer 將 Doctrine ORM 導入您的專案中。
composer require doctrine/orm:^3.0 doctrine/dbal:^4.0 symfony/cache
請注意,Doctrine 在 2021 年 4 月 30 日發布 v2.0.0 版本時,正式將 doctrine/cache
標示為已不建議使用,並刪除了該函式庫中的所有快取執行個體。從那時開始,他們建議改用 symfony/cache
,它是符合 PSR-6 的執行個體。如果您只想在實作期間快取 Doctrine 資訊,則只需要這個,基本上沒有缺點,我們將展示如何設定。
如果您尚未遷移到 PHP8,或只是想要繼續使用傳統的 PHPDoc 註解來標註您的實體,您還需要導入 doctrine/annotations
套件,它曾經是 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, options: ['collation' => 'NOCASE'])]
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;
}
}
接著,新增您的 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'
]
]
]
];
現在我們定義 EntityManager
服務,這是您的程式碼中與 ORM 互動的主要點。
Slim 4 要求您提供自己的 PSR-11 容器實作。本範例使用 uma/dic
,一個簡單且簡潔的 PSR-11 容器。將其調整到您自己的容器選擇。
傳統上,註解元資料讀取器是最受歡迎的,但從 doctrine/orm
2.10.0 開始,它們讓對 doctrine/annotations
的依賴性變成選用的,暗示這個專案偏好使用者遷移到現代的 PHP8 屬性符號。
這裡顯示如何以 PHP8 屬性設定元資料讀取器。如果您尚未遷移到 PHP8,或是想要使用傳統的 PHPDoc 註解,您需要以 Composer 明確地要求 doctrine/annotations
,並呼叫 Setup::createAnnotationMetadataConfiguration(...)
而不是 Setup::createAttributeMetadataConfiguration(...)
,如下面的範例所示。
<?php
// bootstrap.php
use Doctrine\DBAL\DriverManager;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\ORMSetup;
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'] ?
new ArrayAdapter() :
new FilesystemAdapter(directory: $settings['doctrine']['cache_dir']);
$config = ORMSetup::createAttributeMetadataConfiguration(
$settings['doctrine']['metadata_dirs'],
$settings['doctrine']['dev_mode'],
null,
$cache
);
$connection = DriverManager::getConnection($settings['doctrine']['connection']);
return new EntityManager($connection, $config);
});
return $container;
要執行資料庫遷移,驗證類別註解等,您將建立 doctrine
CLI 應用程式。這個檔案只需要擷取我們剛剛在容器中定義的 EntityManager 服務,並將它傳遞給 ConsoleRunner::run(new SingleManagerProvider($em))
。
慣例上以沒有 .php 副檔名的方式建立這個檔案並讓它可執行。它可以放置在專案的根目錄或 bin/
子目錄中。檔案以 #!/usr/bin/env php
開頭,並可以用 Linux 上的 chmod +x doctrine
指令讓它可執行。
#!/usr/bin/env php
<?php
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Tools\Console\ConsoleRunner;
use Doctrine\ORM\Tools\Console\EntityManagerProvider\SingleManagerProvider;
use Slim\Container;
/** @var Container $container */
$container = require_once __DIR__ . '/bootstrap.php';
ConsoleRunner::run(new SingleManagerProvider($container->get(EntityManager::class)));
花點時間驗證主控台應用程式是否運作正常。正確設定後,它的輸出將多多少少像這樣
$ ./doctrine
Doctrine Command Line Interface 3.1.1.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: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:generate-proxies [orm:generate:proxies] Generates proxy classes for entity classes
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
此時,您可以透過執行 php vendor/bin/doctrine orm:schema-tool:create
來初始化資料庫並載入架構。
恭喜!您現在可以在命令列管理您的資料庫,並在您的程式碼中需要的地方使用 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;
}
}