diff options
author | Carl Schwan <carl@carlschwan.eu> | 2022-07-11 13:03:16 +0300 |
---|---|---|
committer | Carl Schwan <carl@carlschwan.eu> | 2022-08-24 13:36:11 +0300 |
commit | 0971a9ea53419d84607c96b250e630963b6eb331 (patch) | |
tree | 616beb6082c686eecc1fce103b791a96f05f4a59 /lib/public | |
parent | 1b9768bde23ad64bb8553495c7cbdfc0fc564900 (diff) |
fixup! Introduce Doctrine ORM
Diffstat (limited to 'lib/public')
-rw-r--r-- | lib/public/DB/ORM/IEntityManager.php | 7 | ||||
-rw-r--r-- | lib/public/DB/ORM/IEntityRepository.php | 16 | ||||
-rw-r--r-- | lib/public/DB/ORM/IParameter.php | 4 | ||||
-rw-r--r-- | lib/public/DB/ORM/IQuery.php | 11 | ||||
-rw-r--r-- | lib/public/DB/ORM/IQueryBuilder.php | 553 | ||||
-rw-r--r-- | lib/public/IContainer.php | 1 |
6 files changed, 580 insertions, 12 deletions
diff --git a/lib/public/DB/ORM/IEntityManager.php b/lib/public/DB/ORM/IEntityManager.php index 355c743b604..9c44af63a64 100644 --- a/lib/public/DB/ORM/IEntityManager.php +++ b/lib/public/DB/ORM/IEntityManager.php @@ -1,5 +1,10 @@ <?php +declare(strict_types=1); + +// SPDX-FileCopyrightText: Carl Schwan <carl@carlschwan.eu> +// SPDX-License-Identifier: AGPL-3.0-or-later + namespace OCP\DB\ORM; use DateTimeInterface; @@ -17,6 +22,8 @@ interface IEntityManager { */ public function createQuery(string $dql = ''): IQuery; + public function createQueryBuilder(): IQueryBuilder; + /** * Flushes all changes to objects that have been queued up to now to the database. * This effectively synchronizes the in-memory state of managed objects with the diff --git a/lib/public/DB/ORM/IEntityRepository.php b/lib/public/DB/ORM/IEntityRepository.php index 3ec5f72b1f7..2d43932a613 100644 --- a/lib/public/DB/ORM/IEntityRepository.php +++ b/lib/public/DB/ORM/IEntityRepository.php @@ -7,8 +7,7 @@ namespace OCP\DB\ORM; * * @template-covariant T of object */ -interface IEntityRepository -{ +interface IEntityRepository { /** * Finds an object by its primary key / identifier. * @@ -17,7 +16,7 @@ interface IEntityRepository * @return object|null The object. * @psalm-return T|null */ - public function find($id); + public function find($id): ?object; /** * Finds all objects in the repository. @@ -25,7 +24,7 @@ interface IEntityRepository * @return array<int, object> The objects. * @psalm-return T[] */ - public function findAll(); + public function findAll(): array; /** * Finds objects by a set of criteria. @@ -48,22 +47,21 @@ interface IEntityRepository ?array $orderBy = null, ?int $limit = null, ?int $offset = null - ); + ): array; /** * Finds a single object by a set of criteria. * * @param array<string, mixed> $criteria The criteria. * - * @return object|null The object. - * @psalm-return T|null + * @return T|null */ - public function findOneBy(array $criteria); + public function findOneBy(array $criteria): ?object; /** * Returns the class name of the object managed by the repository. * * @psalm-return class-string<T> */ - public function getClassName(); + public function getClassName(): string; } diff --git a/lib/public/DB/ORM/IParameter.php b/lib/public/DB/ORM/IParameter.php index 00f3050f740..3fc7880ec0a 100644 --- a/lib/public/DB/ORM/IParameter.php +++ b/lib/public/DB/ORM/IParameter.php @@ -7,7 +7,7 @@ interface IParameter { /** * Retrieves the Parameter name. */ - public function getName(): string + public function getName(): string; /** * Retrieves the Parameter value. @@ -31,7 +31,7 @@ interface IParameter { * * @return void */ - public function setValue($value, $type = null): void + public function setValue($value, $type = null): void; public function typeWasSpecified(): bool; } diff --git a/lib/public/DB/ORM/IQuery.php b/lib/public/DB/ORM/IQuery.php index f84c5230d71..4c0477ace56 100644 --- a/lib/public/DB/ORM/IQuery.php +++ b/lib/public/DB/ORM/IQuery.php @@ -2,6 +2,8 @@ namespace OCP\DB\ORM; +use Doctrine\Common\Collections\ArrayCollection; + interface IQuery { /** * Enable/disable second level query (result) caching for this query. @@ -79,4 +81,13 @@ interface IQuery { public function getSingleScalarResult(); + public function getSql(): string; + + /** + * Get all defined parameters. + * + * @return ArrayCollection The defined query parameters. + * @psalm-return ArrayCollection<int, \Doctrine\ORM\Query\Parameter> + */ + public function getParameters(): ArrayCollection; } diff --git a/lib/public/DB/ORM/IQueryBuilder.php b/lib/public/DB/ORM/IQueryBuilder.php new file mode 100644 index 00000000000..8a5106c9c80 --- /dev/null +++ b/lib/public/DB/ORM/IQueryBuilder.php @@ -0,0 +1,553 @@ +<?php + +declare(strict_types=1); + +// SPDX-FileCopyrightText: Carl Schwan <carl@carlschwan.eu> +// SPDX-License-Identifier: AGPL-3.0-or-later + +namespace OCP\DB\ORM; + +use DateTimeInterface; +use OCP\IDBConnection; + +/** + * @since 25.0.0 + */ +interface IQueryBuilder { + /** + * Gets an ExpressionBuilder used for object-oriented construction of query expressions. + * This producer method is intended for convenient inline usage. Example: + * + * <code> + * $qb = $em->createQueryBuilder(); + * $qb + * ->select('u') + * ->from('User', 'u') + * ->where($qb->expr()->eq('u.id', 1)); + * </code> + * + * For more complex expression construction, consider storing the expression + * builder object in a local variable. + */ + public function expr(): Query\Expr; + + /** + * Sets a query parameter for the query being constructed. + * + * <code> + * $qb = $em->createQueryBuilder() + * ->select('u') + * ->from('User', 'u') + * ->where('u.id = :user_id') + * ->setParameter('user_id', 1); + * </code> + * + * @param string|int $key The parameter position or name. + * @param mixed $value The parameter value. + * @param string|int|null $type ParameterType::* or \Doctrine\DBAL\Types\Type::* constant + */ + public function setParameter($key, $value, $type = null): self; + + /** + * Sets a collection of query parameters for the query being constructed. + * + * <code> + * $qb = $em->createQueryBuilder() + * ->select('u') + * ->from('User', 'u') + * ->where('u.id = :user_id1 OR u.id = :user_id2') + * ->setParameters(new ArrayCollection(array( + * new Parameter('user_id1', 1), + * new Parameter('user_id2', 2) + * ))); + * </code> + * + * @param ArrayCollection|mixed[] $parameters The query parameters to set. + * @psalm-param ArrayCollection<int, Parameter>|mixed[] $parameters + */ + public function setParameters($parameters): self; + + /** + * Gets all defined query parameters for the query being constructed. + * + * @return ArrayCollection The currently defined query parameters. + * @psalm-return ArrayCollection<int, Parameter> + */ + public function getParameters(); + + /** + * Gets a (previously set) query parameter of the query being constructed. + * + * @param string|int $key The key (index or name) of the bound parameter. + * + * @return Parameter|null The value of the bound parameter. + */ + public function getParameter($key): ?IParameter; + + /** + * Sets the position of the first result to retrieve (the "offset"). + * + * @param int|null $firstResult The first result to return. + * + * @return $this + */ + public function setFirstResult(?int $firstResult): self + + /** + * Gets the position of the first result the query object was set to retrieve (the "offset"). + * Returns NULL if {@link setFirstResult} was not applied to this QueryBuilder. + * + * @return int|null The position of the first result. + */ + public function getFirstResult(): ?int; + + /** + * Sets the maximum number of results to retrieve (the "limit"). + * + * @param int|null $maxResults The maximum number of results to retrieve. + */ + public function setMaxResults(?int $maxResults): self; + + /** + * Gets the maximum number of results the query object was set to retrieve (the "limit"). + * Returns NULL if {@link setMaxResults} was not applied to this query builder. + * + * @return int|null Maximum number of results. + */ + public function getMaxResults(): ?int; + + /** + * Specifies an item that is to be returned in the query result. + * Replaces any previously specified selections, if any. + * + * <code> + * $qb = $em->createQueryBuilder() + * ->select('u', 'p') + * ->from('User', 'u') + * ->leftJoin('u.Phonenumbers', 'p'); + * </code> + * + * @param mixed $select The selection expressions. + */ + public function select($select = null): self; + + /** + * Adds a DISTINCT flag to this query. + * + * <code> + * $qb = $em->createQueryBuilder() + * ->select('u') + * ->distinct() + * ->from('User', 'u'); + * </code> + */ + public function distinct(bool $flag = true): self; + + /** + * Adds an item that is to be returned in the query result. + * + * <code> + * $qb = $em->createQueryBuilder() + * ->select('u') + * ->addSelect('p') + * ->from('User', 'u') + * ->leftJoin('u.Phonenumbers', 'p'); + * </code> + * + * @param mixed $select The selection expression. + */ + public function addSelect($select = null): self; + + /** + * Turns the query being built into a bulk delete query that ranges over + * a certain entity type. + * + * <code> + * $qb = $em->createQueryBuilder() + * ->delete('User', 'u') + * ->where('u.id = :user_id') + * ->setParameter('user_id', 1); + * </code> + * + * @param string|null $delete The class/type whose instances are subject to the deletion. + * @param string|null $alias The class/type alias used in the constructed query. + */ + public function delete(?string $delete = null, ?string $alias = null): self; + + /** + * Turns the query being built into a bulk update query that ranges over + * a certain entity type. + * + * <code> + * $qb = $em->createQueryBuilder() + * ->update('User', 'u') + * ->set('u.password', '?1') + * ->where('u.id = ?2'); + * </code> + * + * @param string|null $update The class/type whose instances are subject to the update. + * @param string|null $alias The class/type alias used in the constructed query. + */ + public function update(?string $update = null, ?string $alias = null): self; + + /** + * Creates and adds a query root corresponding to the entity identified by the given alias, + * forming a cartesian product with any existing query roots. + * + * <code> + * $qb = $em->createQueryBuilder() + * ->select('u') + * ->from('User', 'u'); + * </code> + * + * @param string $from The class name. + * @param string $alias The alias of the class. + * @param string|null $indexBy The index for the from. + * + * @return $this + */ + public function from(string $from, string $alias, ?string $indexBy = null); + + /** + * Updates a query root corresponding to an entity setting its index by. This method is intended to be used with + * EntityRepository->createQueryBuilder(), which creates the initial FROM clause and do not allow you to update it + * setting an index by. + * + * <code> + * $qb = $userRepository->createQueryBuilder('u') + * ->indexBy('u', 'u.id'); + * + * // Is equivalent to... + * + * $qb = $em->createQueryBuilder() + * ->select('u') + * ->from('User', 'u', 'u.id'); + * </code> + * + * @param string $alias The root alias of the class. + * @param string $indexBy The index for the from. + * + * @throws Query\QueryException + */ + public function indexBy(string $alias, string $indexBy): self; + + /** + * Creates and adds a join over an entity association to the query. + * + * The entities in the joined association will be fetched as part of the query + * result if the alias used for the joined association is placed in the select + * expressions. + * + * <code> + * $qb = $em->createQueryBuilder() + * ->select('u') + * ->from('User', 'u') + * ->join('u.Phonenumbers', 'p', Expr\Join::WITH, 'p.is_primary = 1'); + * </code> + * + * @param string $join The relationship to join. + * @param string $alias The alias of the join. + * @param string|null $conditionType The condition type constant. Either ON or WITH. + * @param string|Expr\Comparison|Expr\Composite|null $condition The condition for the join. + * @param string|null $indexBy The index for the join. + * @psalm-param Expr\Join::ON|Expr\Join::WITH|null $conditionType + */ + public function join(string $join, string $alias, ?string $conditionType = null, $condition = null, ?string $indexBy = null): self; + + /** + * Creates and adds a join over an entity association to the query. + * + * The entities in the joined association will be fetched as part of the query + * result if the alias used for the joined association is placed in the select + * expressions. + * + * [php] + * $qb = $em->createQueryBuilder() + * ->select('u') + * ->from('User', 'u') + * ->innerJoin('u.Phonenumbers', 'p', Expr\Join::WITH, 'p.is_primary = 1'); + * + * @param string $join The relationship to join. + * @param string $alias The alias of the join. + * @param string|null $conditionType The condition type constant. Either ON or WITH. + * @param string|Expr\Comparison|Expr\Composite|null $condition The condition for the join. + * @param string|null $indexBy The index for the join. + * @psalm-param Expr\Join::ON|Expr\Join::WITH|null $conditionType + */ + public function innerJoin(string $join, string $alias, ?string $conditionType = null, $condition = null, ?string $indexBy = null): self; + + /** + * Creates and adds a left join over an entity association to the query. + * + * The entities in the joined association will be fetched as part of the query + * result if the alias used for the joined association is placed in the select + * expressions. + * + * <code> + * $qb = $em->createQueryBuilder() + * ->select('u') + * ->from('User', 'u') + * ->leftJoin('u.Phonenumbers', 'p', Expr\Join::WITH, 'p.is_primary = 1'); + * </code> + * + * @param string $join The relationship to join. + * @param string $alias The alias of the join. + * @param string|null $conditionType The condition type constant. Either ON or WITH. + * @param string|Expr\Comparison|Expr\Composite|null $condition The condition for the join. + * @param string|null $indexBy The index for the join. + * @psalm-param Expr\Join::ON|Expr\Join::WITH|null $conditionType + * + * @return $this + */ + public function leftJoin(string $join, string $alias, $conditionType = null, $condition = null, ?string $indexBy = null); + + /** + * Sets a new value for a field in a bulk update query. + * + * <code> + * $qb = $em->createQueryBuilder() + * ->update('User', 'u') + * ->set('u.password', '?1') + * ->where('u.id = ?2'); + * </code> + * + * @param string $key The key/field to set. + * @param mixed $value The value, expression, placeholder, etc. + */ + public function set(string $key, $value): self; + + /** + * Specifies one or more restrictions to the query result. + * Replaces any previously specified restrictions, if any. + * + * <code> + * $qb = $em->createQueryBuilder() + * ->select('u') + * ->from('User', 'u') + * ->where('u.id = ?'); + * + * // You can optionally programmatically build and/or expressions + * $qb = $em->createQueryBuilder(); + * + * $or = $qb->expr()->orX(); + * $or->add($qb->expr()->eq('u.id', 1)); + * $or->add($qb->expr()->eq('u.id', 2)); + * + * $qb->update('User', 'u') + * ->set('u.password', '?') + * ->where($or); + * </code> + * + * @param mixed $predicates The restriction predicates. + * + * @return $this + */ + public function where($predicates) + { + if (! (func_num_args() === 1 && $predicates instanceof Expr\Composite)) { + $predicates = new Expr\Andx(func_get_args()); + } + + return $this->add('where', $predicates); + } + + /** + * Adds one or more restrictions to the query results, forming a logical + * conjunction with any previously specified restrictions. + * + * <code> + * $qb = $em->createQueryBuilder() + * ->select('u') + * ->from('User', 'u') + * ->where('u.username LIKE ?') + * ->andWhere('u.is_active = 1'); + * </code> + * + * @see where() + * + * @param mixed $where The query restrictions. + * + * @return $this + */ + public function andWhere() + { + $args = func_get_args(); + $where = $this->getDQLPart('where'); + + if ($where instanceof Expr\Andx) { + $where->addMultiple($args); + } else { + array_unshift($args, $where); + $where = new Expr\Andx($args); + } + + return $this->add('where', $where); + } + + /** + * Adds one or more restrictions to the query results, forming a logical + * disjunction with any previously specified restrictions. + * + * <code> + * $qb = $em->createQueryBuilder() + * ->select('u') + * ->from('User', 'u') + * ->where('u.id = 1') + * ->orWhere('u.id = 2'); + * </code> + * + * @see where() + * + * @param mixed $where The WHERE statement. + * + * @return $this + */ + public function orWhere() + { + $args = func_get_args(); + $where = $this->getDQLPart('where'); + + if ($where instanceof Expr\Orx) { + $where->addMultiple($args); + } else { + array_unshift($args, $where); + $where = new Expr\Orx($args); + } + + return $this->add('where', $where); + } + + /** + * Specifies a grouping over the results of the query. + * Replaces any previously specified groupings, if any. + * + * <code> + * $qb = $em->createQueryBuilder() + * ->select('u') + * ->from('User', 'u') + * ->groupBy('u.id'); + * </code> + * + * @param string $groupBy The grouping expression. + * + * @return $this + */ + public function groupBy($groupBy) + { + return $this->add('groupBy', new Expr\GroupBy(func_get_args())); + } + + /** + * Adds a grouping expression to the query. + * + * <code> + * $qb = $em->createQueryBuilder() + * ->select('u') + * ->from('User', 'u') + * ->groupBy('u.lastLogin') + * ->addGroupBy('u.createdAt'); + * </code> + * + * @param string $groupBy The grouping expression. + * + * @return $this + */ + public function addGroupBy($groupBy) + { + return $this->add('groupBy', new Expr\GroupBy(func_get_args()), true); + } + + /** + * Specifies a restriction over the groups of the query. + * Replaces any previous having restrictions, if any. + * + * @param mixed $having The restriction over the groups. + * + * @return $this + */ + public function having($having) + { + if (! (func_num_args() === 1 && ($having instanceof Expr\Andx || $having instanceof Expr\Orx))) { + $having = new Expr\Andx(func_get_args()); + } + + return $this->add('having', $having); + } + + /** + * Adds a restriction over the groups of the query, forming a logical + * conjunction with any existing having restrictions. + * + * @param mixed $having The restriction to append. + * + * @return $this + */ + public function andHaving($having) + { + $args = func_get_args(); + $having = $this->getDQLPart('having'); + + if ($having instanceof Expr\Andx) { + $having->addMultiple($args); + } else { + array_unshift($args, $having); + $having = new Expr\Andx($args); + } + + return $this->add('having', $having); + } + + /** + * Adds a restriction over the groups of the query, forming a logical + * disjunction with any existing having restrictions. + * + * @param mixed $having The restriction to add. + * + * @return $this + */ + public function orHaving($having) + { + $args = func_get_args(); + $having = $this->getDQLPart('having'); + + if ($having instanceof Expr\Orx) { + $having->addMultiple($args); + } else { + array_unshift($args, $having); + $having = new Expr\Orx($args); + } + + return $this->add('having', $having); + } + + /** + * Specifies an ordering for the query results. + * Replaces any previously specified orderings, if any. + * + * @param string|Expr\OrderBy $sort The ordering expression. + * @param string|null $order The ordering direction. + * + * @return $this + */ + public function orderBy($sort, $order = null) + { + $orderBy = $sort instanceof Expr\OrderBy ? $sort : new Expr\OrderBy($sort, $order); + + return $this->add('orderBy', $orderBy); + } + + /** + * Adds an ordering to the query results. + * + * @param string|Expr\OrderBy $sort The ordering expression. + * @param string|null $order The ordering direction. + * + * @return $this + */ + public function addOrderBy($sort, $order = null) + { + $orderBy = $sort instanceof Expr\OrderBy ? $sort : new Expr\OrderBy($sort, $order); + + return $this->add('orderBy', $orderBy, true); + } +} diff --git a/lib/public/IContainer.php b/lib/public/IContainer.php index 08634ad508f..aaa2cafeb67 100644 --- a/lib/public/IContainer.php +++ b/lib/public/IContainer.php @@ -40,7 +40,6 @@ use Psr\Container\ContainerInterface; * IContainer is the basic interface to be used for any internal dependency injection mechanism * * @since 6.0.0 - * @deprecated 20.0.0 use \Psr\Container\ContainerInterface */ interface IContainer extends ContainerInterface { |