Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
97.50% covered (success)
97.50%
39 / 40
83.33% covered (warning)
83.33%
5 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
ParentPropertyListCachedRepository
97.50% covered (success)
97.50%
39 / 40
83.33% covered (warning)
83.33%
5 / 6
14
0.00% covered (danger)
0.00%
0 / 1
 deleteCache
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
3
 findAllUris
94.74% covered (success)
94.74%
18 / 19
0.00% covered (danger)
0.00%
0 / 1
5.00
 removeUsingListUri
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
3
 getCache
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getParentPropertyListRepository
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getDependencyRepository
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3/**
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; under version 2
7 * of the License (non-upgradable).
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17 *
18 * Copyright (c) 2021 (original work) Open Assessment Technologies SA;
19 */
20
21declare(strict_types=1);
22
23namespace oat\tao\model\Lists\DataAccess\Repository;
24
25use InvalidArgumentException;
26use core_kernel_classes_Property;
27use oat\oatbox\cache\SimpleCache;
28use Psr\SimpleCache\CacheInterface;
29use oat\oatbox\service\ConfigurableService;
30use oat\tao\model\Lists\Business\Contract\DependencyRepositoryInterface;
31use oat\tao\model\Lists\Business\Contract\ParentPropertyListRepositoryInterface;
32
33class ParentPropertyListCachedRepository extends ConfigurableService implements ParentPropertyListRepositoryInterface
34{
35    public const OPTION_LIST_URI = 'listUri';
36    public const OPTION_PROPERTY = 'property';
37
38    private const CACHE_MASK = 'depends_on_property-%s-%s';
39    private const LIST_CACHE_MASK = 'depends_on_property-%s';
40
41    public function deleteCache(array $options): void
42    {
43        if (empty($options[self::OPTION_LIST_URI])) {
44            throw new InvalidArgumentException('listUri is required to clear the cache');
45        }
46
47        $this->removeUsingListUri($options[self::OPTION_LIST_URI]);
48
49        $childListUris = $this->getDependencyRepository()->findChildListUris(
50            [
51                'parentListUri' => $options[self::OPTION_LIST_URI]
52            ]
53        );
54
55        foreach ($childListUris as $uri) {
56            $this->removeUsingListUri($uri);
57        }
58    }
59
60    public function findAllUris(array $options): array
61    {
62        /** @var core_kernel_classes_Property $property */
63        $property = $options[self::OPTION_PROPERTY] ?? null;
64
65        $cache = $this->getCache();
66
67        # @TODO Remove requirement from property parameter
68        if (!$property) {
69            return $this->getParentPropertyListRepository()->findAllUris($options);
70        }
71
72        $listUri = $options[self::OPTION_LIST_URI] ?? $property->getRange()->getUri();
73        $cacheKey = sprintf(self::CACHE_MASK, $property->getUri(), $listUri);
74        $listCacheKey = sprintf(self::LIST_CACHE_MASK, $listUri);
75
76        $currentValues = [];
77        $listCacheValues = [$cacheKey];
78
79        if ($cache->has($listCacheKey)) {
80            $currentValues = $cache->get($listCacheKey);
81            $listCacheValues = array_unique(array_merge($currentValues, $listCacheValues));
82        }
83
84        if ($currentValues !== $listCacheValues) {
85            $cache->set($listCacheKey, $listCacheValues);
86        }
87
88        if ($cache->has($cacheKey)) {
89            return $cache->get($cacheKey);
90        }
91
92        $uris = $this->getParentPropertyListRepository()->findAllUris($options);
93
94        $cache->set($cacheKey, $uris);
95
96        return $uris;
97    }
98
99    private function removeUsingListUri(string $uri): void
100    {
101        $listCacheKey = sprintf(self::LIST_CACHE_MASK, $uri);
102        $cache = $this->getCache();
103
104        if ($cache->has($listCacheKey)) {
105            $listCacheValues = $cache->get($listCacheKey);
106
107            foreach ($listCacheValues as $value) {
108                [$key, $propertyUri, $listUri]  = explode('-', $value);
109                $cache->delete(sprintf(self::CACHE_MASK, $propertyUri, $listUri));
110            }
111
112            $cache->delete($listCacheKey);
113        }
114    }
115
116    private function getCache(): CacheInterface
117    {
118        return $this->getServiceLocator()->get(SimpleCache::SERVICE_ID);
119    }
120
121    private function getParentPropertyListRepository(): ParentPropertyListRepositoryInterface
122    {
123        return $this->getServiceLocator()->get(ParentPropertyListRepository::class);
124    }
125
126    private function getDependencyRepository(): DependencyRepositoryInterface
127    {
128        return $this->getServiceLocator()->getContainer()->get(DependencyRepository::class);
129    }
130}