简要介绍一下规格:
规范是一种设计模式,您可以用它以布尔逻辑操作连接的对象链的形式反映业务逻辑规则。 规范允许您摆脱存储库中的重复,相似方法以及业务逻辑重复。
今天,有两个(如果您了解其他项目,请在评论中写下)成功且流行的PHP项目,这些项目使您可以在规范和过滤数据集中描述业务规则。 这些是RulerZ和Happyr学说规范 。 这两个项目都是有优势和劣势的强大工具。 比较这些项目将得出整篇文章。 在这里,我想告诉您“ Doctrine规范”中的新版本给我们带来了什么。
简要介绍教义规范
那些或多或少熟悉该项目的人可以安全地跳过此部分。
在该项目的帮助下,您可以以对象的形式描述规范,从组成上将其组成,从而制定复杂的业务规则。 所得的组合物可以自由地重复使用,并且可以组合成甚至更容易测试的复杂组合物。 原则规范用于构建原则查询。 从本质上讲,Doctrine规范是对Doctrine ORM QueryBuilder和Doctrine ORM Query的抽象级别。
规范适用于“教义存储库”:
$result = $em->getRepository(MyEntity::class)->match($spec);
该规范可以手动应用,但并不是特别方便,并且从长远来看毫无意义。 $spec = ... $alias = 'e'; $qb = $em->getRepository(MyEntity::class)->createQueryBuilder($alias); $spec->modify($qb, $alias); $filter = (string) $spec->getFilter($qb, $alias); $qb->andWhere($filter); $result = $qb->getQuery()->execute();
存储库中有几种方法:
match
-获取与规范相对应的所有结果;matchSingleResult
等效于Query::getSingleResult()
;matchOneOrNullResult
等同于matchSingleResult
,但允许为null
;getQuery
通过对其应用规范来创建QueryBuilder并从中返回Query对象。
最近,已经向其中添加了getQueryBuilder
方法,该方法创建了一个QueryBuilder并将其应用规范返回。
该项目确定了几种类型的规范:
逻辑规格
andX
和orX
也用作orX
的集合。
Spec::andX()
Spec::orX()
Spec::not()
通常通过Spec
外观安装库规范的对象,但这不是必需的。 您可以显式实例化规范对象:
new AndX(); new OrX(): new Not();
过滤器规格
实际上,过滤规范构成了业务逻辑规则,并在WHERE
请求中使用。 其中包括比较操作:
isNull
-SQL IS NULL
等效isNotNull
等效的SQL IS NOT NULL
- in-相当于
IN ()
notIn
相当于NOT IN ()
eq
相等测试=
neq
检查不平等!=
lt
小于<
lte
小于或等于<=
gt
大于>
gte
大于或等于>=
like
-SQL LIKE
等效instanceOfX
等效于DQL INSTANCE OF
使用过滤规范的示例:
$spec = Spec::andX( Spec::eq('ended', 0), Spec::orX( Spec::lt('endDate', new \DateTime()), Spec::andX( Spec::isNull('endDate'), Spec::lt('startDate', new \DateTime('-4 weeks')) ) ) );
查询修饰符
查询修饰符与业务逻辑和业务规则无关。 顾名思义,它们仅修改QueryBuilder。 预定义修饰符的名称和目的与QueryBuilder中的类似方法相对应。
join
leftJoin
innerJoin
limit
offset
orderBy
groupBy
having
我要单独注意slice
修改器。 它结合了limit
和offset
功能,并根据切片的大小及其序列号计算偏移量。 在实现此修饰符时,我们不同意该项目的作者。 创建修饰符后,我追求的目标是简化分页期间的规格配置。 在这种情况下,序列号为1的第一页应该与序列号为1的第一个切片等效。但是项目作者认为以编程样式即0开始倒计时是正确的。因此,值得记住的是,如果需要第一个切片,则需要指定0作为序列号。
结果修饰符
结果修饰符与规范略有不同。 它们适用于学说查询。 以下修饰符控制数据水合( Query::setHydrationMode()
):
asArray
asSingleScalar
asScalar
cache
修改器控制查询结果的缓存。
我们还应该提到修饰符roundDateTimeParams
。 当您需要使用需要将一些值与当前时间进行比较的业务规则时,它有助于解决缓存问题。 这些是正常的业务规则,但是由于时间不是恒定的,因此缓存一秒钟以上对您不起作用。 roundDateTimeParams
修饰符旨在解决此问题。 它遍历请求的所有参数,在其中搜索日期,并将其四舍五入为指定的值,这将使我们获得的日期值始终是一个值的倍数,而将来我们将无法获得日期。 也就是说,如果我们想将请求缓存10分钟,则可以使用Spec::cache(600)
和Spec::roundDateTimeParams(600)
。 最初,为了方便起见,建议将这两个修饰符结合在一起,但决定将它们分开以进行SRP。
嵌入式规格
Happyr Doctrine-Specification具有单独的规范接口,该接口结合了过滤器和请求修饰符。 唯一的预定义规范是countOf
它允许您获取与规范相对应的实体数。 要创建自己的规范,通常会扩展抽象BaseSpecification
类。
革新性
新方法已添加到存储库:
matchSingleScalarResult
等效于Query::getSingleScalarResult()
;matchScalarResult
等同于Query::getScalarResult()
;iterate
等效于Query::iterate()
。
MemberOfX
了MemberOfX
规范- MemberOfX
了MEMBER OF
的DQL等效项MEMBER OF
并且indexBy
了indexBy
查询修饰符-了QueryBuilder::indexBy()
的等效项。
操作数
新版本引入了Operand的概念。 过滤器中的所有条件均由左右操作数以及它们之间的运算符组成。
<left_operand> <operator> <right_operand>
在以前的版本中,左操作数只能是一个实体字段,而右操作数只能是一个值。 这是一种简单有效的机制,足以完成大多数任务。 同时,它施加了某些限制:
- 无法使用功能;
- 不能为字段使用别名;
- 比较两个字段是不可能的。
- 比较两个值是不可能的。
- 无法使用算术运算;
- 无法为值指定数据类型。
在新版本中,将操作数对象传递到参数中的过滤器,并将它们在DQL中的转换委派给操作数本身。 这开辟了许多可能性,并使过滤器更容易。
领域与价值
为了保持向后兼容性,如果过滤器中的第一个参数不是操作数,则将其转换为字段操作数,最后一个参数也将转换为值操作数。 因此,您应该没有问题更新。
您可以比较2个字段:
您可以比较不同实体的2个字段:
算术运算
添加了对标准算术运算符-
, +
, *
, /
, %
。 例如,考虑用户点的计算:
算术运算可以相互嵌套:
功能介绍
新版本添加了带有函数的操作数。 它们可以用作Spec
类的静态方法,也可以通过Spec::fun()
方法使用。
函数可以彼此嵌套:
函数的参数可以作为单独的参数传递,也可以通过将其传递给数组来传递:
抽样管理
有时您需要管理一个返回值列表。 例如:
- 在结果中添加另一个实体,以免进行子查询来获取链接;
- 不返回整个实体,而是仅返回一组单独的字段;
- 使用别名;
- 使用带有隐藏条件的别名进行排序(它要求使用Doctrine,但它们承诺会对其进行修复 )。
在0.8.0版之前,这些任务需要创建满足这些需求的规范。 从版本0.8.0开始,可以使用getQueryBuilder()
方法并通过QueryBuilder界面管理选择。
新版本1.0.0添加了select
和addSelect
请求addSelect
。 select
完全替换了可选值列表,而addSelect
将新值添加到列表中。 作为值,可以使用实现Selection
接口或过滤器的对象。 因此,您可以根据需要扩展库的功能。 考虑已经存在的机会。
您可以选择一个字段:
您可以将一个字段添加到选择中:
您可以选择几个字段:
您可以将实体添加到返回值:
您可以对可选字段使用别名:
您可以将隐藏字段添加到选择中:
例如,您可以使用表达式来获得产品的折扣:
您可以在规范中使用别名:
基本上就是这些。 这就是创新的终点。 新版本带来了许多有趣且有用的功能。 我希望他们对你感兴趣。
PS:我可以通过一个示例分析规范的使用,并说明使用规范的优缺点。 如果您对此感兴趣,请在评论中或PM中写。