Brevemente sobre las especificaciones:
Una especificación es un patrón de diseño con el que puede reflejar las reglas de la lógica empresarial en forma de una cadena de objetos conectados por operaciones lógicas booleanas. Las especificaciones le permiten deshacerse de métodos duplicados y similares en el repositorio y la duplicación de la lógica empresarial.
Hoy en día hay dos (si conoce otros proyectos, por favor escriba en los comentarios) proyectos PHP exitosos y populares que le permitan describir las reglas comerciales en las especificaciones y filtrar los conjuntos de datos. Estas son RulerZ y Happyr Doctrine Specification . Ambos proyectos son herramientas poderosas con sus ventajas y desventajas. La comparación de estos proyectos dibujará un artículo completo. Aquí quiero contarles lo que nos trajo la nueva versión de la Especificación de Doctrina.
Brevemente sobre la especificación de la doctrina
Aquellos que estén más o menos familiarizados con el proyecto, pueden saltarse esta sección de manera segura.
Con la ayuda de este proyecto, puede describir especificaciones en forma de objetos, componiéndolas a partir de la composición y, por lo tanto, elaborar reglas comerciales complejas. Las composiciones resultantes pueden reutilizarse libremente y combinarse en composiciones aún más complejas que son fáciles de probar. La especificación de Doctrine se usa para construir consultas de Doctrine. En esencia, la Especificación de Doctrine es el nivel de abstracción sobre Doctrine ORM QueryBuilder y Doctrine ORM Query.
Las especificaciones se aplican a través del repositorio de Doctrine:
$result = $em->getRepository(MyEntity::class)->match($spec);
La especificación se puede aplicar manualmente, pero no es particularmente conveniente y, a la larga, no tiene sentido. $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();
Hay varios métodos en el repositorio:
match
: obtener todos los resultados correspondientes a la especificación;matchSingleResult
- equivalente de Query::getSingleResult()
;matchOneOrNullResult
: equivalente a matchSingleResult
, pero permite null
;getQuery
: crea un QueryBuilder al aplicarle una especificación y le devuelve un objeto Query.
Recientemente, se getQueryBuilder
ha agregado el método getQueryBuilder
, que crea un QueryBuilder y, al aplicarle la especificación, lo devuelve.
El proyecto identifica varios tipos de especificaciones:
Especificaciones lógicas
Las andX
y orX
también sirven como una colección de especificaciones.
Spec::andX()
Spec::orX()
Spec::not()
Es habitual instalar objetos de especificaciones de biblioteca a través de la fachada de Spec
, pero esto no es necesario. Puede crear una instancia explícita del objeto de especificación:
new AndX(); new OrX(): new Not();
Especificación de filtro
Las especificaciones de filtrado, de hecho, conforman las reglas de la lógica empresarial y se utilizan en la solicitud WHERE
. Estas incluyen operaciones de comparación:
isNull
- SQL IS NULL
equivalenteisNotNull
- SQL IS NOT NULL
equivalentein
- equivalente a IN ()
notIn
- NOT IN ()
equivalenteeq
- prueba de igualdad =
neq
- ¡busca desigualdad !=
lt
- menos de <
lte
- menor o igual que <=
gt
- más de >
gte
- mayor o igual que >=
like
- equivalente a SQL LIKE
instanceOfX
- equivalente de DQL INSTANCE OF
Un ejemplo de uso de especificaciones de filtrado:
$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')) ) ) );
Modificadores de consulta
Los modificadores de consulta no tienen nada que ver con la lógica comercial y las reglas comerciales. Como su nombre lo indica, solo modifican QueryBuilder. El nombre y el propósito de los modificadores predefinidos corresponden a métodos similares en QueryBuilder.
join
leftJoin
innerJoin
limit
offset
orderBy
groupBy
having
Quiero señalar por separado el modificador de slice
. Combina las funciones limit
y offset
y calcula el desplazamiento en función del tamaño del segmento y su número de serie. En la implementación de este modificador, no estamos de acuerdo con el autor del proyecto. Al crear un modificador, perseguí el objetivo de simplificar la configuración de las especificaciones durante la paginación. En este contexto, la primera página con el número de serie 1 debería haber sido equivalente al primer segmento con el número de serie 1. Pero el autor del proyecto consideró correcto comenzar la cuenta regresiva en un estilo de programación, es decir, desde 0. Por lo tanto, vale la pena recordar que si necesita el primer segmento, debe especificar 0 como número de serie.
Modificadores de resultados
Los modificadores de resultados existen ligeramente aparte de las especificaciones. Se aplican a Doctrine Query. Los siguientes modificadores controlan la hidratación de datos ( Query::setHydrationMode()
):
asArray
asSingleScalar
asScalar
El modificador de cache
controla el almacenamiento en caché del resultado de la consulta.
También debemos mencionar el modificador roundDateTimeParams
. Ayuda a resolver problemas de almacenamiento en caché cuando necesita trabajar con reglas comerciales que requieren comparar algunos valores con la hora actual. Estas son reglas comerciales normales, pero debido al hecho de que el tiempo no es constante, el almacenamiento en caché durante más de un segundo no funcionará para usted. El modificador roundDateTimeParams
está diseñado para resolver este problema. Revisa todos los parámetros de la solicitud, busca la fecha en ellos y lo redondea al valor especificado, lo que nos da valores de fecha que siempre son múltiplos de un valor y no obtendremos la fecha en el futuro. Es decir, si queremos almacenar en caché la solicitud durante 10 minutos, usamos Spec::cache(600)
y Spec::roundDateTimeParams(600)
. Inicialmente, se propuso combinar estos dos modificadores por conveniencia, pero se decidió separarlos para SRP.
Especificaciones integradas
Happyr Doctrine-Specification tiene una interfaz separada para especificaciones que combina un filtro y un modificador de solicitud. La única especificación predefinida es countOf
que le permite obtener el número de entidades correspondientes a la especificación. Para crear sus propias especificaciones, es costumbre extender la clase abstracta BaseSpecification
.
Innovaciones
Se han agregado nuevos métodos al repositorio:
matchSingleScalarResult
- equivalente de Query::getSingleScalarResult()
;matchScalarResult
- equivalente a Query::getScalarResult()
;iterate
es el equivalente de Query::iterate()
.
Se MemberOfX
especificación MemberOfX
se MemberOfX
el equivalente DQL de MEMBER OF
y el modificador de consulta indexBy
, el equivalente de QueryBuilder::indexBy()
.
Operandos
El nuevo lanzamiento introduce el concepto de Operand . Todas las condiciones en los filtros consisten en operandos izquierdo y derecho y un operador entre ellos.
<left_operand> <operator> <right_operand>
En versiones anteriores, el operando izquierdo solo podía ser un campo de entidad, y el operando derecho solo podía ser un valor. Este es un mecanismo simple y efectivo que es suficiente para la mayoría de las tareas. Al mismo tiempo, impone ciertas restricciones:
- Incapaz de usar funciones;
- No se pueden usar alias para campos;
- Es imposible comparar dos campos;
- Es imposible comparar dos valores;
- Incapaz de usar operaciones aritméticas;
- No se puede especificar el tipo de datos para el valor.
En la nueva versión, los objetos de operando se pasan a los filtros en argumentos y su transformación en DQL se delega a los propios operandos. Esto abre muchas posibilidades y facilita los filtros.
Campo y valor
Para mantener la compatibilidad con versiones anteriores, el primer argumento de los filtros se convierte en un operando de campo si no es un operando, y el último argumento también se convierte en un operando de valor. Por lo tanto, no debería tener problemas para actualizar.
Puedes comparar 2 campos:
Puede comparar 2 campos de diferentes entidades:
Operaciones aritméticas
Soporte agregado para operaciones aritméticas estándar -
, +
, *
, /
, %
. Por ejemplo, considere el cálculo de puntos de usuario:
Las operaciones aritméticas se pueden anidar una en otra:
Las funciones
La nueva versión agregó operandos con funciones. Se pueden usar como métodos estáticos de la clase Spec
, o mediante el método Spec::fun()
.
Las funciones se pueden anidar una en otra:
Los argumentos para las funciones se pueden pasar como argumentos separados, o pasándolos en una matriz:
Gestión de muestreo
Algunas veces necesita administrar una lista de valores de retorno. Por ejemplo:
- Agregue otra entidad al resultado para no hacer subconsultas para obtener los enlaces;
- Para devolver no toda la entidad, sino solo un conjunto de campos separados;
- Usa alias;
- Utilice alias ocultos con condiciones para la clasificación (requiere Doctrine, pero prometen arreglarlo ).
Antes de la versión 0.8.0, estas tareas requerían la creación de especificaciones para estas necesidades. A partir de la versión 0.8.0, puede usar el método getQueryBuilder()
y administrar la selección a través de la interfaz QueryBuilder.
La nueva versión 1.0.0 agrega los addSelect
solicitud select
y addSelect
. select
reemplaza completamente la lista de valores seleccionables, y addSelect
agrega nuevos valores a la lista. Como valor, puede usar un objeto que implemente la interfaz de Selection
o un filtro. Por lo tanto, puede ampliar las capacidades de la biblioteca para satisfacer sus necesidades. Considere las oportunidades que ya existen.
Puedes seleccionar un campo:
Puede agregar un campo a la selección:
Puede seleccionar varios campos:
Puede agregar una entidad a los valores devueltos:
Puede usar alias para campos seleccionables:
Puede agregar campos ocultos a la selección:
Puede usar expresiones, por ejemplo, para obtener un descuento en un producto:
Puede usar alias en las especificaciones:
Eso es básicamente todo. Aquí es donde terminan las innovaciones. El nuevo lanzamiento ha traído muchas características interesantes y útiles. Espero que te hayan interesado.
PD: Puedo usar un ejemplo para analizar el uso de especificaciones y mostrar las ventajas y desventajas de su uso. Si esto es interesante para usted, escriba en los comentarios o en PM.