%PDF- %PDF-
Direktori : /www/varak.net/nextcloud.varak.net/apps_old/apps/circles/lib/Tools/Db/ |
Current File : //www/varak.net/nextcloud.varak.net/apps_old/apps/circles/lib/Tools/Db/ExtendedQueryBuilder.php |
<?php declare(strict_types=1); /** * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\Circles\Tools\Db; use DateInterval; use DateTime; use Doctrine\DBAL\Query\QueryBuilder as DBALQueryBuilder; use Exception; use OC; use OC\DB\QueryBuilder\QueryBuilder; use OC\SystemConfig; use OCA\Circles\Tools\Exceptions\DateTimeException; use OCA\Circles\Tools\Exceptions\InvalidItemException; use OCA\Circles\Tools\Exceptions\RowNotFoundException; use OCA\Circles\Tools\Traits\TArrayTools; use OCP\DB\QueryBuilder\ICompositeExpression; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\IDBConnection; use Psr\Log\LoggerInterface; class ExtendedQueryBuilder extends QueryBuilder { use TArrayTools; /** @var string */ private $defaultSelectAlias = ''; /** @var array */ private $defaultValues = []; public function __construct() { parent::__construct( OC::$server->get(IDBConnection::class), OC::$server->get(SystemConfig::class), OC::$server->get(LoggerInterface::class) ); } /** * @param string $alias * * @return self */ public function setDefaultSelectAlias(string $alias): self { $this->defaultSelectAlias = $alias; return $this; } /** * @return string */ public function getDefaultSelectAlias(): string { return $this->defaultSelectAlias; } /** * @return array */ public function getDefaultValues(): array { return $this->defaultValues; } /** * @param string $key * @param string $value * * @return $this */ public function addDefaultValue(string $key, string $value): self { $this->defaultValues[$key] = $value; return $this; } /** * @param int $size * @param int $page */ public function paginate(int $size, int $page = 0): void { if ($page < 0) { $page = 0; } $this->chunk($page * $size, $size); } /** * @param int $offset * @param int $limit */ public function chunk(int $offset, int $limit): void { if ($offset > -1) { $this->setFirstResult($offset); } if ($limit > 0) { $this->setMaxResults($limit); } } /** * Limit the request to the Id * * @param int $id */ public function limitToId(int $id): void { $this->limitInt('id', $id); } /** * @param array $ids */ public function limitToIds(array $ids): void { $this->limitArray('id', $ids); } /** * @param string $id */ public function limitToIdString(string $id): void { $this->limit('id', $id); } /** * @param string $userId */ public function limitToUserId(string $userId): void { $this->limit('user_id', $userId); } /** * @param string $uniqueId */ public function limitToUniqueId(string $uniqueId): void { $this->limit('unique_id', $uniqueId); } /** * @param string $memberId */ public function limitToMemberId(string $memberId): void { $this->limit('member_id', $memberId); } /** * @param string $status */ public function limitToStatus(string $status): void { $this->limit('status', $status, '', false); } /** * @param int $type */ public function limitToType(int $type): void { $this->limitInt('type', $type); } /** * @param string $type */ public function limitToTypeString(string $type): void { $this->limit('type', $type, '', false); } /** * @param string $token */ public function limitToToken(string $token): void { $this->limit('token', $token); } /** * Limit the request to the creation * * @param int $delay * * @return self * @throws Exception */ public function limitToCreation(int $delay = 0): self { $date = new DateTime('now'); $date->sub(new DateInterval('PT' . $delay . 'M')); $this->limitToDBFieldDateTime('creation', $date, true); return $this; } /** * @param string $field * @param DateTime $date * @param bool $orNull */ public function limitToDBFieldDateTime(string $field, DateTime $date, bool $orNull = false): void { $expr = $this->expr(); $pf = ($this->getType() === DBALQueryBuilder::SELECT) ? $this->getDefaultSelectAlias() . '.' : ''; $field = $pf . $field; $orX = $expr->orX(); $orX->add( $expr->lte($field, $this->createNamedParameter($date, IQueryBuilder::PARAM_DATE)) ); if ($orNull === true) { $orX->add($expr->isNull($field)); } $this->andWhere($orX); } /** * @param int $timestamp * @param string $field * * @throws DateTimeException */ public function limitToSince(int $timestamp, string $field): void { try { $dTime = new DateTime(); $dTime->setTimestamp($timestamp); } catch (Exception $e) { throw new DateTimeException($e->getMessage()); } $expr = $this->expr(); $pf = ($this->getType() === DBALQueryBuilder::SELECT) ? $this->getDefaultSelectAlias() . '.' : ''; $field = $pf . $field; $orX = $expr->orX(); $orX->add( $expr->gte($field, $this->createNamedParameter($dTime, IQueryBuilder::PARAM_DATE)) ); $this->andWhere($orX); } /** * @param string $field * @param string $value */ public function searchInDBField(string $field, string $value): void { $expr = $this->expr(); $pf = ($this->getType() === DBALQueryBuilder::SELECT) ? $this->getDefaultSelectAlias() . '.' : ''; $field = $pf . $field; $this->andWhere($expr->iLike($field, $this->createNamedParameter($value))); } /** * @param string $field * @param string $value * @param string $alias * @param bool $cs */ public function like(string $field, string $value, string $alias = '', bool $cs = true): void { $this->andWhere($this->exprLike($field, $value, $alias, $cs)); } /** * @param string $field * @param string $value * @param string $alias * @param bool $cs */ public function limit(string $field, string $value, string $alias = '', bool $cs = true): void { $this->andWhere($this->exprLimit($field, $value, $alias, $cs)); } /** * @param string $field * @param int $value * @param string $alias */ public function limitInt(string $field, int $value, string $alias = ''): void { $this->andWhere($this->exprLimitInt($field, $value, $alias)); } /** * @param string $field * @param bool $value * @param string $alias */ public function limitBool(string $field, bool $value, string $alias = ''): void { $this->andWhere($this->exprLimitBool($field, $value, $alias)); } /** * @param string $field * @param bool $orNull * @param string $alias */ public function limitEmpty(string $field, bool $orNull = false, string $alias = ''): void { $this->andWhere($this->exprLimitEmpty($field, $orNull, $alias)); } /** * @param string $field * @param bool $orEmpty * @param string $alias */ public function limitNull(string $field, bool $orEmpty = false, string $alias = ''): void { $this->andWhere($this->exprLimitNull($field, $orEmpty, $alias)); } /** * @param string $field * @param array $value * @param string $alias * @param bool $cs */ public function limitArray(string $field, array $value, string $alias = '', bool $cs = true): void { $this->andWhere($this->exprLimitArray($field, $value, $alias, $cs)); } /** * @param string $field * @param array $value * @param string $alias * @param int $type */ public function limitInArray(string $field, array $value, string $alias = '', int $type = IQueryBuilder::PARAM_STR_ARRAY): void { $this->andWhere($this->exprLimitInArray($field, $value, $alias, $type)); } /** * @param string $field * @param int $flag * @param string $alias */ public function limitBitwise(string $field, int $flag, string $alias = ''): void { $this->andWhere($this->exprLimitBitwise($field, $flag, $alias)); } /** * @param string $field * @param int $value * @param bool $gte * @param string $alias */ public function gt(string $field, int $value, bool $gte = false, string $alias = ''): void { $this->andWhere($this->exprGt($field, $value, $gte, $alias)); } /** * @param string $field * @param int $value * @param bool $lte * @param string $alias */ public function lt(string $field, int $value, bool $lte = false, string $alias = ''): void { $this->andWhere($this->exprLt($field, $value, $lte, $alias)); } /** * @param string $field * @param string $value * @param string $alias * @param bool $cs * * @return string */ public function exprLike(string $field, string $value, string $alias = '', bool $cs = true): string { if ($this->getType() === DBALQueryBuilder::SELECT) { $field = (($alias === '') ? $this->getDefaultSelectAlias() : $alias) . '.' . $field; } $expr = $this->expr(); if ($cs) { return $expr->like($field, $this->createNamedParameter($value)); } else { return $expr->iLike($field, $this->createNamedParameter($value)); } } public function exprLimit(string $field, string $value, string $alias = '', bool $cs = true): string { if ($this->getType() === DBALQueryBuilder::SELECT) { $field = (($alias === '') ? $this->getDefaultSelectAlias() : $alias) . '.' . $field; } $expr = $this->expr(); if ($value === '') { return $expr->emptyString($field); } if ($cs) { return $expr->eq($field, $this->createNamedParameter($value)); } else { $func = $this->func(); return $expr->eq($func->lower($field), $func->lower($this->createNamedParameter($value))); } } public function exprLimitInt(string $field, int $value, string $alias = ''): string { if ($this->getType() === DBALQueryBuilder::SELECT) { $field = (($alias === '') ? $this->getDefaultSelectAlias() : $alias) . '.' . $field; } $expr = $this->expr(); return $expr->eq($field, $this->createNamedParameter($value, IQueryBuilder::PARAM_INT)); } /** * @param string $field * @param bool $value * @param string $alias * * @return string */ public function exprLimitBool(string $field, bool $value, string $alias = ''): string { if ($this->getType() === DBALQueryBuilder::SELECT) { $field = (($alias === '') ? $this->getDefaultSelectAlias() : $alias) . '.' . $field; } $expr = $this->expr(); return $expr->eq($field, $this->createNamedParameter($value, IQueryBuilder::PARAM_BOOL)); } /** * @param string $field * @param bool $orNull * @param string $alias * * @return ICompositeExpression */ public function exprLimitEmpty( string $field, bool $orNull = false, string $alias = '' ): ICompositeExpression { if ($this->getType() === DBALQueryBuilder::SELECT) { $field = (($alias === '') ? $this->getDefaultSelectAlias() : $alias) . '.' . $field; } $expr = $this->expr(); $orX = $expr->orX(); $orX->add($expr->emptyString($field)); if ($orNull) { $orX->add($expr->isNull($field)); } return $orX; } /** * @param string $field * @param bool $orEmpty * @param string $alias * * @return ICompositeExpression */ public function exprLimitNull( string $field, bool $orEmpty = false, string $alias = '' ): ICompositeExpression { if ($this->getType() === DBALQueryBuilder::SELECT) { $field = (($alias === '') ? $this->getDefaultSelectAlias() : $alias) . '.' . $field; } $expr = $this->expr(); $orX = $expr->orX(); $orX->add($expr->isNull($field)); if ($orEmpty) { $orX->add($expr->emptyString($field)); } return $orX; } /** * @param string $field * @param array $values * @param string $alias * @param bool $cs * * @return ICompositeExpression */ public function exprLimitArray( string $field, array $values, string $alias = '', bool $cs = true ): ICompositeExpression { $andX = $this->expr()->andX(); foreach ($values as $value) { if (is_integer($value)) { $andX->add($this->exprLimitInt($field, $value, $alias)); } else { $andX->add($this->exprLimit($field, $value, $alias, $cs)); } } return $andX; } /** * @param string $field * @param array $values * @param string $alias * @param int $type * * @return string */ public function exprLimitInArray( string $field, array $values, string $alias = '', int $type = IQueryBuilder::PARAM_STR_ARRAY ): string { if ($this->getType() === DBALQueryBuilder::SELECT) { $field = (($alias === '') ? $this->getDefaultSelectAlias() : $alias) . '.' . $field; } $expr = $this->expr(); return $expr->in($field, $this->createNamedParameter($values, $type)); } /** * @param string $field * @param int $flag * @param string $alias * * @return string */ public function exprLimitBitwise(string $field, int $flag, string $alias = ''): string { if ($this->getType() === DBALQueryBuilder::SELECT) { $field = (($alias === '') ? $this->getDefaultSelectAlias() : $alias) . '.' . $field; } $expr = $this->expr(); return $expr->gt( $expr->bitwiseAnd($field, $flag), $this->createNamedParameter(0, IQueryBuilder::PARAM_INT) ); } /** * @param string $field * @param int $value * @param bool $lte * @param string $alias * * @return string */ public function exprLt(string $field, int $value, bool $lte = false, string $alias = ''): string { if ($this->getType() === DBALQueryBuilder::SELECT) { $field = (($alias === '') ? $this->getDefaultSelectAlias() : $alias) . '.' . $field; } $expr = $this->expr(); if ($lte) { return $expr->lte($field, $this->createNamedParameter($value, IQueryBuilder::PARAM_INT)); } else { return $expr->lt($field, $this->createNamedParameter($value, IQueryBuilder::PARAM_INT)); } } /** * @param string $field * @param int $value * @param bool $gte * @param string $alias * * @return string */ public function exprGt(string $field, int $value, bool $gte = false, string $alias = ''): string { if ($this->getType() === DBALQueryBuilder::SELECT) { $field = (($alias === '') ? $this->getDefaultSelectAlias() : $alias) . '.' . $field; } $expr = $this->expr(); if ($gte) { return $expr->gte($field, $this->createNamedParameter($value, IQueryBuilder::PARAM_INT)); } else { return $expr->gt($field, $this->createNamedParameter($value, IQueryBuilder::PARAM_INT)); } } /** * @param string $field * @param string $value * @param string $alias * @param bool $cs */ public function unlike(string $field, string $value, string $alias = '', bool $cs = true): void { $this->andWhere($this->exprUnlike($field, $value, $alias, $cs)); } /** * @param string $field * @param string $value * @param string $alias * @param bool $cs */ public function filter(string $field, string $value, string $alias = '', bool $cs = true): void { $this->andWhere($this->exprFilter($field, $value, $alias, $cs)); } /** * @param string $field * @param int $value * @param string $alias */ public function filterInt(string $field, int $value, string $alias = ''): void { $this->andWhere($this->exprFilterInt($field, $value, $alias)); } /** * @param string $field * @param bool $value * @param string $alias */ public function filterBool(string $field, bool $value, string $alias = ''): void { $this->andWhere($this->exprFilterBool($field, $value, $alias)); } /** * @param string $field * @param bool $norNull * @param string $alias */ public function filterEmpty(string $field, bool $norNull = false, string $alias = ''): void { $this->andWhere($this->exprFilterEmpty($field, $norNull, $alias)); } /** * @param string $field * @param bool $norEmpty * @param string $alias */ public function filterNull(string $field, bool $norEmpty = false, string $alias = ''): void { $this->andWhere($this->exprFilterNull($field, $norEmpty, $alias)); } /** * @param string $field * @param array $value * @param string $alias * @param bool $cs */ public function filterArray(string $field, array $value, string $alias = '', bool $cs = true): void { $this->andWhere($this->exprFilterArray($field, $value, $alias, $cs)); } /** * @param string $field * @param array $value * @param string $alias */ public function filterInArray(string $field, array $value, string $alias = ''): void { $this->andWhere($this->exprFilterInArray($field, $value, $alias)); } /** * @param string $field * @param int $flag * @param string $alias */ public function filterBitwise(string $field, int $flag, string $alias = ''): void { $this->andWhere($this->exprFilterBitwise($field, $flag, $alias)); } /** * @param string $field * @param string $value * @param string $alias * @param bool $cs * * @return string */ public function exprUnlike(string $field, string $value, string $alias = '', bool $cs = true): string { if ($this->getType() === DBALQueryBuilder::SELECT) { $field = (($alias === '') ? $this->getDefaultSelectAlias() : $alias) . '.' . $field; } $expr = $this->expr(); if ($cs) { return $expr->notLike($field, $this->createNamedParameter($value)); } else { $func = $this->func(); return $expr->notLike($func->lower($field), $func->lower($this->createNamedParameter($value))); } } /** * @param string $field * @param string $value * @param string $alias * @param bool $cs * * @return string */ public function exprFilter(string $field, string $value, string $alias = '', bool $cs = true): string { if ($this->getType() === DBALQueryBuilder::SELECT) { $field = (($alias === '') ? $this->getDefaultSelectAlias() : $alias) . '.' . $field; } $expr = $this->expr(); if ($value === '') { return $expr->nonEmptyString($field); } if ($cs) { return $expr->neq($field, $this->createNamedParameter($value)); } else { $func = $this->func(); return $expr->neq($func->lower($field), $func->lower($this->createNamedParameter($value))); } } /** * @param string $field * @param int $value * @param string $alias * * @return string */ public function exprFilterInt(string $field, int $value, string $alias = ''): string { if ($this->getType() === DBALQueryBuilder::SELECT) { $field = (($alias === '') ? $this->getDefaultSelectAlias() : $alias) . '.' . $field; } $expr = $this->expr(); return $expr->neq($field, $this->createNamedParameter($value, IQueryBuilder::PARAM_INT)); } /** * @param string $field * @param bool $value * @param string $alias * * @return string */ public function exprFilterBool(string $field, bool $value, string $alias = ''): string { if ($this->getType() === DBALQueryBuilder::SELECT) { $field = (($alias === '') ? $this->getDefaultSelectAlias() : $alias) . '.' . $field; } $expr = $this->expr(); return $expr->neq($field, $this->createNamedParameter($value, IQueryBuilder::PARAM_BOOL)); } /** * @param string $field * @param bool $norNull * @param string $alias * * @return ICompositeExpression */ public function exprFilterEmpty( string $field, bool $norNull = false, string $alias = '' ): ICompositeExpression { if ($this->getType() === DBALQueryBuilder::SELECT) { $field = (($alias === '') ? $this->getDefaultSelectAlias() : $alias) . '.' . $field; } $expr = $this->expr(); $andX = $expr->andX(); $andX->add($expr->nonEmptyString($field)); if ($norNull) { $andX->add($expr->isNotNull($field)); } return $andX; } /** * @param string $field * @param bool $norEmpty * @param string $alias * * @return ICompositeExpression */ public function exprFilterNull( string $field, bool $norEmpty = false, string $alias = '' ): ICompositeExpression { if ($this->getType() === DBALQueryBuilder::SELECT) { $field = (($alias === '') ? $this->getDefaultSelectAlias() : $alias) . '.' . $field; } $expr = $this->expr(); $andX = $expr->andX(); $andX->add($expr->isNotNull($field)); if ($norEmpty) { $andX->add($expr->nonEmptyString($field)); } return $andX; } /** * @param string $field * @param array $values * @param string $alias * @param bool $cs * * @return ICompositeExpression */ public function exprFilterArray( string $field, array $values, string $alias = '', bool $cs = true ): ICompositeExpression { if ($this->getType() === DBALQueryBuilder::SELECT) { $field = (($alias === '') ? $this->getDefaultSelectAlias() : $alias) . '.' . $field; } $orX = $this->expr()->orX(); foreach ($values as $value) { if (is_integer($value)) { $orX->add($this->exprFilterInt($field, $value, $alias)); } else { $orX->add($this->exprFilter($field, $value, $alias, $cs)); } } return $orX; } /** * @param string $field * @param array $values * @param string $alias * * @return string */ public function exprFilterInArray(string $field, array $values, string $alias = ''): string { if ($this->getType() === DBALQueryBuilder::SELECT) { $field = (($alias === '') ? $this->getDefaultSelectAlias() : $alias) . '.' . $field; } $expr = $this->expr(); return $expr->notIn($field, $this->createNamedParameter($values, IQueryBuilder::PARAM_STR_ARRAY)); } /** * @param string $field * @param int $flag * @param string $alias * * @return string */ public function exprFilterBitwise(string $field, int $flag, string $alias = ''): string { if ($this->getType() === DBALQueryBuilder::SELECT) { $field = (($alias === '') ? $this->getDefaultSelectAlias() : $alias) . '.' . $field; } $expr = $this->expr(); return $expr->eq( $expr->bitwiseAnd($field, $flag), $this->createNamedParameter(0, IQueryBuilder::PARAM_INT) ); } /** * @param string $object * @param array $params * * @return IQueryRow * @throws RowNotFoundException * @throws InvalidItemException */ public function asItem(string $object, array $params = []): IQueryRow { return $this->getRow([$this, 'parseSimpleSelectSql'], $object, $params); } /** * @param string $object * @param array $params * * @return IQueryRow[] */ public function asItems(string $object, array $params = []): array { return $this->getRows([$this, 'parseSimpleSelectSql'], $object, $params); } /** * @param string $field * @param array $params * * @return IQueryRow * @throws InvalidItemException * @throws RowNotFoundException */ public function asItemFromField(string $field, array $params = []): IQueryRow { $param['modelFromField'] = $field; return $this->getRow([$this, 'parseSimpleSelectSql'], '', $params); } /** * @param string $field * @param array $params * * @return IQueryRow[] */ public function asItemsFromField(string $field, array $params = []): array { $param['modelFromField'] = $field; return $this->getRows([$this, 'parseSimpleSelectSql'], $field, $params); } /** * @param array $data * @param ExtendedQueryBuilder $qb * @param string $object * @param array $params * * @return IQueryRow * @throws InvalidItemException */ private function parseSimpleSelectSql( array $data, ExtendedQueryBuilder $qb, string $object, array $params ): IQueryRow { $fromField = $this->get('modelFromField', $params); if ($fromField !== '') { $object = $fromField; } $item = new $object(); if (!($item instanceof IQueryRow)) { throw new InvalidItemException(); } if (!empty($params)) { $data['_params'] = $params; } foreach ($qb->getDefaultValues() as $k => $v) { if ($this->get($k, $data) === '') { $data[$k] = $v; } } $data = array_merge($qb->getDefaultValues(), $data); $item->importFromDatabase($data); return $item; } /** * @param callable $method * @param string $object * @param array $params * * @return IQueryRow * @throws RowNotFoundException */ public function getRow(callable $method, string $object = '', array $params = []): IQueryRow { $cursor = $this->execute(); $data = $cursor->fetch(); $cursor->closeCursor(); if ($data === false) { throw new RowNotFoundException(); } return $method($data, $this, $object, $params); } /** * @param callable $method * @param string $object * @param array $params * * @return IQueryRow[] */ public function getRows(callable $method, string $object = '', array $params = []): array { $rows = []; $cursor = $this->execute(); while ($data = $cursor->fetch()) { try { $rows[] = $method($data, $this, $object, $params); } catch (Exception $e) { } } $cursor->closeCursor(); return $rows; } /** * @param string $table * @param array $fields * @param string $alias * * @return $this */ public function generateSelect( string $table, array $fields, string $alias = '' ): self { $selectFields = array_map( function (string $item) use ($alias) { if ($alias === '') { return $item; } return $alias . '.' . $item; }, $fields ); $this->select($selectFields) ->from($table, $alias) ->setDefaultSelectAlias($alias); return $this; } /** * @param array $fields * @param string $alias * @param string $prefix * @param array $default * * @return $this */ public function generateSelectAlias( array $fields, string $alias, string $prefix, array $default = [] ): self { $prefix = trim($prefix) . '_'; foreach ($default as $k => $v) { $this->addDefaultValue($prefix . $k, (string)$v); } foreach ($fields as $field) { $this->selectAlias($alias . '.' . $field, $prefix . $field); } return $this; } }