Completed
Push — sf_cache ( 93bbec...94d0e5 )
by André
13:04
created

loadParentLocationsForDraftContent()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 20
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 13
nc 3
nop 1
dl 0
loc 20
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * File containing the LocationHandler implementation.
5
 *
6
 * @copyright Copyright (C) eZ Systems AS. All rights reserved.
7
 * @license For full copyright and license information view LICENSE file distributed with this source code.
8
 */
9
namespace eZ\Publish\Core\Persistence\Cache;
10
11
use eZ\Publish\SPI\Persistence\Content\Location\Handler as LocationHandlerInterface;
12
use eZ\Publish\SPI\Persistence\Content\Location\CreateStruct;
13
use eZ\Publish\SPI\Persistence\Content\Location\UpdateStruct;
14
use eZ\Publish\SPI\Persistence\Content\Location;
15
16
/**
17
 * @inheritdoc
18
 */
19
class LocationHandler extends AbstractHandler implements LocationHandlerInterface
20
{
21
    /**
22
     * @inheritdoc
23
     */
24
    public function load($locationId)
25
    {
26
        $cacheItem = $this->cache->getItem("ez-location-${locationId}");
27
        if ($cacheItem->isHit()) {
28
            return $cacheItem->get();
29
        }
30
31
        $this->logger->logCall(__METHOD__, array('location' => $locationId));
32
        $location = $this->persistenceHandler->locationHandler()->load($locationId);
33
        $cacheItem->set($location);
34
        $cacheItem->tag($this->getCacheTags($location));
35
        $this->cache->save($cacheItem);
36
37
        return $location;
38
    }
39
40
    /**
41
     * @inheritdoc
42
     */
43
    public function loadSubtreeIds($locationId)
44
    {
45
        $cacheItem = $this->cache->getItem("ez-location-subtree-${locationId}");
46
        if ($cacheItem->isHit()) {
47
            return $cacheItem->get();
48
        }
49
50
        $this->logger->logCall(__METHOD__, array('location' => $locationId));
51
        $locationIds = $this->persistenceHandler->locationHandler()->loadSubtreeIds($locationId);
52
53
        $cacheItem->set($locationIds);
54
        $cacheTags = ['location-'.$locationId, 'location-path-'.$locationId];
55
        foreach ($locationIds as $locationId) {
56
            $cacheTags[] = 'location-'.$locationId;
57
            $cacheTags[] = 'location-path-'.$locationId;
58
        }
59
        $cacheItem->tag($cacheTags);
60
        $this->cache->save($cacheItem);
61
62
        return $locationIds;
63
    }
64
65
    /**
66
     * @inheritdoc
67
     */
68
    public function loadLocationsByContent($contentId, $rootLocationId = null)
69
    {
70
        if ($rootLocationId) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $rootLocationId of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
71
            $cacheItem = $this->cache->getItem("ez-content-locations-${contentId}-root-${rootLocationId}");
72
            $cacheTags = ['content-'.$contentId, 'location-'.$rootLocationId, 'location-path-'.$rootLocationId];
73
        } else {
74
            $cacheItem = $this->cache->getItem("ez-content-locations-${contentId}");
75
            $cacheTags = ['content-'.$contentId];
76
        }
77
78
        if ($cacheItem->isHit()) {
79
            return $cacheItem->get();
80
        }
81
82
        $this->logger->logCall(__METHOD__, array('content' => $contentId, 'root' => $rootLocationId));
83
        $locations = $this->persistenceHandler->locationHandler()->loadLocationsByContent($contentId, $rootLocationId);
84
85
        $cacheItem->set($locations);
86
        foreach ($locations as $location) {
87
            $cacheTags = $this->getCacheTags($location, $cacheTags);
88
        }
89
        $cacheItem->tag($cacheTags);
90
        $this->cache->save($cacheItem);
91
92
        return $locations;
93
    }
94
95
    /**
96
     * @inheritdoc
97
     */
98
    public function loadParentLocationsForDraftContent($contentId)
99
    {
100
        $cacheItem = $this->cache->getItem("ez-content-locations-${contentId}-parentForDraft");
101
        if ($cacheItem->isHit()) {
102
            return $cacheItem->get();
103
        }
104
105
        $this->logger->logCall(__METHOD__, array('content' => $contentId));
106
        $locations = $this->persistenceHandler->locationHandler()->loadParentLocationsForDraftContent($contentId);
107
108
        $cacheItem->set($locations);
109
        $cacheTags = ['content-'.$contentId];
110
        foreach ($locations as $location) {
111
            $cacheTags = $this->getCacheTags($location, $cacheTags);
112
        }
113
        $cacheItem->tag($cacheTags);
114
        $this->cache->save($cacheItem);
115
116
        return $locations;
117
    }
118
119
    /**
120
     * @inheritdoc
121
     */
122
    public function loadByRemoteId($remoteId)
123
    {
124
        $this->logger->logCall(__METHOD__, array('location' => $remoteId));
125
126
        return $this->persistenceHandler->locationHandler()->loadByRemoteId($remoteId);
127
    }
128
129
    /**
130
     * @inheritdoc
131
     */
132
    public function copySubtree($sourceId, $destinationParentId)
133
    {
134
        $this->logger->logCall(__METHOD__, array('source' => $sourceId, 'destination' => $destinationParentId));
135
136
        return $this->persistenceHandler->locationHandler()->copySubtree($sourceId, $destinationParentId);
137
    }
138
139
    /**
140
     * @inheritdoc
141
     */
142
    public function move($sourceId, $destinationParentId)
143
    {
144
        $this->logger->logCall(__METHOD__, array('source' => $sourceId, 'destination' => $destinationParentId));
145
        $return = $this->persistenceHandler->locationHandler()->move($sourceId, $destinationParentId);
146
147
        $this->cache->invalidateTags(['location-path-'.$sourceId]);
148
149
        return $return;
150
    }
151
152
    /**
153
     * @inheritdoc
154
     */
155
    public function markSubtreeModified($locationId, $timestamp = null)
156
    {
157
        $this->logger->logCall(__METHOD__, array('location' => $locationId, 'time' => $timestamp));
158
        $this->persistenceHandler->locationHandler()->markSubtreeModified($locationId, $timestamp);
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\SPI\Persisten...::markSubtreeModified() has been deprecated with message: As of 6.8, not been used by repository since 5.x.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
159
    }
160
161
    /**
162
     * @inheritdoc
163
     */
164
    public function hide($locationId)
165
    {
166
        $this->logger->logCall(__METHOD__, array('location' => $locationId));
167
        $return = $this->persistenceHandler->locationHandler()->hide($locationId);
168
169
        $this->cache->invalidateTags(['location-path-'.$locationId]);
170
171
        return $return;
172
    }
173
174
    /**
175
     * @inheritdoc
176
     */
177
    public function unHide($locationId)
178
    {
179
        $this->logger->logCall(__METHOD__, array('location' => $locationId));
180
        $return = $this->persistenceHandler->locationHandler()->unHide($locationId);
181
182
        $this->cache->invalidateTags(['location-path-'.$locationId]);
183
184
        return $return;
185
    }
186
187
    /**
188
     * @inheritdoc
189
     */
190 View Code Duplication
    public function swap($locationId1, $locationId2)
191
    {
192
        $this->logger->logCall(__METHOD__, array('location1' => $locationId1, 'location2' => $locationId2));
193
        $locationHandler = $this->persistenceHandler->locationHandler();
194
195
        $return = $locationHandler->swap($locationId1, $locationId2);
196
197
        $this->cache->invalidateTags(['location-'.$locationId1, 'location-'.$locationId2]);
198
199
        return $return;
200
    }
201
202
    /**
203
     * @inheritdoc
204
     */
205 View Code Duplication
    public function update(UpdateStruct $struct, $locationId)
206
    {
207
        $this->logger->logCall(__METHOD__, array('location' => $locationId, 'struct' => $struct));
208
        $this->persistenceHandler->locationHandler()->update($struct, $locationId);
209
210
        $this->cache->invalidateTags(['location-'.$locationId]);
211
    }
212
213
    /**
214
     * @inheritdoc
215
     */
216 View Code Duplication
    public function create(CreateStruct $locationStruct)
217
    {
218
        $this->logger->logCall(__METHOD__, array('struct' => $locationStruct));
219
        $location = $this->persistenceHandler->locationHandler()->create($locationStruct);
220
221
        // invalidate cache connected to the content
222
        $this->cache->invalidateTags(['content-'.$locationStruct->contentId]);
223
224
        // warm-up cache
225
        $this->cache->save(
226
            $this->cache->getItem('location-'.$location->id)
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Psr\Cache\CacheItemInterface as the method tag() does only exist in the following implementations of said interface: Symfony\Component\Cache\CacheItem.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
227
                ->set($location)
228
                ->tag($this->getCacheTags($location))
229
        );
230
231
        return $location;
232
    }
233
234
    /**
235
     * @inheritdoc
236
     */
237
    public function removeSubtree($locationId)
238
    {
239
        $this->logger->logCall(__METHOD__, array('location' => $locationId));
240
        $return = $this->persistenceHandler->locationHandler()->removeSubtree($locationId);
241
242
        $this->cache->invalidateTags(['location-path-'.$locationId]);
243
244
        return $return;
245
    }
246
247
    /**
248
     * @inheritdoc
249
     */
250 View Code Duplication
    public function setSectionForSubtree($locationId, $sectionId)
251
    {
252
        $this->logger->logCall(__METHOD__, array('location' => $locationId, 'section' => $sectionId));
253
        $this->persistenceHandler->locationHandler()->setSectionForSubtree($locationId, $sectionId);
254
255
        $this->cache->invalidateTags(['location-path-'.$locationId]);
256
    }
257
258
    /**
259
     * @inheritdoc
260
     */
261 View Code Duplication
    public function changeMainLocation($contentId, $locationId)
262
    {
263
        $this->logger->logCall(__METHOD__, array('location' => $locationId, 'content' => $contentId));
264
        $this->persistenceHandler->locationHandler()->changeMainLocation($contentId, $locationId);
265
266
        $this->cache->invalidateTags(['content-'.$contentId]);
267
    }
268
269
    /**
270
     * Return relevant content and location tags so cache can be purged reliably.
271
     *
272
     * @param Location $location
273
     * @param array $tags Optional, can be used to specify additional tags.
274
     *
275
     * @return array
276
     */
277
    private function getCacheTags(Location $location, $tags = [])
278
    {
279
        // @todo use a different content tag here and reflect on in other handlers to be able to clear only content(?)
280
        $tags[] = 'content-'.$location->contentId;
281
        $tags[] = 'location-'.$location->id;
282 View Code Duplication
        foreach (explode('/', trim($location->pathString, '/')) as $pathId) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
283
            $tags[] = 'location-path-'.$pathId;
284
        }
285
286
        return $tags;
287
    }
288
}
289