darkorsa / cordo
基于分层架构和使用CQRS、分层架构、事件、队列等设计的微框架,旨在高效地开发REST API。
Requires
- darkorsa/cordo-core: ~0.50.0
Requires (Dev)
- nunomaduro/phpinsights: dev-master
- pestphp/pest: ^1.18
- pestphp/pest-plugin-faker: ^1.0
- phpstan/phpstan: ^1.8
- symfony/var-dumper: ^5.2
README
Cordo是一个微框架,旨在通过使用分层架构、CQRS(命令查询责任分离)等原则,高效地开发REST API。
- 分层架构
- CQRS(命令查询责任分离)
- 事件调度器
- 仓库模式
- 队列
- OAuth2
- UUIDs
- 按功能打包
- 最小化配置方法
它符合PSRs: PSR-1
、PSR-2
、PSR-3
、PSR-4
、PSR-7
、PSR-11
、PSR-15
、PSR-18
。
创建此框架的主要目标是创建一个高效的工具,用于构建具有良好架构基础和尽可能少的“魔法”和配置的API应用程序。
注意: Cordo仍在开发中。一些基本功能已实现,但测试仍在进行中。请记住这一点。
要求
- PHP 8.1或更高版本
- Apache/Nginx
可选要求
- MySql 5.7(默认数据库驱动程序)
- PHP Redis扩展(队列的驱动程序)
安装
要创建新项目,请转到项目文件夹,并在该文件夹内键入
$ composer create-project darkorsa/cordo ./ -s dev
然后复制.env_example
文件,并将其重命名为.env
。然后填写您的配置数据。
可选地,您可以运行控制台命令
$ php cordo core:init --withOAuth --withUuid
它将创建
- OAuth2所需的所有必要数据库表
- UUID数据库帮助函数
仍然缺少
- 缓存 - 对于缓存,您可以查看Cordo Gateway
工作原理
Cordo并没有重新发明轮子。它基本上是一系列流行的PHP库的组合,并按顺序配置,以创建一个符合现代PHP良好编程实践的单 giản 框架。
一些使用的库
- Doctrine
- OAuth2
- Fast Route
- Tactician
- Fractal
- Plates
- Monolog
- PHP-DI
- Bernard
- Whoops
- Relay
- Guzzle
- Symfony Console
- Laminas ACL
- Laminas Mail
本文档不会详细说明如何处理路由、命令总线、依赖注入容器、查询数据库等,有关这些,请参阅相关库的文档。
还鼓励您自己查找内部的工作原理,查看Cordo Core库,其中包含抽象类和接口。
如果您想了解如何在所有层中组织代码,如何利用CQRS
、Repository Pattern
、Events
、Queues
等,请查看Users Bundle。查看安装说明此处。
入口点
应用程序的入口点
Web
HTTP请求的入口点是public/index.php
。您的apache/nginx配置应指向public
文件夹。
控制台
使用Symfony Console组件处理命令行命令。
您可以通过命令行使用以下命令来执行命令:
php cordo [command_name]
列出当前已注册的命令
php cordo list
全局命令应通过在应用对象中添加它们的方式注册到 ./cordo
文件中
$application->add(new SecurityCheckerCommand(new SecurityChecker()));
功能命令应注册到 app/[Context]/[PackageName]/UI/Console/commands.php
文件。
return [ YourConsoleCommand::class, AnotherConsoleCommand::class ];
注册新包
本框架使用按功能划分的包方法。这意味着您将代码组织在 app/
文件夹中的包中。
只需将您的包文件夹名称添加到 app/Register.php
protected static $register = [ 'Shop\Users', // add you packages here ];
一旦您的包被注册,框架将能够访问定义的路由、依赖注入容器定义、配置、命令等。
包结构
用户包默认包含实现的基本 CRUD 操作。
以下是代码的组织方式
app/Shop/Users/
.
├── Application
│ ├── Acl
│ │ └── UsersAcl.php
│ ├── Command
│ │ ├── CreateNewUser.php
│ │ ├── DeleteUser.php
│ │ ├── Handler
│ │ │ ├── CreateNewUserHandler.php
│ │ │ ├── DeleteUserHandler.php
│ │ │ ├── SendUserWelcomeMessageHandler.php
│ │ │ └── UpdateUserHandler.php
│ │ ├── SendUserWelcomeMessage.php
│ │ └── UpdateUser.php
│ ├── Event
│ │ ├── Listener
│ │ │ └── UserCreatedListener.php
│ │ └── Register
│ │ └── UsersListeners.php
│ ├── Query
│ │ ├── UserFilter.php
│ │ ├── UserQuery.php
│ │ └── UserView.php
│ ├── Service
│ │ └── UserQueryService.php
│ ├── config
│ │ └── users.php
│ ├── definitions.php
│ └── handlers.php
├── Domain
│ ├── Event
│ │ └── UserCreated.php
│ ├── User.php
│ ├── UserActive.php
│ ├── UserEmail.php
│ ├── UserId.php
│ ├── UserPassword.php
│ ├── UserPasswordHash.php
│ └── UserRepository.php
├── Infrastructure
│ └── Persistance
│ └── Doctrine
│ ├── ORM
│ │ ├── Metadata
│ │ │ └── App.Shop.Users.Domain.User.dcm.xml
│ │ └── UserDoctrineRepository.php
│ └── Query
│ ├── UserDoctrineFilter.php
│ └── UserDoctrineQuery.php
├── UI
│ ├── Console
│ │ ├── Command
│ │ │ └── CreateNewUserConsoleCommand.php
│ │ └── commands.php
│ ├── Http
│ │ ├── Auth
│ │ │ └── OAuth2UserCredentials.php
│ │ ├── Controller
│ │ │ ├── UserCommandsController.php
│ │ │ └── UserQueriesController.php
│ │ ├── Middleware
│ │ │ └── OAuthMiddleware.php
│ │ └── Route
│ │ ├── OAuthRoutes.php
│ │ └── UsersRoutes.php
│ ├── Transformer
│ │ └── UserTransformer.php
│ ├── Validator
│ │ ├── EmailExistsValidation.php
│ │ ├── NewUserValidator.php
│ │ └── UpdateUserValidator.php
│ ├── trans
│ │ ├── mail.en.yaml
│ │ ├── mail.es.yaml
│ │ └── mail.pl.yaml
│ └── views
│ └── mail
│ └── new-user-welcome.php
└── UsersInit.php
此结构由以下层组成:用户界面、应用、领域和 基础设施。
重要!
如果您想快速生成新模块的样板代码,有一个相应的命令
php cordo core:module-builder <context> <module_name> [module_archive_file]
您可以在 app/resources/module
中找到预先准备好的存档。
这将为您节省大量时间,因为它将生成典型 CRUD 的整个文件夹和文件结构。
路由
路由定义应位于 app/[Context]/[PackageName]/UI/Http/Route/[PackageName]Routes.php
文件中。路由加载类应继承自抽象类 Cordo\Core\Application\Service\Register\RoutesRegister
。
使用 FastRoute 进行路由,但进行了修改,允许使用按路由 中间件
。
生成 API 文档的最佳方式是使用 ApiDoc,但可以根据个人偏好进行更改。
依赖注入容器
DI 容器定义应放置在 app/[Context]/[PackageName]/Application/definitions.php
。
Cordo 使用 PHP-ID 作为 DI 容器,如需了解详细信息,请参阅 文档。
配置
全局配置文件应位于 config/ 目录中,而功能配置的位置应为:app/[Context]/[PackageName]/Application/config/
配置文件应返回 PHP 关联数组。支持多维数组。
用法
$limit = $config->get('users.limit');
其中 "users" 是配置文件的名称,以下段是数组的关联键。
数据库
数据库配置位于 bootstrap/db.php
文件中。框架使用 Doctrine 进行数据库存储和对象映射。
根据 CQRS 方法,首选使用 Doctrine ORM 进行存储,以及使用 Doctrine DBAL 进行查询。
Doctrine 已预先配置以支持 UUID。
也支持 XML 映射,因此您可以直接将领域模型与数据库表进行映射。您应将映射放置在 app/[Context]/[PackageName]/Infrastructure/Doctrine/ORM/Metadata/
。
当您的映射准备就绪后,您可以直接从 composer 创建/更新/删除模式。
composer schema-create composer schema-update composer schema-drop
邮件发送器
对于邮件,使用 Laminas Mail。目前有两个邮件传输驱动程序:log
(用于开发)和 smtp
。您可以在 config/mail.php
文件中定义您的邮件驱动程序和凭据。
要添加/更改驱动程序,只需在 bootstrap/app.php
中替换 MailerFactory
类即可。
国际化
翻译由Symfony 翻译处理。默认的文件格式为 Yaml
。
您应将翻译文件放在 app/[上下文]/[包名]/UI/trans/
文件夹或子文件夹中。命名约定为:[域].[语言].yaml
,例如:mail.en.yaml
。
用法
$translator->trans('hello', [], 'mail', 'en')
您可以通过在请求 URI 中添加 &lang
参数或运行控制台命令时添加 --lang
标志来设置每个请求的语言。
翻译配置文件位于 config/trans.php
。
视图
Plates 被用作模板引擎。将您的视图文件放在 app/[上下文]/[包名]/UI/views/
文件夹或子文件夹中。
用法
$templates->render('[context].[module]::[subfolder]/[template_name]', [ // data you want to pass to the template file ]);
命令总线
Cordo 使用 Tactician 命令总线来实现 命令模式
。
您的命令 -> 处理器映射应放在:app/[上下文]/[包名]/Application/handlers.php
文件中。
命令总线被配置为在每个单独的事务中锁定每个处理器,它还支持事件、队列、命令日志。请查看 bootstrap/command_bus.php
和 Tactician 文档以获取详细信息。
事件
与命令 -> 处理器映射不同,其中对于每个 命令 只能有一个 处理器,您可以为单个发出的事件有多个监听器。
您的监听器定义应位于:app/[上下文]/[包名]/Event/Loader/[包名]Listeners.php
。事件加载器类应扩展 Cordo\Core\Application\Service\Register\ListenersRegister
。
以下是发出事件的示例
/** * @var League\Event\EmitterInterface */ $emitter->emit('users.created', new UserCreated($command->email()));
在 app/[上下文]/[包名]/Application/events.php
文件中定义您的监听器(请参阅用户模块中的示例)
$emitter->addListener( 'users.created', static function ($event, UserCreated $userCreated) use ($container) { $listener = new UserCreatedListener($container); $listener->handle($userCreated); } );
队列
对于后台处理,使用 Bernard 库。
当前支持的驱动程序有
- Flatfile
- Redis 扩展
队列的配置文件位于此处,您可以指定在应用程序中使用的驱动程序:config/queue.php
。
如果您想使您的命令排队,只需实现 Cordo\Core\Application\Queue\MessageInterface
接口或扩展 Cordo\Core\Application\Queue\AbstractMessage
类。
要启动后台进程处理队列中的命令,请在控制台中运行
php queue-worker &
要更好地了解如何处理事件,请查看 Users Bundle 模块,并查看如何为新创建的用户发送欢迎信息。
注意:如果您想使用队列的 Redis 驱动程序,请确保您已安装 PHP 的 Redis 扩展。您可以从 PECL 仓库安装它。
$ sudo pecl install redis $ sudo service php7.4-fpm restart
OAuth2
此框架默认使用 OAuth2 作为授权方法。OAuth2 服务器配置位于:app/config/auth.php
。
有关真实生活中的 OAuth2 实现,请查看 Users Bundle)
ACL
为了授权的目的,使用了 Zend ACL。ACL 角色、资源、权限可以在每个包的 app/[上下文]/[包名]/Application/Acl/[包名]Acl.php
中单独定义,该文件应扩展 Cordo\Core\Application\Service\Register\AclRegister
。
在随 Users Bundle 一起提供的 Auth
包中,已经为用户 ACL 规则准备了 CRUD 操作。
错误
默认情况下,所有错误都记录到 storage/logs/error.log
文件中。
此外,在dev
环境中,错误将以美观格式通过Whoops显示在屏幕上。控制台中的错误也将进行美观格式化。在production
环境中,错误堆栈跟踪将被发送到在config/error.php
中定义的地址。
如果您想更改这些行为,可以在bootstrap/error.php
文件中实现。
致谢
许可证
MIT许可证(MIT)。有关更多信息,请参阅许可证文件。