diff options
author | Maxence Lange <maxence@artificial-owl.com> | 2022-08-30 19:28:06 +0300 |
---|---|---|
committer | Maxence Lange <maxence@artificial-owl.com> | 2022-10-22 15:32:12 +0300 |
commit | 6be7c4df14c781fb3eb81d7e7ea9a9f9b799a609 (patch) | |
tree | b3aea9e0ea2381b51106f49f38fd05788da87eb4 | |
parent | 886dfd88e167e9581954243332b99528264c767c (diff) |
+DataProbe
Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
-rw-r--r-- | lib/CirclesManager.php | 35 | ||||
-rw-r--r-- | lib/Db/CircleRequest.php | 43 | ||||
-rw-r--r-- | lib/Db/CoreQueryBuilder.php | 81 | ||||
-rw-r--r-- | lib/Model/Probes/DataProbe.php | 111 | ||||
-rw-r--r-- | lib/Service/CircleService.php | 24 |
5 files changed, 287 insertions, 7 deletions
diff --git a/lib/CirclesManager.php b/lib/CirclesManager.php index 6acbd69d..3959d843 100644 --- a/lib/CirclesManager.php +++ b/lib/CirclesManager.php @@ -57,6 +57,7 @@ use OCA\Circles\Model\FederatedUser; use OCA\Circles\Model\Member; use OCA\Circles\Model\Membership; use OCA\Circles\Model\Probes\CircleProbe; +use OCA\Circles\Model\Probes\DataProbe; use OCA\Circles\Service\CircleService; use OCA\Circles\Service\ConfigService; use OCA\Circles\Service\FederatedUserService; @@ -316,7 +317,14 @@ class CirclesManager { /** - * returns Circles available, based on current session + * WARNING: This method is not using Cached Memberships meaning that the request can be heavy and should + * only be used if probeCircles() does not fit your need. + * + * Always prefer probeCircles(); + * + * returns available Circles to the current session. + * + * @see probeCircles() * * @return Circle[] * @throws InitiatorNotFoundException @@ -510,6 +518,31 @@ class CirclesManager { /** + * Returns data about Circles based on cached Memberships. + * Meaning that only Circles the current user is a member will be returned. + * + * CircleProbe is used to filter Circles to be returned by the method. + * DataProbe is used to add details to returned Circles. + * + * @param CircleProbe|null $circleProbe + * @param DataProbe|null $dataProbe + * + * @return array + * @throws InitiatorNotFoundException + * @throws RequestBuilderException + */ + public function probeCircles(?CircleProbe $circleProbe = null, ?DataProbe $dataProbe = null): array { + if (is_null($circleProbe)) { + $circleProbe = new CircleProbe(); + $circleProbe->filterHiddenCircles() + ->filterBackendCircles(); + } + + return $this->circleService->probeCircles($circleProbe, $dataProbe); + } + + + /** * WIP * * @param string $circleId diff --git a/lib/Db/CircleRequest.php b/lib/Db/CircleRequest.php index 1303f480..afb9f160 100644 --- a/lib/Db/CircleRequest.php +++ b/lib/Db/CircleRequest.php @@ -42,6 +42,7 @@ use OCA\Circles\Model\Circle; use OCA\Circles\Model\FederatedUser; use OCA\Circles\Model\Member; use OCA\Circles\Model\Probes\CircleProbe; +use OCA\Circles\Model\Probes\DataProbe; /** * Class CircleRequest @@ -203,6 +204,48 @@ class CircleRequest extends CircleRequestBuilder { /** + * get data about multiple Circles. + * + * - CircleProbe is used to define the list of circles to be returned by the method, + * - DataProbe is used to define the complexity of the data to be returned for each entry of the list + * + * @param IFederatedUser|null $initiator + * @param CircleProbe $circleProbe + * @param DataProbe $dataProbe + * + * @return array + * @throws RequestBuilderException + */ + public function probeCircles( + ?IFederatedUser $initiator, + CircleProbe $circleProbe, + DataProbe $dataProbe + ): array { + $qb = $this->getCircleSelectSql(); + if (!$dataProbe->has(CoreQueryBuilder::MEMBERSHIPS)) { + $dataProbe->add(CoreQueryBuilder::MEMBERSHIPS); + } + + $qb->setAlternateSqlPath(CoreQueryBuilder::CIRCLE, $dataProbe->getPath()) + ->setOptions([CoreQueryBuilder::CIRCLE], $circleProbe->getAsOptions()); + + $qb->leftJoinOwner(CoreQueryBuilder::CIRCLE); + + $qb->innerJoinMembership(CoreQueryBuilder::CIRCLE); + + if (!is_null($initiator)) { + $qb->limitToSingleId( + $initiator->getSingleId(), $qb->generateAlias( + CoreQueryBuilder::CIRCLE, + CoreQueryBuilder::MEMBERSHIPS + ) + ); + } + + return $this->getItemsFromRequest($qb); + } + + /** * @param array $circleIds * * @return array diff --git a/lib/Db/CoreQueryBuilder.php b/lib/Db/CoreQueryBuilder.php index 01268ea0..fffad9d3 100644 --- a/lib/Db/CoreQueryBuilder.php +++ b/lib/Db/CoreQueryBuilder.php @@ -238,6 +238,7 @@ class CoreQueryBuilder extends ExtendedQueryBuilder { /** @var array */ private $options = []; + private array $alternateSqlPath = []; /** * CoreQueryBuilder constructor. @@ -315,8 +316,8 @@ class CoreQueryBuilder extends ExtendedQueryBuilder { /** * @param string $singleId */ - public function limitToSingleId(string $singleId): void { - $this->limit('single_id', $singleId, '', true); + public function limitToSingleId(string $singleId, string $alias = ''): void { + $this->limit('single_id', $singleId, $alias, true); } @@ -888,6 +889,43 @@ class CoreQueryBuilder extends ExtendedQueryBuilder { /** * @param string $alias + * @param string $field + * + * @throws RequestBuilderException + */ + public function innerJoinMembership(string $alias, string $field = 'unique_id'): void { + if ($this->getType() !== QueryBuilder::SELECT) { + return; + } + + try { + $aliasMembership = $this->generateAlias($alias, self::MEMBERSHIPS); + } catch (RequestBuilderException $e) { + return; + } + + $expr = $this->expr(); + $this->generateMembershipSelectAlias($aliasMembership) + ->innerJoin( + $alias, CoreRequestBuilder::TABLE_MEMBERSHIP, $aliasMembership, + $expr->andX( + $expr->eq($aliasMembership . '.circle_id', $alias . '.' . $field), + $expr->eq( + $aliasMembership . '.level', + $this->createNamedParameter( + Member::LEVEL_MEMBER, + self::PARAM_INT + ) + ) + ) + ); + +// $this->leftJoinBasedOn($aliasMember); + } + + + /** + * @param string $alias * @param string $fieldCircleId * @param string $fieldSingleId * @@ -1658,8 +1696,8 @@ class CoreQueryBuilder extends ExtendedQueryBuilder { public function generateAlias(string $base, string $extension, ?array &$options = []): string { $search = str_replace('_', '.', $base); $path = $search . '.' . $extension; - if (!$this->validKey($path, self::$SQL_PATH) - && !in_array($extension, $this->getArray($search, self::$SQL_PATH))) { + if (!$this->validKey($path, $this->getSqlPath()) + && !in_array($extension, $this->getArray($search, $this->getSqlPath()))) { throw new RequestBuilderException($extension . ' not found in ' . $search); } @@ -1672,7 +1710,7 @@ class CoreQueryBuilder extends ExtendedQueryBuilder { $optionPath = trim($optionPath . '.' . $p, '.'); $options = array_merge( $options, - $this->getArray($optionPath . '.' . self::OPTIONS, self::$SQL_PATH), + $this->getArray($optionPath . '.' . self::OPTIONS, $this->getSqlPath()), $this->getArray($optionPath . '.' . self::OPTIONS, $this->options) ); } @@ -1691,7 +1729,7 @@ class CoreQueryBuilder extends ExtendedQueryBuilder { $search = str_replace('_', '.', $prefix); $path = []; - foreach ($this->getArray($search, self::$SQL_PATH) as $arr => $item) { + foreach ($this->getArray($search, $this->getSqlPath()) as $arr => $item) { if (is_numeric($arr)) { $k = $item; } else { @@ -1702,4 +1740,35 @@ class CoreQueryBuilder extends ExtendedQueryBuilder { return $path; } + + + /** + * @return array + */ + public function getSqlPath(): array { + if (empty($this->alternateSqlPath)) { + return self::$SQL_PATH; + } + + return $this->alternateSqlPath; + } + + + /** + * DataProbe uses this to set which data need to be extracted, based on self::$SQL_PATH. + * + * @param string $key + * @param array $path + * + * @return $this + */ + public function setAlternateSqlPath(string $key, array $path = []): self { + if (empty($this->alternateSqlPath)) { + $this->alternateSqlPath = self::$SQL_PATH; + } + + $this->alternateSqlPath[$key] = $path; + + return $this; + } } diff --git a/lib/Model/Probes/DataProbe.php b/lib/Model/Probes/DataProbe.php new file mode 100644 index 00000000..cb6b6461 --- /dev/null +++ b/lib/Model/Probes/DataProbe.php @@ -0,0 +1,111 @@ +<?php + +declare(strict_types=1); + + +/** + * Circles - Bring cloud-users closer together. + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Maxence Lange <maxence@artificial-owl.com> + * @copyright 2022 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + + +namespace OCA\Circles\Model\Probes; + +use OCA\Circles\Db\CoreQueryBuilder; + +/** + * Class CircleProbe + * + * @package OCA\Circles\Model\Probes + */ +class DataProbe extends BasicProbe { + public const OWNER = CoreQueryBuilder::OWNER; + public const MEMBER = CoreQueryBuilder::MEMBER; + public const BASED_ON = CoreQueryBuilder::BASED_ON; + public const MEMBERSHIPS = CoreQueryBuilder::MEMBERSHIPS; + public const CONFIG = CoreQueryBuilder::CONFIG; + public const INITIATOR = CoreQueryBuilder::INITIATOR; + public const INHERITED_BY = CoreQueryBuilder::INHERITED_BY; + + + private array $path = []; + + + public function __construct() { + } + + + /** + * @param string $key + * @param array $path + * + * @return $this + */ + public function add(string $key, array $path = []): self { + $this->path[$key] = $path; + + return $this; + } + + + /** + * @param string $key + * + * @return bool + */ + public function has(string $key): bool { + return (array_key_exists($key, $this->path)); + } + + + /** + * @return array + */ + public function getPath(): array { + return $this->path; + } + + + /** + * Return an array with includes as options + * + * @return array + */ + public function getAsOptions(): array { + return array_merge( + [ + 'path' => $this->getPath() + ], + parent::getAsOptions() + ); + } + + /** + * Return a JSON object with includes as options + * + * @return array + */ + public function JsonSerialize(): array { + return $this->getAsOptions(); + } +} diff --git a/lib/Service/CircleService.php b/lib/Service/CircleService.php index 8b865ae2..7d0a241b 100644 --- a/lib/Service/CircleService.php +++ b/lib/Service/CircleService.php @@ -62,6 +62,7 @@ use OCA\Circles\Model\FederatedUser; use OCA\Circles\Model\ManagedModel; use OCA\Circles\Model\Member; use OCA\Circles\Model\Probes\CircleProbe; +use OCA\Circles\Model\Probes\DataProbe; use OCA\Circles\Model\Probes\MemberProbe; use OCA\Circles\StatusCode; use OCA\Circles\Tools\Exceptions\InvalidItemException; @@ -756,4 +757,27 @@ class CircleService { private function generateGetCirclesCacheKey(FederatedUser $federatedUser, string $probeSum): string { return $federatedUser->getSingleId() . '#' . $probeSum; } + + + /** + * @param CircleProbe $circleProbe + * @param DataProbe|null $dataProbe + * + * @return array + * @throws InitiatorNotFoundException + * @throws RequestBuilderException + */ + public function probeCircles(CircleProbe $circleProbe, ?DataProbe $dataProbe = null): array { + $this->federatedUserService->mustHaveCurrentUser(); + + if (is_null($dataProbe)) { + $dataProbe = new DataProbe(); + } + + return $this->circleRequest->probeCircles( + $this->federatedUserService->getCurrentUser(), + $circleProbe, + $dataProbe + ); + } } |