yuptogun / dootong
PHP DDD 的一种简单抽象动态伪 DTO 模型
dev-main
2023-04-04 00:53 UTC
Requires (Dev)
- phpunit/phpunit: ^9.5
- vlucas/phpdotenv: ^5.3
This package is auto-updated.
Last update: 2024-09-04 04:13:21 UTC
README
您在 PHP 中编写 DTO 的止痛药。
在韩语中,“头痛”是“두통”,罗马化为 DooTOng。
快速入门
class User extends Yuptogun\Dootong\Dootong { protected function getAttributes(): array { return ['id', 'email', 'username', 'password', 'created_at']; } protected function getRequiredAttributes(): array { return ['email', 'password']; } protected function getHiddenAttributes(): array { return []; } protected function getAttributeCastings(): array { return [ 'id' => 'increment', 'password' => 'password', 'created_at' => 'datetime', ]; } } $user = User::sufferFrom( (new MySQL(new PDO('mysql:host=localhost;dbname=test', 'test', 'test'))) ->diagnose("SELECT * FROM users WHERE email LIKE concat('%', :email)") ->prescribe("INSERT INTO users (email, username, pwd) VALUES (:email, :username, :pwd)") ); /** @var User[] $yahooUsers */ $yahooUsers = $user->get(['email' => '@yahoo.com']); foreach ($yahooUsers as $u) { /** @var int $id type casted */ $id = $u->id; /** @var null $timezone "hidden" */ $timezone = $u->timezone; } /** @var User $newUser */ $newUser = $user->get($user->set([ 'email' => 'foo@bar.com', 'username' => 'foo', 'pwd' => 'bar', ])); /** @var null $newUserPassword "password" type basically hidden */ $newUserPassword = $newUser->pwd; /** * "password" type works with comparison method. * if you have multiple password type attributes, specify one in the second argument. * * @var true $newUserPasswordCheck */ $newUserPasswordCheck = $newUser->isPassword('bar');
核心概念
一个 DTO,任何仓库
Dootong
是以一组属性及其处理方法表示的实体。Headache
是一个可以提供/保存实体的仓库。
任何 Dootong
都可以“受”任何类型的 Headache
的影响,只要它们能够相处。
use MyApp\DTO\Order; $redis = new Yuptogun\Dootong\Types\Redis($config); $mysql = new Yuptogun\Dootong\Types\MySQL($pdo); $ordersQueued = Order::setRepository($redis) ->diagnose('LRANGE orders 0 10') ->get(); foreach ($ordersQueued as $order) { Order::sufferFrom($mysql) ->prescribe("INSERT INTO orders (user_id, product_id) VALUES (:user_id, :product_id)") ->set([ 'user_id' => $order->user_id, 'product_id' => $order->product_id ]); }
针对现实世界问题
现实世界的查询不可避免地是杂乱的。
这是您在将它们建模为 ORM 时每天头痛的原因。
SELECT a.a_id AS `user_id`, max(a.a_name) AS `user_name`, ifnull(max(bc.bc_name), '') AS `purchase_name` FROM a LEFT JOIN ( SELECT b.a_id, b.b_name AS bc_name, concat(b.b_name, b.b_id) AS bc_id FROM b WHERE b.a_id = a.a_id AND b.created_at >= '2021-01-01 00:00:00' AND b.cancelled_at IS NULL UNION ALL SELECT c.a_id, c.c_name AS bc_name, concat(c.c_name, c.c_id) AS bc_id FROM c WHERE c.a_id = a.a_id AND c.created_at >= '2021-01-01 00:00:00' AND c.cancelled_at IS NULL ) bc ON bc.a_id = a.a_id WHERE a.email LIKE concat('%@', :email_domain) AND bc.bc_name LIKE concat('%', :product_name) GROUP BY a.a_id, bc.bc_id;
使用 Dootong
。一次定义您头痛的原因,得到诊断和处方。
然后一切开始运转。
class PaidUsersSince2021 extends MySQL { protected $getter = THE_QUERY_ABOVE; } $paidUsersSince2021 = PaidUser::sufferFrom(new PaidUsersSince2021($pdo))->get([ 'email_domain' => 'google.com', 'product_name' => 'painkiller 3000', ]);
如何贡献
一切都可以改进,包括这个 README。
单元测试
docker-compose up -d --build docker run --rm -it -v "$(pwd):/app" -w /app composer install --ignore-platform-reqs docker run --rm -it -v "$(pwd):/app" -w /app yuptogun/dootong-test-php php ./vendor/bin/phpunit tests