diff --git a/components/ILIAS/ResourceStorage/classes/CollectionDBRepository.php b/components/ILIAS/ResourceStorage/classes/CollectionDBRepository.php index a75b6ba80833..96e4d38b9442 100755 --- a/components/ILIAS/ResourceStorage/classes/CollectionDBRepository.php +++ b/components/ILIAS/ResourceStorage/classes/CollectionDBRepository.php @@ -38,6 +38,9 @@ class CollectionDBRepository implements CollectionRepository public const R_IDENTIFICATION = 'rid'; public const C_IDENTIFICATION = 'rcid'; + /** @var array */ + private array $resource_ids_cache = []; + public function __construct(protected \ilDBInterface $db) { } @@ -55,11 +58,18 @@ public function blank( ?int $owner_id = null, ?string $title = null ): ResourceCollection { - return new ResourceCollection( + $collection = new ResourceCollection( $identification, $owner_id ?? ResourceCollection::NO_SPECIFIC_OWNER, $title ?? '' ); + + $rcid = $identification->serialize(); + if (!isset($this->resource_ids_cache[$rcid])) { + $this->resource_ids_cache[$rcid] = []; + } + + return $collection; } public function existing(ResourceCollectionIdentification $identification): ResourceCollection @@ -91,17 +101,24 @@ public function has(ResourceCollectionIdentification $identification): bool */ public function getResourceIdStrings(ResourceCollectionIdentification $identification): \Generator { - $q = "SELECT " . self::R_IDENTIFICATION . " FROM " . self::COLLECTION_ASSIGNMENT_TABLE_NAME . " WHERE " . self::C_IDENTIFICATION . " = %s ORDER BY position ASC"; - $r = $this->db->queryF($q, ['text'], [$identification->serialize()]); - while ($d = $this->db->fetchAssoc($r)) { - yield (string) $d[self::R_IDENTIFICATION]; + $rcid = $identification->serialize(); + + if (!isset($this->resource_ids_cache[$rcid])) { + $this->preload([$rcid]); + } + + foreach ($this->resource_ids_cache[$rcid] ?? [] as $rid) { + yield $rid; } } public function clear(ResourceCollectionIdentification $identification): void { + $rcid = $identification->serialize(); $q = "DELETE FROM " . self::COLLECTION_ASSIGNMENT_TABLE_NAME . " WHERE " . self::C_IDENTIFICATION . " = %s"; - $r = $this->db->manipulateF($q, ['text'], [$identification->serialize()]); + $this->db->manipulateF($q, ['text'], [$rcid]); + + $this->resource_ids_cache[$rcid] = []; } public function update(ResourceCollection $collection, DataContainer $event_data_container): void @@ -148,6 +165,8 @@ public function update(ResourceCollection $collection, DataContainer $event_data ] ); } + + $this->resource_ids_cache[$identification->serialize()] = array_values($resource_identification_strings); if ($this->has($identification)) { $this->db->update( self::COLLECTION_TABLE_NAME, @@ -174,34 +193,111 @@ public function update(ResourceCollection $collection, DataContainer $event_data public function removeResourceFromAllCollections(ResourceIdentification $resource_identification): void { + $rid = $resource_identification->serialize(); + $this->db->manipulateF( "DELETE FROM " . self::COLLECTION_ASSIGNMENT_TABLE_NAME . " WHERE " . self::R_IDENTIFICATION . " = %s", ['text'], - [$resource_identification->serialize()] + [$rid] ); + + foreach ($this->resource_ids_cache as $rcid => $rids) { + if (in_array($rid, $rids, true)) { + $this->resource_ids_cache[$rcid] = array_values(array_diff($rids, [$rid])); + } + } } public function delete(ResourceCollectionIdentification $identification): void { + $rcid = $identification->serialize(); + $this->db->manipulateF( "DELETE FROM " . self::COLLECTION_ASSIGNMENT_TABLE_NAME . " WHERE " . self::C_IDENTIFICATION . " = %s", ['text'], - [$identification->serialize()] + [$rcid] ); $this->db->manipulateF( "DELETE FROM " . self::COLLECTION_TABLE_NAME . " WHERE " . self::C_IDENTIFICATION . " = %s", ['text'], - [$identification->serialize()] + [$rcid] ); + + unset($this->resource_ids_cache[$rcid]); } public function preload(array $identification_strings): void { - // TODO: Implement preload() method. + if ($identification_strings === []) { + return; + } + + $identification_strings = array_values(array_unique($identification_strings)); + + $to_load = []; + foreach ($identification_strings as $rcid) { + if (!isset($this->resource_ids_cache[$rcid])) { + $this->resource_ids_cache[$rcid] = []; + $to_load[] = $rcid; + } + } + + if ($to_load === []) { + return; + } + + $q = "SELECT " . self::C_IDENTIFICATION . ", " . self::R_IDENTIFICATION . + " FROM " . self::COLLECTION_ASSIGNMENT_TABLE_NAME . + " WHERE " . $this->db->in(self::C_IDENTIFICATION, $to_load, false, 'text') . + " ORDER BY position ASC"; + + $res = $this->db->query($q); + while ($row = $this->db->fetchAssoc($res)) { + $rcid = (string) $row[self::C_IDENTIFICATION]; + $rid = (string) $row[self::R_IDENTIFICATION]; + $this->resource_ids_cache[$rcid][] = $rid; + } + } + + /** + * @param string[] $collection_identifications + * @return ResourceIdentification[] + */ + public function getResourceIdsForCollections(array $collection_identifications): array + { + if ($collection_identifications === []) { + return []; + } + + $collection_identifications = array_values(array_unique($collection_identifications)); + + $to_preload = []; + foreach ($collection_identifications as $rcid) { + if (!isset($this->resource_ids_cache[$rcid])) { + $to_preload[] = $rcid; + } + } + if ($to_preload !== []) { + $this->preload($to_preload); + } + + $result_rids = []; + foreach ($collection_identifications as $rcid) { + foreach ($this->resource_ids_cache[$rcid] ?? [] as $rid) { + $result_rids[] = $rid; + } + } + + $result_rids = array_values(array_unique($result_rids)); + + return array_map( + static fn(string $rid): ResourceIdentification => new ResourceIdentification($rid), + $result_rids + ); } public function populateFromArray(array $data): void { - // TODO: Implement populateFromArray() method. + // Nothing to do here } } diff --git a/components/ILIAS/ResourceStorage/src/Collection/Repository/CollectionRepository.php b/components/ILIAS/ResourceStorage/src/Collection/Repository/CollectionRepository.php index c3aecf21e5c0..87ead4085a1a 100755 --- a/components/ILIAS/ResourceStorage/src/Collection/Repository/CollectionRepository.php +++ b/components/ILIAS/ResourceStorage/src/Collection/Repository/CollectionRepository.php @@ -25,13 +25,14 @@ use ILIAS\ResourceStorage\Identification\ResourceIdentification; use ILIAS\ResourceStorage\Lock\LockingRepository; use ILIAS\ResourceStorage\Events\DataContainer; +use ILIAS\ResourceStorage\Preloader\PreloadableRepository; /** * Interface CollectionRepository * * @author Fabian Schmid */ -interface CollectionRepository extends LockingRepository +interface CollectionRepository extends LockingRepository, PreloadableRepository { public function has(ResourceCollectionIdentification $identification): bool; @@ -46,6 +47,12 @@ public function clear(ResourceCollectionIdentification $identification): void; */ public function getResourceIdStrings(ResourceCollectionIdentification $identification): \Generator; + /** + * @param string[] $collection_identifications + * @return ResourceIdentification[] + */ + public function getResourceIdsForCollections(array $collection_identifications): array; + public function update(ResourceCollection $collection, DataContainer $event_data_container): void; public function delete(ResourceCollectionIdentification $identification): void; diff --git a/components/ILIAS/ResourceStorage/src/Preloader/RepositoryPreloader.php b/components/ILIAS/ResourceStorage/src/Preloader/RepositoryPreloader.php index 2d0581e2e99f..040b3ef77fa0 100755 --- a/components/ILIAS/ResourceStorage/src/Preloader/RepositoryPreloader.php +++ b/components/ILIAS/ResourceStorage/src/Preloader/RepositoryPreloader.php @@ -27,4 +27,12 @@ interface RepositoryPreloader { public function preload(array $identification_strings): void; + + /** + * Preload collections (by their collection identifications) and all + * resources contained in those collections. + * + * @param string[] $collection_identification_strings + */ + public function preloadCollections(array $collection_identification_strings): void; } diff --git a/components/ILIAS/ResourceStorage/src/Preloader/StandardRepositoryPreloader.php b/components/ILIAS/ResourceStorage/src/Preloader/StandardRepositoryPreloader.php index c57f1925eb6f..4e4cd692eeb9 100755 --- a/components/ILIAS/ResourceStorage/src/Preloader/StandardRepositoryPreloader.php +++ b/components/ILIAS/ResourceStorage/src/Preloader/StandardRepositoryPreloader.php @@ -26,6 +26,8 @@ use ILIAS\ResourceStorage\Stakeholder\Repository\StakeholderRepository; use ILIAS\ResourceStorage\Repositories; use ILIAS\ResourceStorage\Resource\Repository\FlavourRepository; +use ILIAS\ResourceStorage\Collection\Repository\CollectionRepository; +use ILIAS\ResourceStorage\Identification\ResourceIdentification; /** * Class StandardRepositoryPreloader @@ -38,6 +40,7 @@ class StandardRepositoryPreloader implements RepositoryPreloader protected InformationRepository $information_repository; protected StakeholderRepository $stakeholder_repository; protected FlavourRepository $flavour_repository; + protected CollectionRepository $collection_repository; public function __construct(Repositories $repositories) { @@ -46,6 +49,7 @@ public function __construct(Repositories $repositories) $this->information_repository = $repositories->getInformationRepository(); $this->stakeholder_repository = $repositories->getStakeholderRepository(); $this->flavour_repository = $repositories->getFlavourRepository(); + $this->collection_repository = $repositories->getCollectionRepository(); } public function preload(array $identification_strings): void @@ -56,4 +60,24 @@ public function preload(array $identification_strings): void $this->stakeholder_repository->preload($identification_strings); $this->flavour_repository->preload($identification_strings); } + + /** + * @param string[] $collection_identification_strings + */ + public function preloadCollections(array $collection_identification_strings): void + { + if ($collection_identification_strings === []) { + return; + } + $resource_ids = $this->collection_repository->getResourceIdsForCollections($collection_identification_strings); + $resource_ids = array_values(array_unique( + array_map(static fn(ResourceIdentification $id) => $id->serialize(), $resource_ids) + )); + + if ($resource_ids === []) { + return; + } + + $this->preload($resource_ids); + } } diff --git a/components/ILIAS/ResourceStorage/src/Services.php b/components/ILIAS/ResourceStorage/src/Services.php index 811632eb5446..e9f30cf27364 100755 --- a/components/ILIAS/ResourceStorage/src/Services.php +++ b/components/ILIAS/ResourceStorage/src/Services.php @@ -161,6 +161,14 @@ public function preload(array $identification_strings): void $this->preloader->preload($identification_strings); } + /** + * @param string[] $collection_identification_strings + */ + public function preloadCollections(array $collection_identification_strings): void + { + $this->preloader->preloadCollections($collection_identification_strings); + } + public function events(): Subject { return $this->events;