wakebit / cycle-bridge
循环ORM桥接器
v2.1.0
2023-04-24 05:37 UTC
Requires
- php: ^8.0|^8.1|^8.2
- cycle/annotated: ^3.0
- cycle/database: ^2.0
- cycle/migrations: ^3.0
- cycle/orm: ^2.0
- cycle/schema-builder: ^2.0
- cycle/schema-migrations-generator: ^2.0
- cycle/schema-renderer: ^1.1
- psr/container: ^1.0|^2.0
- psr/simple-cache: ^1.0|^2.0|^3.0
- spiral/core: ^2.9
- symfony/console: ^5.1|^6.0
Requires (Dev)
- cache/filesystem-adapter: ^1.1
- friendsofphp/php-cs-fixer: ^3.4
- league/flysystem: ^1.0
- php-di/php-di: ^6.3
- phpunit/phpunit: ^8.5 || ^9.5
- psalm/plugin-phpunit: ^0.16.1
- vimeo/psalm: ^4.19
- voku/arrayy: ^7.9
README
此软件包提供了一套Symfony命令和用于集成任何框架的Cycle ORM的类。我们支持ORM的两种版本集成。如果您想将其集成到Laravel中,我们已经有一个单独的软件包,它使用此桥接器。
要求
- PHP >= 8.0
- Cycle ORM 1或2(分别对应于
v1.x
和v2.x
分支)
安装
- 使用composer安装此软件包
composer require wakebit/cycle-bridge
PHP-DI使用的示例
- 声明配置
config/config.php
并填写数据库凭证
<?php declare(strict_types=1); use function DI\env; return [ // Environment variables 'debug' => env('APP_DEBUG', 'true'), // Database 'db.connection' => env('DB_CONNECTION', 'mysql'), 'db.host' => env('DB_HOST', 'localhost'), 'db.database' => env('DB_DATABASE', ''), 'db.username' => env('DB_USERNAME', ''), 'db.password' => env('DB_PASSWORD', ''), ];
- 声明ORM配置
config/cycle.php
。不要忘记设置正确的实体路径和迁移路径
<?php use Cycle\Database\Config\DatabaseConfig; use Cycle\Migrations\Config\MigrationConfig; use Psr\Container\ContainerInterface; use Spiral\Tokenizer\Config\TokenizerConfig; use Wakebit\CycleBridge\Schema\Config\SchemaConfig; use function DI\create; /** * @psalm-suppress UndefinedClass * @psalm-suppress MixedArgument */ return [ 'database' => static function (ContainerInterface $container): DatabaseConfig { return new DatabaseConfig([ 'default' => 'default', 'databases' => [ 'default' => [ 'connection' => $container->get('config')['db.connection'], ], ], 'connections' => [ 'sqlite' => new \Cycle\Database\Config\SQLiteDriverConfig( connection: new \Cycle\Database\Config\SQLite\MemoryConnectionConfig(), queryCache: true, ), 'mysql' => new \Cycle\Database\Config\MySQLDriverConfig( connection: new \Cycle\Database\Config\MySQL\TcpConnectionConfig( database: $container->get('config')['db.database'], host: $container->get('config')['db.host'], port: 3306, user: $container->get('config')['db.username'], password: $container->get('config')['db.password'], ), queryCache: true, ), 'postgres' => new \Cycle\Database\Config\PostgresDriverConfig( connection: new \Cycle\Database\Config\Postgres\TcpConnectionConfig( database: $container->get('config')['db.database'], host: $container->get('config')['db.host'], port: 5432, user: $container->get('config')['db.username'], password: $container->get('config')['db.password'], ), schema: 'public', queryCache: true, ), 'sqlServer' => new \Cycle\Database\Config\SQLServerDriverConfig( connection: new \Cycle\Database\Config\SQLServer\TcpConnectionConfig( database: $container->get('config')['db.database'], host: $container->get('config')['db.host'], port: 1433, user: $container->get('config')['db.username'], password: $container->get('config')['db.password'], ), queryCache: true, ), ], ]); }, 'orm' => [ 'schema' => static function (): SchemaConfig { return new SchemaConfig(); }, 'tokenizer' => static function (): TokenizerConfig { return new TokenizerConfig([ 'directories' => [ __DIR__ . '/../src/Entity', ], 'exclude' => [ ], ]); }, ], 'migrations' => static function (ContainerInterface $container): MigrationConfig { return new MigrationConfig([ 'directory' => __DIR__ . '/../resources/migrations', 'table' => 'migrations', 'safe' => filter_var($container->get('config')['debug'], FILTER_VALIDATE_BOOLEAN), ]); }, ];
- 在
config/container.php
中声明PHP-DI容器的依赖项
<?php declare(strict_types=1); use Cycle\Database\Config\DatabaseConfig; use Cycle\Database\DatabaseInterface; use Cycle\Database\DatabaseManager; use Cycle\Database\DatabaseProviderInterface; use Cycle\Migrations\Config\MigrationConfig; use Cycle\Migrations\FileRepository; use Cycle\Migrations\RepositoryInterface; use Cycle\ORM\EntityManager; use Cycle\ORM\EntityManagerInterface; use Cycle\ORM\Factory; use Cycle\ORM\FactoryInterface; use Cycle\ORM\ORM; use Cycle\ORM\ORMInterface; use Cycle\ORM\SchemaInterface; use Psr\Container\ContainerInterface; use Spiral\Tokenizer\ClassesInterface; use Spiral\Tokenizer\ClassLocator; use Spiral\Tokenizer\Config\TokenizerConfig; use Spiral\Tokenizer\Tokenizer; use Wakebit\CycleBridge\Contracts\Schema\CacheManagerInterface; use Wakebit\CycleBridge\Contracts\Schema\CompilerInterface; use Wakebit\CycleBridge\Contracts\Schema\GeneratorQueueInterface; use Wakebit\CycleBridge\Schema\CacheManager; use Wakebit\CycleBridge\Schema\Compiler; use Wakebit\CycleBridge\Schema\Config\SchemaConfig; use Wakebit\CycleBridge\Schema\GeneratorQueue; use Wakebit\CycleBridge\Schema\SchemaFactory; use function DI\autowire; use function DI\factory; use function DI\get; return [ 'config' => require 'config.php', 'cycle' => require 'cycle.php', DatabaseConfig::class => static function (ContainerInterface $container): DatabaseConfig { return $container->get('cycle')['database']; }, SchemaConfig::class => static function (ContainerInterface $container): SchemaConfig { return $container->get('cycle')['orm']['schema']; }, TokenizerConfig::class => static function (ContainerInterface $container): TokenizerConfig { return $container->get('cycle')['orm']['tokenizer']; }, MigrationConfig::class => static function (ContainerInterface $container): MigrationConfig { return $container->get('cycle')['migrations']; }, DatabaseProviderInterface::class => autowire(DatabaseManager::class), DatabaseInterface::class => static function (ContainerInterface $container): DatabaseInterface { return $container->get(DatabaseProviderInterface::class)->database(); }, DatabaseManager::class => get(DatabaseProviderInterface::class), ClassLocator::class => get(ClassesInterface::class), ClassesInterface::class => static function (ContainerInterface $container): ClassesInterface { return $container->get(Tokenizer::class)->classLocator(); }, FactoryInterface::class => autowire(Factory::class), CacheManagerInterface::class => static function (): CacheManagerInterface { // Here you need to pass PSR-16 compatible cache pool. See example with cache file below. // Packages: league/flysystem, cache/filesystem-adapter $filesystemAdapter = new \League\Flysystem\Adapter\Local(__DIR__ . '/../var/cache'); $filesystem = new \League\Flysystem\Filesystem($filesystemAdapter); $pool = new \Cache\Adapter\Filesystem\FilesystemCachePool($filesystem); return new CacheManager($pool); }, GeneratorQueueInterface::class => autowire(GeneratorQueue::class), CompilerInterface::class => autowire(Compiler::class), SchemaInterface::class => factory([SchemaFactory::class, 'create']), ORMInterface::class => static function (ContainerInterface $container): ORMInterface { return new ORM($container->get(FactoryInterface::class), $container->get(SchemaInterface::class)); }, EntityManagerInterface::class => autowire(EntityManager::class), RepositoryInterface::class => autowire(FileRepository::class), ];
- 现在,您需要将上一步创建的依赖项数组加载到PHP-DI中。在您可以使用依赖项之后,编写您的代码。
让我们看一个快速示例。定义实体
<?php declare(strict_types=1); namespace App\Entity; use Cycle\Annotated\Annotation\Entity; use Cycle\Annotated\Annotation\Column; #[Entity] class User { #[Column(type: 'primary')] private int $id; #[Column(type: 'string')] private string $name; public function getId(): int { return $this->id; } public function getName(): string { return $this->name; } public function setName(string $name): void { $this->name = $name; } }
您可以从容器中获取DBAL、ORM和EntityManager。快速使用示例
<?php declare(strict_types=1); namespace App; use Cycle\Database\DatabaseProviderInterface; use Cycle\ORM\EntityManagerInterface; use Cycle\ORM\ORMInterface; final class SomeClass { public function __construct( private DatabaseProviderInterface $dbal, private EntityManagerInterface $em, private ORMInterface $orm, ) { } public function __invoke() { // DBAL $tables = $this->dbal->database()->getTables(); $tableNames = array_map(fn (\Cycle\Database\TableInterface $table): string => $table->getName(), $tables); dump($tableNames); // Create, modify, delete entities using Transaction $user = new \App\Entity\User(); $user->setName("Hello World"); $this->em->persist($user); $this->em->run(); dump($user); // ORM $repository = $this->orm->getRepository(\App\Entity\User::class); $users = $repository->findAll(); dump($users); $user = $repository->findByPK(1); dump($user); } }
更多内容请参考官方Cycle ORM文档。
控制台命令
操作ORM模式
数据库迁移
数据库命令
编写功能测试
如果您使用的是内存数据库(SQLite),您可以直接在测试的setUp
方法中运行迁移,调用控制台命令cycle:migrate
。对于其他数据库,请按照此说明进行操作,并在tearDown
方法中删除所有表。
高级
手动定义ORM模式
如果您想使用手动定义的ORM模式,您可以在cycle.php
的orm.schema.map
配置键中定义它
use Wakebit\CycleBridge\Schema\Config\SchemaConfig; return [ // ... 'orm' => [ 'schema' => static function (): SchemaConfig { return new SchemaConfig([ 'map' => require __DIR__ . '/../orm_schema.php', ]); }, ] // ... ]
手动定义的模式应以数组形式表示。它将被传递到\Cycle\ORM\Schema
构造函数中。更多内容请参考这里。
自定义模式编译管道
您可以在cycle.php
的orm.schema.generators
配置键中重新定义ORM模式编译生成器
use Wakebit\CycleBridge\Schema\Config\SchemaConfig; return [ // ... 'orm' => [ 'schema' => static function (): SchemaConfig { return new SchemaConfig([ 'generators' => [ 'index' => [], 'render' => [ \Cycle\Schema\Generator\ResetTables::class, // re-declared table schemas (remove columns) \Cycle\Schema\Generator\GenerateRelations::class, // generate entity relations \Cycle\Schema\Generator\ValidateEntities::class, // make sure all entity schemas are correct \Cycle\Schema\Generator\RenderTables::class, // declare table schemas \Cycle\Schema\Generator\RenderRelations::class, // declare relation keys and indexes ], 'postprocess' => [ \Cycle\Schema\Generator\GenerateTypecast::class, // typecast non string columns ], ] ]); }, ] // ... ]
类将通过DI容器解析。默认管道您可以在这里查看。
默认集合工厂
您可以在容器定义中指定预定义的或您自己的集合工厂
FactoryInterface::class => static function (ContainerInterface $container): FactoryInterface { return new \Cycle\ORM\Factory( dbal: $container->get(DatabaseProviderInterface::class), defaultCollectionFactory: new \Cycle\ORM\Collection\DoctrineCollectionFactory(), ); },
致谢
- Cycle ORM,PHP DataMapper ORM和数据建模引擎,由SpiralScout提供。
- Spiral Scout,Cycle ORM的作者。
- Spiral Framework Cycle Bridge,提供代码示例和使用示例。