Skip to content

Commit

Permalink
IBX-843: Introduced ContentLocationMapper
Browse files Browse the repository at this point in the history
For more details see https://issues.ibexa.co/browse/IBX-843 and ezsystems/ezplatform-kernel#249

* Created InMemoryContentLocationMapper

* Implemented LocationService hooks for ContentLocationMapper

* Registered DI services

* Created unit tests
  • Loading branch information
webhdx authored Nov 5, 2021
1 parent 82ad5d3 commit 83d01ad
Show file tree
Hide file tree
Showing 9 changed files with 520 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,7 @@ private function handleApiLoading(ContainerBuilder $container, FileLoader $loade
$coreLoader->load('user_preference.yml');
$coreLoader->load('events.yml');
$coreLoader->load('thumbnails.yml');
$coreLoader->load('content_location_mapper.yml');

// Public API services
$loader->load('papi.yml');
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

/**
* @copyright Copyright (C) Ibexa AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
declare(strict_types=1);

namespace eZ\Publish\Core\Repository\Mapper\ContentLocationMapper;

/**
* @internal For internal use by Ibexa packages only
*/
interface ContentLocationMapper
{
public function hasMapping(int $locationId): bool;

public function getMapping(int $locationId): int;

public function setMapping(int $locationId, int $contentId): void;

public function removeMapping(int $locationId): void;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
<?php

/**
* @copyright Copyright (C) Ibexa AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
declare(strict_types=1);

namespace eZ\Publish\Core\Repository\Mapper\ContentLocationMapper;

use eZ\Publish\API\Repository\LocationService as RepositoryLocationService;
use eZ\Publish\API\Repository\Values\Content\ContentInfo;
use eZ\Publish\API\Repository\Values\Content\Location;
use eZ\Publish\API\Repository\Values\Content\LocationList;
use eZ\Publish\SPI\Repository\Decorator\LocationServiceDecorator;

/**
* Service decorator hooking ContentLocationMapper to load* calls.
*
* @internal
*/
final class DecoratedLocationService extends LocationServiceDecorator
{
/** @var \eZ\Publish\Core\Repository\Mapper\ContentLocationMapper\ContentLocationMapper */
private $contentLocationMapper;

public function __construct(
RepositoryLocationService $innerService,
ContentLocationMapper $contentLocationMapper
) {
parent::__construct($innerService);

$this->contentLocationMapper = $contentLocationMapper;
}

public function loadLocation(
int $locationId,
?array $prioritizedLanguages = null,
?bool $useAlwaysAvailable = null
): Location {
$location = $this->innerService->loadLocation(
$locationId,
$prioritizedLanguages,
$useAlwaysAvailable
);

$this->contentLocationMapper->setMapping(
$locationId,
$location->contentId
);

return $location;
}

public function loadLocationList(
array $locationIds,
?array $prioritizedLanguages = null,
?bool $useAlwaysAvailable = null
): iterable {
$locationList = $this->innerService->loadLocationList(
$locationIds,
$prioritizedLanguages,
$useAlwaysAvailable
);

$this->setLocationMappings($locationList);

return $locationList;
}

public function loadLocations(
ContentInfo $contentInfo,
?Location $rootLocation = null,
?array $prioritizedLanguages = null
): iterable {
$locations = $this->innerService->loadLocations(
$contentInfo,
$rootLocation,
$prioritizedLanguages
);

$this->setLocationMappings($locations);

return $locations;
}

public function loadLocationChildren(
Location $location,
int $offset = 0,
int $limit = 25,
?array $prioritizedLanguages = null
): LocationList {
$locationChildren = $this->innerService->loadLocationChildren(
$location,
$offset,
$limit,
$prioritizedLanguages
);

$this->setLocationMappings($locationChildren->locations);

return $locationChildren;
}

public function loadAllLocations(
int $offset = 0,
int $limit = 25
): array {
$locations = $this->innerService->loadAllLocations(
$offset,
$limit
);

$this->setLocationMappings($locations);

return $locations;
}

/**
* @param iterable<\eZ\Publish\API\Repository\Values\Content\Location>
*/
private function setLocationMappings(iterable $locationList): void
{
foreach ($locationList as $location) {
$this->contentLocationMapper->setMapping(
$location->id,
$location->contentId
);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

/**
* @copyright Copyright (C) Ibexa AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
declare(strict_types=1);

namespace eZ\Publish\Core\Repository\Mapper\ContentLocationMapper;

/**
* Retrieves Content ID from Location ID.
*
* Helps in scenarios where you need to retrieve Content IDs from
* a large location list. You'd normally do LocationService::loadLocation call
* for every Location ID which requires a lot of memory.
*
* It works by tracing all loadLocation calls via Service\LocationService decorator
* and updating the map accordingly. Currently, in memory cache mechanism is used but
* can be further optimized by implementing persistence cache.
*
* @internal For internal use by Ibexa packages only
*/
final class InMemoryContentLocationMapper implements ContentLocationMapper
{
/** @var Array<int, int> */
private $map;

/**
* @param int[] $map
*/
public function __construct(array $map = [])
{
$this->map = $map;
}

public function hasMapping(int $locationId): bool
{
return isset($this->map[$locationId]);
}

public function getMapping(int $locationId): int
{
return $this->map[$locationId];
}

public function setMapping(int $locationId, int $contentId): void
{
$this->map[$locationId] = $contentId;
}

public function removeMapping(int $locationId): void
{
unset($this->map[$locationId]);
}
}
7 changes: 3 additions & 4 deletions eZ/Publish/Core/Repository/Mapper/Readme.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# Mappers

Collection of light mappers meant for internal use in Repository
and/or RepositoryServices.
Collection of light mappers meant for internal use by Ibexa packages only.

Given their use they can not rely on Repository or RepositoryServices as
that will lead to cyclic dependencies, they can only rely on SPI and other helpers.
Given their use they should not rely on Repository or RepositoryServices as
that will lead to cyclic dependencies, they should only rely on SPI and other helpers.
Loading

0 comments on commit 83d01ad

Please sign in to comment.