timetoogo / penumbra
此包已被弃用,不再维护。未建议替代包。
面向域的ORM,集成了PHP 5.4+的查询
dev-dev
2014-07-31 12:19 UTC
Requires
- php: >=5.4.0
- nikic/php-parser: 0.9.4
Requires (Dev)
- phpunit/dbunit: >=1.2
- phpunit/phpunit: 3.7.*
This package is auto-updated.
Last update: 2020-08-24 21:34:16 UTC
README
面向域的ORM,专为PHP 5.4+精心打造。
Penumbra尚未完成,基础和架构已经有了,但代码库几乎没有任何单元测试。由于Penumbra最初是一个学习练习,目标是创建一个不影响域模型的orm,因此该项目保持了良好的代码质量,但很快就会变得明显,我无法单独开发和维护此项目,尤其是在学校期间。需要严肃的贡献者,请随意克隆存储库并查看代码库,如果您有任何问题、询问或想开始贡献,请通过电子邮件联系我:elliot@aanet.com.au。
请注意,这是我第一个大型开源项目,所以任何建议/推荐都欢迎。
PHP的另一个ORM?!
是的!Penumbra提供了一些其他ORM没有的特性。Penumbra是100%的数据映射器,旨在在提供强大的语言集成查询API的同时,完全解耦您的域模型。
Penumbra当前状态的概述
- ORM 功能正在运行,但远未稳定。
- 总体而言,保持了良好的代码质量。
- 仅设置就需要大量的工作。
- 代码库规模相当大(约15,000行代码)。
- API结构尚未最终确定。
- 测试套件令人震惊。
- 缺乏文档/代码注释。
- 需要严肃的贡献者。
Penumbra的目标
- 提供一种可维护且合理的复杂ORM领域的方法。
- 以无污染和灵活的域模型回报用户。
- 提供流畅的语言集成查询(类似于C#的LINQ)
- 减少对底层平台的查询数量,并帮助消除n+1查询。
灵活的域模型
Penumbra旨在尽可能减少对领域模型的限制
- Penumbra原生支持:字段、getter/setter,甚至是实体属性中的索引器或调用。
- 您的实体可以完全不感知Penumbra:无需基类、注解和持久化逻辑。
- 透明的关系加载和持久化。
- 实体间无缝的识别和非识别关系
- 内嵌对象
- 值对象
- 多态类型
PHP集成查询(Pinq)
- 以领域而不是数据库的方式查询。
- 抽象出底层数据库。
- 保持完整的IDE自动补全。
- 消除魔法字符串的烦恼,防止SQL注入。
- 强大的聚合API,
Count, Maximum, Minimum, Average, Sum, Implode, All, Any
- 支持用于参数化查询的变量
function ($_) use ($Value) {...
- 支持动态字段、方法调用、函数调用等。
- 甚至支持关系属性以实现无缝连接!
实体请求(SELECT
)- 示例
$MiddleAgedUsersRequest = $UserRepository->Request() ->Where(function (User $User) { return $User->GetAge() > 20 && $User->GetAge() < 50 ; }) ->OrderByDescending(function (User $User) { return $User->GetLastLoginDate(); }); $SomeActiveMiddleAgedUsers = $MiddleAgedUsersRequest->AsArray();
将映射为类似以下的内容
SELECT Users.* FROM Users WHERE Users.Age > 20 AND Users.Age < 50 ORDER BY Users.LastLoginDate DESC;
复杂数据请求(SELECT
)- 示例
$UserStatistics = $UserRepository->Request() ->From($MiddleAgedUsersRequest) ->Where(function (User $User) { return $User->IsActive(); }) ->GroupBy(function (User $User) { return $User->GetAge(); }) ->Select(function (User $User, IAggregate $Users) { return [ 'Age' => $User->GetAge(), 'Amount' => $Users->Count(), 'AverageVisits' => $Users->Average(function (User $User) { return $User->GetVisitsPerDay(); })), ]; });
将映射为类似以下的内容
SELECT Users.Age AS Age, COUNT(*) AS Amount, AVG(Users.VisitsPerDay) AS AverageVisits FROM (SELECT Users.* FROM Users WHERE Users.Age > 20 AND Users.Age < 50 ORDER BY Users.LastLoginDate DESC) AS Users WHERE Users.IsActive GROUP BY Users.Age;
存储过程(UPDATE
)- 示例
$InactiveUserProcedure = $UserRepository->Procedure( function (User $User) { $User->SetIsActive(false); $User->SetInactivationDate(new DateTime()); }) ->Where(function (User $User) { return $User->GetLastLoginDate() < (new DateTime())->sub(new DateInterval('P2Y')); }); $InactiveUserProcedure->Execute();
将映射为类似以下的内容
UPDATE Users SET Users.IsActive = 0, Users.InactivationDate = NOW() WHERE Users.LastLoginDate < DATE_SUB(NOW(), INTERVAL 2 YEAR)
注意:提供的函数实际上从未执行,它们被解析,然后映射到底层平台作为查询。
合理的查询
Penumbra的主要目标是在尽可能多的程度上利用底层数据库。
- Penumbra将在可能的情况下使用批量插入/更新和删除。
- 消除由过度懒加载引入的令人讨厌的N+1查询场景。使用Penumbra,目前有多个关系加载实现
Eager
- 关系与父实体一起加载,并且适当连接子实体。全局范围懒加载
- 关系不与父实体一起加载,但在需要时,全局将加载所有未加载的关系。请求范围懒加载
(推荐)- 当请求对象图中所有实体需要时加载关系。父范围懒加载
(可能N+1)- 当需要从每个父实体加载关系时加载关系。
示例
User是父实体,一个用户有多个帖子,一个帖子有一个作者和多个标签。这是典型的N+1场景。
$User = $UserRepository->LoadById(1); foreach($User->GetPosts() as $Post) { $Post->GetAuthor()->GetFullName(); foreach($Post->GetTags() as $Tag) { $Tag->GetName(); } }
以下是每种加载模式执行查询的数量(N=帖子数);
Eager
- 3(用户 | 帖子与作者连接 | 所有标签),当用户被加载时。全局范围懒加载
- 对于加载单个请求,这相当于下面的请求范围懒加载
模式。请求范围懒加载
- 4(用户 | 帖子 | 所有作者 | 所有标签),帖子将在迭代时加载,所有标签将在第一次迭代时加载。父范围懒加载
- (N * 2) + 2 -(用户 | 帖子 | 每个帖子的作者 | 每个帖子的标签)。
注意:关系加载模式是针对每个关系的,上面的示例假设每个关系都将有相同的加载模式以简化。