Completed
Push — ezp25636_user_cant_access_tras... ( b1f7b8 )
by
unknown
21:26
created

TrashService::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 9
nc 1
nop 4
dl 0
loc 14
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * File containing the eZ\Publish\Core\Repository\TrashService class.
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\Repository;
10
11
use eZ\Publish\API\Repository\TrashService as TrashServiceInterface;
12
use eZ\Publish\API\Repository\Repository as RepositoryInterface;
13
use eZ\Publish\SPI\Persistence\Handler;
14
use eZ\Publish\API\Repository\Values\Content\Location;
15
use eZ\Publish\Core\Repository\Values\Content\TrashItem;
16
use eZ\Publish\API\Repository\Values\Content\TrashItem as APITrashItem;
17
use eZ\Publish\API\Repository\Values\Content\Query;
18
use eZ\Publish\SPI\Persistence\Content\Location\Trashed;
19
use eZ\Publish\Core\Base\Exceptions\InvalidArgumentValue;
20
use eZ\Publish\Core\Base\Exceptions\UnauthorizedException;
21
use eZ\Publish\API\Repository\Values\Content\SearchResult;
22
use eZ\Publish\API\Repository\Values\Content\Query\Criterion;
23
use eZ\Publish\API\Repository\Values\Content\Query\SortClause;
24
use DateTime;
25
use Exception;
26
27
/**
28
 * Trash service, used for managing trashed content.
29
 */
30
class TrashService implements TrashServiceInterface
31
{
32
    /**
33
     * @var \eZ\Publish\API\Repository\Repository
34
     */
35
    protected $repository;
36
37
    /**
38
     * @var \eZ\Publish\SPI\Persistence\Handler
39
     */
40
    protected $persistenceHandler;
41
42
    /**
43
     * @var array
44
     */
45
    protected $settings;
46
47
    /**
48
     * @var \eZ\Publish\Core\Repository\Helper\NameSchemaService
49
     */
50
    protected $nameSchemaService;
51
52
    /**
53
     * Setups service with reference to repository object that created it & corresponding handler.
54
     *
55
     * @param \eZ\Publish\API\Repository\Repository $repository
56
     * @param \eZ\Publish\SPI\Persistence\Handler $handler
57
     * @param \eZ\Publish\Core\Repository\Helper\NameSchemaService $nameSchemaService
58
     * @param array $settings
59
     */
60
    public function __construct(
61
        RepositoryInterface $repository,
62
        Handler $handler,
63
        Helper\NameSchemaService $nameSchemaService,
64
        array $settings = array()
65
    ) {
66
        $this->repository = $repository;
67
        $this->persistenceHandler = $handler;
68
        $this->nameSchemaService = $nameSchemaService;
69
        // Union makes sure default settings are ignored if provided in argument
70
        $this->settings = $settings + array(
71
            //'defaultSetting' => array(),
72
        );
73
    }
74
75
    /**
76
     * Loads a trashed location object from its $id.
77
     *
78
     * Note that $id is identical to original location, which has been previously trashed
79
     *
80
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException if the user is not allowed to read the trashed location
81
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException - if the location with the given id does not exist
82
     *
83
     * @param mixed $trashItemId
84
     *
85
     * @return \eZ\Publish\API\Repository\Values\Content\TrashItem
86
     */
87
    public function loadTrashItem($trashItemId)
88
    {
89
        if ($this->repository->hasAccess('content', 'restore') !== true) {
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repository\Repository::hasAccess() has been deprecated with message: since 6.6, to be removed. Use PermissionResolver::hasAccess() instead.

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...
90
            throw new UnauthorizedException('content', 'restore');
91
        }
92
93
        $spiTrashItem = $this->persistenceHandler->trashHandler()->loadTrashItem($trashItemId);
94
        $trash = $this->buildDomainTrashItemObject($spiTrashItem);
95
        if (!$this->repository->canUser('content', 'read', $trash->getContentInfo())) {
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repository\Repository::canUser() has been deprecated with message: since 6.6, to be removed. Use PermissionResolver::canUser() instead. Indicates if the current user is allowed to perform an action given by the function on the given
objects. Example: canUser( 'content', 'edit', $content, $location ); This will check edit permission on content given the specific location, if skipped if will check on all locations. Example2: canUser( 'section', 'assign', $content, $section ); Check if user has access to assign $content to $section.

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...
96
            throw new UnauthorizedException('content', 'read');
97
        }
98
99
        return $trash;
100
    }
101
102
    /**
103
     * Sends $location and all its children to trash and returns the corresponding trash item.
104
     *
105
     * Content is left untouched.
106
     *
107
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException if the user is not allowed to trash the given location
108
     *
109
     * @param \eZ\Publish\API\Repository\Values\Content\Location $location
110
     *
111
     * @return null|\eZ\Publish\API\Repository\Values\Content\TrashItem null if location was deleted, otherwise TrashItem
112
     */
113
    public function trash(Location $location)
114
    {
115
        if (!is_numeric($location->id)) {
116
            throw new InvalidArgumentValue('id', $location->id, 'Location');
117
        }
118
119
        if ($this->repository->canUser('content', 'manage_locations', $location->getContentInfo(), $location) !== true) {
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repository\Repository::canUser() has been deprecated with message: since 6.6, to be removed. Use PermissionResolver::canUser() instead. Indicates if the current user is allowed to perform an action given by the function on the given
objects. Example: canUser( 'content', 'edit', $content, $location ); This will check edit permission on content given the specific location, if skipped if will check on all locations. Example2: canUser( 'section', 'assign', $content, $section ); Check if user has access to assign $content to $section.

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...
120
            throw new UnauthorizedException('content', 'manage_locations');
121
        }
122
123
        $this->repository->beginTransaction();
124
        try {
125
            $spiTrashItem = $this->persistenceHandler->trashHandler()->trashSubtree($location->id);
126
            $this->persistenceHandler->urlAliasHandler()->locationDeleted($location->id);
127
            $this->repository->commit();
128
        } catch (Exception $e) {
129
            $this->repository->rollback();
130
            throw $e;
131
        }
132
133
        return isset($spiTrashItem)
134
            ? $this->buildDomainTrashItemObject($spiTrashItem)
135
            : null;
136
    }
137
138
    /**
139
     * Recovers the $trashedLocation at its original place if possible.
140
     *
141
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException if the user is not allowed to recover the trash item at the parent location location
142
     *
143
     * If $newParentLocation is provided, $trashedLocation will be restored under it.
144
     *
145
     * @param \eZ\Publish\API\Repository\Values\Content\TrashItem $trashItem
146
     * @param \eZ\Publish\API\Repository\Values\Content\Location $newParentLocation
147
     *
148
     * @return \eZ\Publish\API\Repository\Values\Content\Location the newly created or recovered location
149
     */
150
    public function recover(APITrashItem $trashItem, Location $newParentLocation = null)
151
    {
152
        if (!is_numeric($trashItem->id)) {
0 ignored issues
show
Documentation introduced by
The property $id is declared protected in eZ\Publish\API\Repository\Values\Content\Location. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
153
            throw new InvalidArgumentValue('id', $trashItem->id, 'TrashItem');
0 ignored issues
show
Documentation introduced by
The property $id is declared protected in eZ\Publish\API\Repository\Values\Content\Location. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
154
        }
155
156
        if ($newParentLocation === null && !is_numeric($trashItem->parentLocationId)) {
0 ignored issues
show
Documentation introduced by
The property $parentLocationId is declared protected in eZ\Publish\API\Repository\Values\Content\Location. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
157
            throw new InvalidArgumentValue('parentLocationId', $trashItem->parentLocationId, 'TrashItem');
0 ignored issues
show
Documentation introduced by
The property $parentLocationId is declared protected in eZ\Publish\API\Repository\Values\Content\Location. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
158
        }
159
160
        if ($newParentLocation !== null && !is_numeric($newParentLocation->id)) {
161
            throw new InvalidArgumentValue('parentLocationId', $newParentLocation->id, 'Location');
162
        }
163
164
        if ($this->repository->hasAccess('content', 'restore') !== true) {
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repository\Repository::hasAccess() has been deprecated with message: since 6.6, to be removed. Use PermissionResolver::hasAccess() instead.

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...
165
            throw new UnauthorizedException('content', 'restore');
166
        }
167
168
        $this->repository->beginTransaction();
169
        try {
170
            $newParentLocationId = $newParentLocation ? $newParentLocation->id : $trashItem->parentLocationId;
0 ignored issues
show
Documentation introduced by
The property $parentLocationId is declared protected in eZ\Publish\API\Repository\Values\Content\Location. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
171
            $newLocationId = $this->persistenceHandler->trashHandler()->recover(
172
                $trashItem->id,
0 ignored issues
show
Documentation introduced by
The property $id is declared protected in eZ\Publish\API\Repository\Values\Content\Location. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
173
                $newParentLocationId
174
            );
175
176
            $content = $this->repository->getContentService()->loadContent($trashItem->contentId);
177
            $urlAliasNames = $this->nameSchemaService->resolveUrlAliasSchema($content);
178
179
            // Publish URL aliases for recovered location
180
            foreach ($urlAliasNames as $languageCode => $name) {
181
                $this->persistenceHandler->urlAliasHandler()->publishUrlAliasForLocation(
182
                    $newLocationId,
183
                    $newParentLocationId,
184
                    $name,
185
                    $languageCode,
186
                    $content->contentInfo->alwaysAvailable
187
                );
188
            }
189
190
            $this->repository->commit();
191
        } catch (Exception $e) {
192
            $this->repository->rollback();
193
            throw $e;
194
        }
195
196
        return $this->repository->getLocationService()->loadLocation($newLocationId);
197
    }
198
199
    /**
200
     * Empties trash.
201
     *
202
     * All locations contained in the trash will be removed. Content objects will be removed
203
     * if all locations of the content are gone.
204
     *
205
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException if the user is not allowed to empty the trash
206
     */
207 View Code Duplication
    public function emptyTrash()
208
    {
209
        if ($this->repository->hasAccess('content', 'cleantrash') !== true) {
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repository\Repository::hasAccess() has been deprecated with message: since 6.6, to be removed. Use PermissionResolver::hasAccess() instead.

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...
210
            throw new UnauthorizedException('content', 'cleantrash');
211
        }
212
213
        $this->repository->beginTransaction();
214
        try {
215
            // Persistence layer takes care of deleting content objects
216
            $this->persistenceHandler->trashHandler()->emptyTrash();
217
            $this->repository->commit();
218
        } catch (Exception $e) {
219
            $this->repository->rollback();
220
            throw $e;
221
        }
222
    }
223
224
    /**
225
     * Deletes a trash item.
226
     *
227
     * The corresponding content object will be removed
228
     *
229
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException if the user is not allowed to delete this trash item
230
     *
231
     * @param \eZ\Publish\API\Repository\Values\Content\TrashItem $trashItem
232
     */
233 View Code Duplication
    public function deleteTrashItem(APITrashItem $trashItem)
234
    {
235
        if ($this->repository->hasAccess('content', 'cleantrash') !== true) {
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repository\Repository::hasAccess() has been deprecated with message: since 6.6, to be removed. Use PermissionResolver::hasAccess() instead.

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...
236
            throw new UnauthorizedException('content', 'cleantrash');
237
        }
238
239
        if (!is_numeric($trashItem->id)) {
0 ignored issues
show
Documentation introduced by
The property $id is declared protected in eZ\Publish\API\Repository\Values\Content\Location. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
240
            throw new InvalidArgumentValue('id', $trashItem->id, 'TrashItem');
0 ignored issues
show
Documentation introduced by
The property $id is declared protected in eZ\Publish\API\Repository\Values\Content\Location. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
241
        }
242
243
        $this->repository->beginTransaction();
244
        try {
245
            $this->persistenceHandler->trashHandler()->deleteTrashItem($trashItem->id);
0 ignored issues
show
Documentation introduced by
The property $id is declared protected in eZ\Publish\API\Repository\Values\Content\Location. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
246
            $this->repository->commit();
247
        } catch (Exception $e) {
248
            $this->repository->rollback();
249
            throw $e;
250
        }
251
    }
252
253
    /**
254
     * Returns a collection of Trashed locations contained in the trash.
255
     *
256
     * $query allows to filter/sort the elements to be contained in the collection.
257
     *
258
     * @param \eZ\Publish\API\Repository\Values\Content\Query $query
259
     *
260
     * @return \eZ\Publish\API\Repository\Values\Content\SearchResult
261
     */
262
    public function findTrashItems(Query $query)
263
    {
264
        if ($query->filter !== null && !$query->filter instanceof Criterion) {
265
            throw new InvalidArgumentValue('query->filter', $query->filter, 'Query');
266
        }
267
268
        if ($query->sortClauses !== null) {
269
            if (!is_array($query->sortClauses)) {
270
                throw new InvalidArgumentValue('query->sortClauses', $query->sortClauses, 'Query');
271
            }
272
273
            foreach ($query->sortClauses as $sortClause) {
274
                if (!$sortClause instanceof SortClause) {
275
                    throw new InvalidArgumentValue('query->sortClauses', 'only instances of SortClause class are allowed');
276
                }
277
            }
278
        }
279
280
        if ($query->offset !== null && !is_numeric($query->offset)) {
281
            throw new InvalidArgumentValue('query->offset', $query->offset, 'Query');
282
        }
283
284
        if ($query->limit !== null && !is_numeric($query->limit)) {
285
            throw new InvalidArgumentValue('query->limit', $query->limit, 'Query');
286
        }
287
288
        $spiTrashItems = $this->persistenceHandler->trashHandler()->findTrashItems(
289
            $query->filter !== null ? $query->filter : null,
290
            $query->offset !== null && $query->offset > 0 ? (int)$query->offset : 0,
291
            $query->limit !== null && $query->limit >= 1 ? (int)$query->limit : null,
292
            $query->sortClauses !== null ? $query->sortClauses : null
0 ignored issues
show
Bug introduced by
It seems like $query->sortClauses !== ...ery->sortClauses : null can also be of type array; however, eZ\Publish\SPI\Persisten...ndler::findTrashItems() does only seem to accept null|array<integer,objec...tent\Query\SortClause>>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
293
        );
294
295
        $trashItems = array();
296
        foreach ($spiTrashItems as $spiTrashItem) {
297
            $trashItems[] = $this->buildDomainTrashItemObject($spiTrashItem);
298
        }
299
300
        $searchResult = new SearchResult();
0 ignored issues
show
Deprecated Code introduced by
The class eZ\Publish\API\Repositor...es\Content\SearchResult has been deprecated with message: This class is returned by find methods providing a result of a search.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

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

Loading history...
301
        $searchResult->count = count($trashItems);
302
        $searchResult->items = $trashItems;
303
        $searchResult->query = $query;
304
305
        return $searchResult;
306
    }
307
308
    /**
309
     * Builds the domain TrashItem object from provided persistence trash item.
310
     *
311
     * @param \eZ\Publish\SPI\Persistence\Content\Location\Trashed $spiTrashItem
312
     *
313
     * @return \eZ\Publish\API\Repository\Values\Content\TrashItem
314
     */
315
    protected function buildDomainTrashItemObject(Trashed $spiTrashItem)
316
    {
317
        // Use sudo as all trash items should be readable when viewing the trash bin
318
        $contentInfo = $this->repository->sudo(
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface eZ\Publish\API\Repository\Repository as the method sudo() does only exist in the following implementations of said interface: eZ\Publish\Core\Repository\Repository, eZ\Publish\Core\SignalSlot\Repository.

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...
319
            function () use ($spiTrashItem) {
320
                return $this->repository->getContentService()->loadContentInfo($spiTrashItem->contentId);
321
            }
322
        );
323
324
        return new TrashItem(
325
            array(
326
                'contentInfo' => $contentInfo,
327
                'id' => $spiTrashItem->id,
328
                'priority' => $spiTrashItem->priority,
329
                'hidden' => $spiTrashItem->hidden,
330
                'invisible' => $spiTrashItem->invisible,
331
                'remoteId' => $spiTrashItem->remoteId,
332
                'parentLocationId' => $spiTrashItem->parentId,
333
                'pathString' => $spiTrashItem->pathString,
334
                'depth' => $spiTrashItem->depth,
335
                'sortField' => $spiTrashItem->sortField,
336
                'sortOrder' => $spiTrashItem->sortOrder,
337
            )
338
        );
339
    }
340
341
    /**
342
     * @param int $timestamp
343
     *
344
     * @return \DateTime
345
     */
346
    protected function getDateTime($timestamp)
347
    {
348
        $dateTime = new DateTime();
349
        $dateTime->setTimestamp($timestamp);
350
351
        return $dateTime;
352
    }
353
}
354