|
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; |
|
12
|
|
|
use eZ\Publish\SPI\Persistence\Content\ContentInfo; |
|
13
|
|
|
use eZ\Publish\SPI\Persistence\Content\Location\Handler as LocationHandlerInterface; |
|
14
|
|
|
use eZ\Publish\SPI\Persistence\Content\Location\CreateStruct; |
|
15
|
|
|
use eZ\Publish\SPI\Persistence\Content\Location\UpdateStruct; |
|
16
|
|
|
use eZ\Publish\SPI\Persistence\Content\Location; |
|
17
|
|
|
|
|
18
|
|
|
/** |
|
19
|
|
|
* @see \eZ\Publish\SPI\Persistence\Content\Location\Handler |
|
20
|
|
|
*/ |
|
21
|
|
|
class LocationHandler extends AbstractInMemoryPersistenceHandler implements LocationHandlerInterface |
|
22
|
|
|
{ |
|
23
|
|
|
/** @var callable */ |
|
24
|
|
|
private $getLocationTags; |
|
25
|
|
|
|
|
26
|
|
|
/** @var callable */ |
|
27
|
|
|
private $getLocationKeys; |
|
28
|
|
|
|
|
29
|
|
|
protected function init(): void |
|
30
|
|
|
{ |
|
31
|
|
|
$this->getLocationTags = static function (Location $location) { |
|
32
|
|
|
$tags = [ |
|
33
|
|
|
'content-' . $location->contentId, |
|
34
|
|
|
'location-' . $location->id, |
|
35
|
|
|
'location-data-' . $location->id |
|
36
|
|
|
]; |
|
37
|
|
View Code Duplication |
foreach (\explode('/', \trim($location->pathString, '/')) as $pathId) { |
|
|
|
|
|
|
38
|
|
|
$tags[] = 'location-path-' . $pathId; |
|
39
|
|
|
$tags[] = 'location-path-data-' . $pathId; |
|
40
|
|
|
} |
|
41
|
|
|
|
|
42
|
|
|
return $tags; |
|
43
|
|
|
}; |
|
44
|
|
|
$this->getLocationKeys = static function (Location $location, $keySuffix = '-1') { |
|
45
|
|
|
return [ |
|
46
|
|
|
'ez-location-' . $location->id . $keySuffix, |
|
47
|
|
|
'ez-location-remoteid-' . $location->remoteId . $keySuffix, |
|
48
|
|
|
]; |
|
49
|
|
|
}; |
|
50
|
|
|
} |
|
51
|
|
|
|
|
52
|
|
|
|
|
53
|
|
|
/** |
|
54
|
|
|
* {@inheritdoc} |
|
55
|
|
|
*/ |
|
56
|
|
View Code Duplication |
public function load($locationId, array $translations = null, bool $useAlwaysAvailable = true) |
|
57
|
|
|
{ |
|
58
|
|
|
$keySuffix = '-' . $this->getCacheTranslationKey($translations, $useAlwaysAvailable); |
|
59
|
|
|
$getLocationKeysFn = $this->getLocationKeys; |
|
60
|
|
|
|
|
61
|
|
|
|
|
62
|
|
|
return $this->getCacheValue( |
|
63
|
|
|
$locationId, |
|
64
|
|
|
'ez-location-', |
|
65
|
|
|
function ($id) use ($translations, $useAlwaysAvailable) { |
|
66
|
|
|
return $this->persistenceHandler->locationHandler()->load($id, $translations, $useAlwaysAvailable); |
|
|
|
|
|
|
67
|
|
|
}, |
|
68
|
|
|
$this->getLocationTags, |
|
69
|
|
|
static function(Location $location) use ($keySuffix, $getLocationKeysFn) { |
|
70
|
|
|
return $getLocationKeysFn($location, $keySuffix); |
|
71
|
|
|
}, |
|
72
|
|
|
$keySuffix |
|
73
|
|
|
); |
|
74
|
|
|
} |
|
75
|
|
|
|
|
76
|
|
View Code Duplication |
public function loadList(array $locationIds, array $translations = null, bool $useAlwaysAvailable = true): iterable |
|
77
|
|
|
{ |
|
78
|
|
|
$keySuffix = '-' . $this->getCacheTranslationKey($translations, $useAlwaysAvailable); |
|
79
|
|
|
$getLocationKeysFn = $this->getLocationKeys; |
|
80
|
|
|
|
|
81
|
|
|
|
|
82
|
|
|
return $this->getMultipleCacheValues( |
|
|
|
|
|
|
83
|
|
|
$locationIds, |
|
84
|
|
|
'ez-location-', |
|
85
|
|
|
function ($id) use ($translations, $useAlwaysAvailable) { |
|
86
|
|
|
return $this->persistenceHandler->locationHandler()->load($id, $translations, $useAlwaysAvailable); |
|
|
|
|
|
|
87
|
|
|
}, |
|
88
|
|
|
$this->getLocationTags, |
|
89
|
|
|
static function(Location $location) use ($keySuffix, $getLocationKeysFn) { |
|
90
|
|
|
return $getLocationKeysFn($location, $keySuffix); |
|
91
|
|
|
}, |
|
92
|
|
|
$keySuffix |
|
93
|
|
|
); |
|
94
|
|
|
} |
|
95
|
|
|
|
|
96
|
|
|
/** |
|
97
|
|
|
* {@inheritdoc} |
|
98
|
|
|
*/ |
|
99
|
|
|
public function loadSubtreeIds($locationId) |
|
100
|
|
|
{ |
|
101
|
|
|
$cacheItem = $this->cache->getItem("ez-location-subtree-${locationId}"); |
|
102
|
|
|
if ($cacheItem->isHit()) { |
|
103
|
|
|
$this->logger->logCacheHit(['location' => $locationId]); |
|
104
|
|
|
|
|
105
|
|
|
return $cacheItem->get(); |
|
106
|
|
|
} |
|
107
|
|
|
|
|
108
|
|
|
$this->logger->logCacheMiss(['location' => $locationId]); |
|
109
|
|
|
$locationIds = $this->persistenceHandler->locationHandler()->loadSubtreeIds($locationId); |
|
110
|
|
|
|
|
111
|
|
|
$cacheItem->set($locationIds); |
|
112
|
|
|
$cacheTags = ['location-' . $locationId, 'location-path-' . $locationId]; |
|
113
|
|
|
foreach ($locationIds as $id) { |
|
114
|
|
|
$cacheTags[] = 'location-' . $id; |
|
115
|
|
|
$cacheTags[] = 'location-path-' . $id; |
|
116
|
|
|
} |
|
117
|
|
|
$cacheItem->tag($cacheTags); |
|
118
|
|
|
$this->cache->save($cacheItem); |
|
119
|
|
|
|
|
120
|
|
|
return $locationIds; |
|
121
|
|
|
} |
|
122
|
|
|
|
|
123
|
|
|
/** |
|
124
|
|
|
* {@inheritdoc} |
|
125
|
|
|
*/ |
|
126
|
|
|
public function loadLocationsByContent($contentId, $rootLocationId = null) |
|
127
|
|
|
{ |
|
128
|
|
|
if ($rootLocationId) { |
|
|
|
|
|
|
129
|
|
|
$cacheItem = $this->cache->getItem("ez-content-locations-${contentId}-root-${rootLocationId}"); |
|
130
|
|
|
$cacheTags = ['content-' . $contentId, 'location-' . $rootLocationId, 'location-path-' . $rootLocationId]; |
|
131
|
|
|
} else { |
|
132
|
|
|
$cacheItem = $this->cache->getItem("ez-content-locations-${contentId}"); |
|
133
|
|
|
$cacheTags = ['content-' . $contentId]; |
|
134
|
|
|
} |
|
135
|
|
|
|
|
136
|
|
|
if ($cacheItem->isHit()) { |
|
137
|
|
|
$this->logger->logCacheHit(['content' => $contentId, 'root' => $rootLocationId]); |
|
138
|
|
|
|
|
139
|
|
|
return $cacheItem->get(); |
|
140
|
|
|
} |
|
141
|
|
|
|
|
142
|
|
|
$this->logger->logCacheMiss(['content' => $contentId, 'root' => $rootLocationId]); |
|
143
|
|
|
$locations = $this->persistenceHandler->locationHandler()->loadLocationsByContent($contentId, $rootLocationId); |
|
144
|
|
|
|
|
145
|
|
|
$cacheItem->set($locations); |
|
146
|
|
|
foreach ($locations as $location) { |
|
147
|
|
|
$cacheTags = $this->getCacheTags($location, $cacheTags); |
|
148
|
|
|
} |
|
149
|
|
|
$cacheItem->tag($cacheTags); |
|
150
|
|
|
$this->cache->save($cacheItem); |
|
151
|
|
|
|
|
152
|
|
|
return $locations; |
|
153
|
|
|
} |
|
154
|
|
|
|
|
155
|
|
|
/** |
|
156
|
|
|
* {@inheritdoc} |
|
157
|
|
|
*/ |
|
158
|
|
|
public function loadParentLocationsForDraftContent($contentId) |
|
159
|
|
|
{ |
|
160
|
|
|
$cacheItem = $this->cache->getItem("ez-content-locations-${contentId}-parentForDraft"); |
|
161
|
|
|
if ($cacheItem->isHit()) { |
|
162
|
|
|
$this->logger->logCacheHit(['content' => $contentId]); |
|
163
|
|
|
|
|
164
|
|
|
return $cacheItem->get(); |
|
165
|
|
|
} |
|
166
|
|
|
|
|
167
|
|
|
$this->logger->logCacheMiss(['content' => $contentId]); |
|
168
|
|
|
$locations = $this->persistenceHandler->locationHandler()->loadParentLocationsForDraftContent($contentId); |
|
169
|
|
|
|
|
170
|
|
|
$cacheItem->set($locations); |
|
171
|
|
|
$cacheTags = ['content-' . $contentId]; |
|
172
|
|
|
foreach ($locations as $location) { |
|
173
|
|
|
$cacheTags = $this->getCacheTags($location, $cacheTags); |
|
174
|
|
|
} |
|
175
|
|
|
$cacheItem->tag($cacheTags); |
|
176
|
|
|
$this->cache->save($cacheItem); |
|
177
|
|
|
|
|
178
|
|
|
return $locations; |
|
179
|
|
|
} |
|
180
|
|
|
|
|
181
|
|
|
/** |
|
182
|
|
|
* {@inheritdoc} |
|
183
|
|
|
*/ |
|
184
|
|
|
public function loadByRemoteId($remoteId, array $translations = null, bool $useAlwaysAvailable = true) |
|
185
|
|
|
{ |
|
186
|
|
|
$translationsKey = $this->getCacheTranslationKey($translations, $useAlwaysAvailable); |
|
187
|
|
|
$cacheItem = $this->cache->getItem("ez-location-remoteid-${remoteId}-${translationsKey}"); |
|
188
|
|
|
if ($cacheItem->isHit()) { |
|
189
|
|
|
return $cacheItem->get(); |
|
190
|
|
|
} |
|
191
|
|
|
|
|
192
|
|
|
$this->logger->logCall( |
|
193
|
|
|
__METHOD__, |
|
194
|
|
|
['location' => $remoteId, 'translations' => $translations, 'always-available' => $useAlwaysAvailable] |
|
195
|
|
|
); |
|
196
|
|
|
$location = $this->persistenceHandler->locationHandler()->loadByRemoteId($remoteId, $translations, $useAlwaysAvailable); |
|
|
|
|
|
|
197
|
|
|
|
|
198
|
|
|
$cacheItem->set($location); |
|
199
|
|
|
$cacheItem->tag($this->getCacheTags($location)); |
|
200
|
|
|
$this->cache->save($cacheItem); |
|
201
|
|
|
|
|
202
|
|
|
return $location; |
|
203
|
|
|
} |
|
204
|
|
|
|
|
205
|
|
|
/** |
|
206
|
|
|
* {@inheritdoc} |
|
207
|
|
|
*/ |
|
208
|
|
View Code Duplication |
public function copySubtree($sourceId, $destinationParentId, $newOwnerId = null) |
|
209
|
|
|
{ |
|
210
|
|
|
$this->logger->logCall(__METHOD__, array( |
|
211
|
|
|
'source' => $sourceId, |
|
212
|
|
|
'destination' => $destinationParentId, |
|
213
|
|
|
'newOwner' => $newOwnerId, |
|
214
|
|
|
)); |
|
215
|
|
|
|
|
216
|
|
|
return $this->persistenceHandler->locationHandler()->copySubtree($sourceId, $destinationParentId, $newOwnerId); |
|
217
|
|
|
} |
|
218
|
|
|
|
|
219
|
|
|
/** |
|
220
|
|
|
* {@inheritdoc} |
|
221
|
|
|
*/ |
|
222
|
|
View Code Duplication |
public function move($sourceId, $destinationParentId) |
|
223
|
|
|
{ |
|
224
|
|
|
$this->logger->logCall(__METHOD__, array('source' => $sourceId, 'destination' => $destinationParentId)); |
|
225
|
|
|
$return = $this->persistenceHandler->locationHandler()->move($sourceId, $destinationParentId); |
|
226
|
|
|
|
|
227
|
|
|
$this->cache->invalidateTags(['location-path-' . $sourceId]); |
|
228
|
|
|
|
|
229
|
|
|
return $return; |
|
230
|
|
|
} |
|
231
|
|
|
|
|
232
|
|
|
/** |
|
233
|
|
|
* {@inheritdoc} |
|
234
|
|
|
*/ |
|
235
|
|
|
public function markSubtreeModified($locationId, $timestamp = null) |
|
236
|
|
|
{ |
|
237
|
|
|
$this->logger->logCall(__METHOD__, array('location' => $locationId, 'time' => $timestamp)); |
|
238
|
|
|
$this->persistenceHandler->locationHandler()->markSubtreeModified($locationId, $timestamp); |
|
|
|
|
|
|
239
|
|
|
} |
|
240
|
|
|
|
|
241
|
|
|
/** |
|
242
|
|
|
* {@inheritdoc} |
|
243
|
|
|
*/ |
|
244
|
|
View Code Duplication |
public function hide($locationId) |
|
245
|
|
|
{ |
|
246
|
|
|
$this->logger->logCall(__METHOD__, array('location' => $locationId)); |
|
247
|
|
|
$return = $this->persistenceHandler->locationHandler()->hide($locationId); |
|
248
|
|
|
|
|
249
|
|
|
$this->cache->invalidateTags(['location-path-data-' . $locationId]); |
|
250
|
|
|
|
|
251
|
|
|
return $return; |
|
252
|
|
|
} |
|
253
|
|
|
|
|
254
|
|
|
/** |
|
255
|
|
|
* {@inheritdoc} |
|
256
|
|
|
*/ |
|
257
|
|
|
public function unHide($locationId) |
|
258
|
|
|
{ |
|
259
|
|
|
$this->logger->logCall(__METHOD__, array('location' => $locationId)); |
|
260
|
|
|
$return = $this->persistenceHandler->locationHandler()->unHide($locationId); |
|
261
|
|
|
|
|
262
|
|
|
$this->cache->invalidateTags(['location-path-data-' . $locationId]); |
|
263
|
|
|
|
|
264
|
|
|
return $return; |
|
265
|
|
|
} |
|
266
|
|
|
|
|
267
|
|
|
/** |
|
268
|
|
|
* Sets a location + all children to invisible. |
|
269
|
|
|
* |
|
270
|
|
|
* @param int $id Location ID |
|
271
|
|
|
*/ |
|
272
|
|
View Code Duplication |
public function setInvisible(int $id): void |
|
273
|
|
|
{ |
|
274
|
|
|
$this->logger->logCall(__METHOD__, ['location' => $id]); |
|
275
|
|
|
$this->persistenceHandler->locationHandler()->setInvisible($id); |
|
276
|
|
|
|
|
277
|
|
|
$this->cache->invalidateTags(['location-path-data-' . $id]); |
|
278
|
|
|
} |
|
279
|
|
|
|
|
280
|
|
|
/** |
|
281
|
|
|
* Sets a location + all children to visible. |
|
282
|
|
|
* |
|
283
|
|
|
* @param int $id Location ID |
|
284
|
|
|
*/ |
|
285
|
|
View Code Duplication |
public function setVisible(int $id): void |
|
286
|
|
|
{ |
|
287
|
|
|
$this->logger->logCall(__METHOD__, ['location' => $id]); |
|
288
|
|
|
$this->persistenceHandler->locationHandler()->setVisible($id); |
|
289
|
|
|
|
|
290
|
|
|
$this->cache->invalidateTags(['location-path-data-' . $id]); |
|
291
|
|
|
} |
|
292
|
|
|
|
|
293
|
|
|
/** |
|
294
|
|
|
* {@inheritdoc} |
|
295
|
|
|
*/ |
|
296
|
|
|
public function swap($locationId1, $locationId2) |
|
297
|
|
|
{ |
|
298
|
|
|
$this->logger->logCall(__METHOD__, array('location1' => $locationId1, 'location2' => $locationId2)); |
|
299
|
|
|
$locationHandler = $this->persistenceHandler->locationHandler(); |
|
300
|
|
|
|
|
301
|
|
|
$return = $locationHandler->swap($locationId1, $locationId2); |
|
302
|
|
|
|
|
303
|
|
|
$this->cache->invalidateTags( |
|
304
|
|
|
[ |
|
305
|
|
|
'location-' . $locationId1, |
|
306
|
|
|
'location-' . $locationId2, |
|
307
|
|
|
] |
|
308
|
|
|
); |
|
309
|
|
|
|
|
310
|
|
|
return $return; |
|
311
|
|
|
} |
|
312
|
|
|
|
|
313
|
|
|
/** |
|
314
|
|
|
* {@inheritdoc} |
|
315
|
|
|
*/ |
|
316
|
|
|
public function update(UpdateStruct $struct, $locationId) |
|
317
|
|
|
{ |
|
318
|
|
|
$this->logger->logCall(__METHOD__, array('location' => $locationId, 'struct' => $struct)); |
|
319
|
|
|
$this->persistenceHandler->locationHandler()->update($struct, $locationId); |
|
320
|
|
|
|
|
321
|
|
|
$this->cache->invalidateTags(['location-data-' . $locationId]); |
|
322
|
|
|
} |
|
323
|
|
|
|
|
324
|
|
|
/** |
|
325
|
|
|
* {@inheritdoc} |
|
326
|
|
|
*/ |
|
327
|
|
View Code Duplication |
public function create(CreateStruct $locationStruct) |
|
328
|
|
|
{ |
|
329
|
|
|
$this->logger->logCall(__METHOD__, array('struct' => $locationStruct)); |
|
330
|
|
|
$location = $this->persistenceHandler->locationHandler()->create($locationStruct); |
|
331
|
|
|
|
|
332
|
|
|
// need to clear loadLocationsByContent and similar collections involving locations data |
|
333
|
|
|
// also need to clear content info on main location changes |
|
334
|
|
|
$this->cache->invalidateTags(['content-' . $locationStruct->contentId, 'role-assignment-group-list-' . $locationStruct->contentId]); |
|
335
|
|
|
|
|
336
|
|
|
return $location; |
|
337
|
|
|
} |
|
338
|
|
|
|
|
339
|
|
|
/** |
|
340
|
|
|
* {@inheritdoc} |
|
341
|
|
|
*/ |
|
342
|
|
|
public function removeSubtree($locationId) |
|
343
|
|
|
{ |
|
344
|
|
|
$this->logger->logCall(__METHOD__, array('location' => $locationId)); |
|
345
|
|
|
$return = $this->persistenceHandler->locationHandler()->removeSubtree($locationId); |
|
346
|
|
|
|
|
347
|
|
|
$this->cache->invalidateTags(['location-path-' . $locationId]); |
|
348
|
|
|
|
|
349
|
|
|
return $return; |
|
350
|
|
|
} |
|
351
|
|
|
|
|
352
|
|
|
/** |
|
353
|
|
|
* {@inheritdoc} |
|
354
|
|
|
*/ |
|
355
|
|
|
public function setSectionForSubtree($locationId, $sectionId) |
|
356
|
|
|
{ |
|
357
|
|
|
$this->logger->logCall(__METHOD__, array('location' => $locationId, 'section' => $sectionId)); |
|
358
|
|
|
$this->persistenceHandler->locationHandler()->setSectionForSubtree($locationId, $sectionId); |
|
359
|
|
|
|
|
360
|
|
|
$this->cache->invalidateTags(['location-path-' . $locationId]); |
|
361
|
|
|
} |
|
362
|
|
|
|
|
363
|
|
|
/** |
|
364
|
|
|
* {@inheritdoc} |
|
365
|
|
|
*/ |
|
366
|
|
|
public function changeMainLocation($contentId, $locationId) |
|
367
|
|
|
{ |
|
368
|
|
|
$this->logger->logCall(__METHOD__, array('location' => $locationId, 'content' => $contentId)); |
|
369
|
|
|
$this->persistenceHandler->locationHandler()->changeMainLocation($contentId, $locationId); |
|
370
|
|
|
|
|
371
|
|
|
$this->cache->invalidateTags(['content-' . $contentId]); |
|
372
|
|
|
} |
|
373
|
|
|
|
|
374
|
|
|
/** |
|
375
|
|
|
* Get the total number of all existing Locations. Can be combined with loadAllLocations. |
|
376
|
|
|
* |
|
377
|
|
|
* @return int |
|
378
|
|
|
*/ |
|
379
|
|
|
public function countAllLocations() |
|
380
|
|
|
{ |
|
381
|
|
|
$this->logger->logCall(__METHOD__); |
|
382
|
|
|
|
|
383
|
|
|
return $this->persistenceHandler->locationHandler()->countAllLocations(); |
|
384
|
|
|
} |
|
385
|
|
|
|
|
386
|
|
|
/** |
|
387
|
|
|
* Bulk-load all existing Locations, constrained by $limit and $offset to paginate results. |
|
388
|
|
|
* |
|
389
|
|
|
* @param int $offset |
|
390
|
|
|
* @param int $limit |
|
391
|
|
|
* |
|
392
|
|
|
* @return \eZ\Publish\SPI\Persistence\Content\Location[] |
|
393
|
|
|
*/ |
|
394
|
|
|
public function loadAllLocations($offset, $limit) |
|
395
|
|
|
{ |
|
396
|
|
|
$this->logger->logCall(__METHOD__, array('offset' => $offset, 'limit' => $limit)); |
|
397
|
|
|
|
|
398
|
|
|
return $this->persistenceHandler->locationHandler()->loadAllLocations($offset, $limit); |
|
399
|
|
|
} |
|
400
|
|
|
|
|
401
|
|
|
/** |
|
402
|
|
|
* Return relevant content and location tags so cache can be purged reliably. |
|
403
|
|
|
* |
|
404
|
|
|
* @param \eZ\Publish\SPI\Persistence\Content\Location $location |
|
405
|
|
|
* @param array $tags Optional, can be used to specify additional tags. |
|
406
|
|
|
* |
|
407
|
|
|
* @return array |
|
408
|
|
|
*/ |
|
409
|
|
|
private function getCacheTags(Location $location, $tags = []) |
|
410
|
|
|
{ |
|
411
|
|
|
$tags[] = 'content-' . $location->contentId; |
|
412
|
|
|
$tags[] = 'location-' . $location->id; |
|
413
|
|
|
$tags[] = 'location-data-' . $location->id; |
|
414
|
|
View Code Duplication |
foreach (explode('/', trim($location->pathString, '/')) as $pathId) { |
|
|
|
|
|
|
415
|
|
|
$tags[] = 'location-path-' . $pathId; |
|
416
|
|
|
$tags[] = 'location-path-data-' . $pathId; |
|
417
|
|
|
} |
|
418
|
|
|
|
|
419
|
|
|
return $tags; |
|
420
|
|
|
} |
|
421
|
|
|
|
|
422
|
|
|
private function getCacheTranslationKey(array $translations = null, bool $useAlwaysAvailable = true): string |
|
423
|
|
|
{ |
|
424
|
|
|
if (empty($translations)) { |
|
425
|
|
|
return (int)$useAlwaysAvailable; |
|
426
|
|
|
} |
|
427
|
|
|
|
|
428
|
|
|
// Sort array as we don't care about order in location handler usage & want to optimize for cache hits. |
|
429
|
|
|
sort($translations); |
|
430
|
|
|
|
|
431
|
|
|
return implode('|', $translations) . '|' . (int)$useAlwaysAvailable; |
|
432
|
|
|
} |
|
433
|
|
|
} |
|
434
|
|
|
|
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.