Completed
Push — master ( d466fc...57558f )
by Pavel
03:56
created

ApiPersister::loadAll()   B

Complexity

Conditions 8
Paths 16

Size

Total Lines 60
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 37
CRAP Score 8.1077

Importance

Changes 2
Bugs 1 Features 0
Metric Value
c 2
b 1
f 0
dl 0
loc 60
ccs 37
cts 42
cp 0.881
rs 7.0677
cc 8
eloc 35
nc 16
nop 4
crap 8.1077

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Bankiru\Api\Doctrine\Persister;
4
5
use Bankiru\Api\Doctrine\EntityManager;
6
use Bankiru\Api\Doctrine\Mapping\ApiMetadata;
7
use Bankiru\Api\Doctrine\Mapping\EntityMetadata;
8
use Bankiru\Api\Doctrine\Proxy\ApiCollection;
9
use Bankiru\Api\Doctrine\Rpc\Finder;
10
use Bankiru\Api\Doctrine\Rpc\Searcher;
11
use Doctrine\Common\Collections\AbstractLazyCollection;
12
use Doctrine\Common\Collections\ArrayCollection;
13
use Doctrine\Common\Collections\Collection;
14
use ScayTrase\Api\Rpc\RpcClientInterface;
15
16
class ApiPersister implements EntityPersister
17
{
18
    /** @var  RpcClientInterface */
19
    private $client;
20
    /** @var  EntityMetadata */
21
    private $metadata;
22
    /** @var EntityManager */
23
    private $manager;
24
25
    /**
26
     * ApiPersister constructor.
27
     *
28
     * @param EntityManager $manager
29
     * @param ApiMetadata   $metadata
30
     */
31 13
    public function __construct(EntityManager $manager, ApiMetadata $metadata)
32
    {
33 13
        $this->manager  = $manager;
34 13
        $this->client   = $manager->getConfiguration()->getRegistry()->get($metadata->getClientName());
35 13
        $this->metadata = $metadata;
0 ignored issues
show
Documentation Bug introduced by
$metadata is of type object<Bankiru\Api\Doctrine\Mapping\ApiMetadata>, but the property $metadata was declared to be of type object<Bankiru\Api\Doctr...Mapping\EntityMetadata>. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
36 13
    }
37
38
    /**
39
     * @return ApiMetadata
40
     */
41 11
    public function getClassMetadata()
42
    {
43 11
        return $this->metadata;
44
    }
45
46
    /**
47
     * Updates a managed entity. The entity is updated according to its current changeset
48
     * in the running UnitOfWork. If there is no changeset, nothing is updated.
49
     *
50
     * @param object $entity The entity to update.
51
     *
52
     * @return void
53
     */
54
    public function update($entity)
55
    {
56
        throw new \BadMethodCallException('Update method is not supported currently');
57
    }
58
59
    /**
60
     * Deletes a managed entity.
61
     *
62
     * The entity to delete must be managed and have a persistent identifier.
63
     * The deletion happens instantaneously.
64
     *
65
     * Subclasses may override this method to customize the semantics of entity deletion.
66
     *
67
     * @param object $entity The entity to delete.
68
     *
69
     * @return bool TRUE if the entity got deleted in the database, FALSE otherwise.
70
     */
71
    public function delete($entity)
72
    {
73
        throw new \BadMethodCallException('Delete method is not supported currently');
74
    }
75
76
    /**
77
     * Count entities (optionally filtered by a criteria)
78
     *
79
     * @param  array|\Doctrine\Common\Collections\Criteria $criteria
80
     *
81
     * @return int
82
     */
83
    public function count($criteria = [])
84
    {
85
        return count($this->loadAll($criteria));
0 ignored issues
show
Bug introduced by
It seems like $criteria defined by parameter $criteria on line 83 can also be of type object<Doctrine\Common\Collections\Criteria>; however, Bankiru\Api\Doctrine\Per...ApiPersister::loadAll() does only seem to accept array, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
86
    }
87
88
    /**
89
     * Loads a list of entities by a list of field criteria.
90
     *
91
     * @param array      $criteria
92
     * @param array|null $orderBy
93
     * @param int|null   $limit
94
     * @param int|null   $offset
95
     *
96
     * @return Collection
97
     */
98 5
    public function loadAll(array $criteria = [], array $orderBy = null, $limit = null, $offset = null)
99
    {
100 5
        $client = $this->manager->getConfiguration()->getRegistry()->get($this->metadata->getClientName());
101
102
        /** @var Searcher $searcher */
103 5
        $searcherClass = $this->metadata->getSearcherClass();
104 5
        $searcher      = new $searcherClass($this->manager);
105
106 5
        $apiCriteria = [];
107 5
        foreach ($criteria as $field => $values) {
108 5
            if ($this->metadata->hasAssociation($field)) {
109 3
                $mapping = $this->metadata->getAssociationMapping($field);
110
                /** @var EntityMetadata $target */
111 3
                $target = $this->manager->getClassMetadata($mapping['target']);
112
113 3
                $converter = function ($value) use ($target) {
114 3
                    if (!is_object($value)) {
115
                        return $value;
116
                    }
117
118 3
                    $ids = $target->getIdentifierValues($value);
119 3
                    if ($target->isIdentifierComposite) {
120
                        return $ids;
121
                    }
122
123 3
                    return array_shift($ids);
124 3
                };
125
126 3
                if (is_array($values)) {
127
                    $values = array_map($converter, $values);
128
                } else {
129 3
                    $values = $converter($values);
130
                }
131 3
            }
132 5
            $apiCriteria[$this->metadata->getApiFieldName($field)] = $values;
133 5
        }
134
135 5
        $apiOrder = [];
136 5
        foreach ((array)$orderBy as $field => $direction) {
137
            $apiOrder[$this->metadata->getApiFieldName($field)] = $direction;
138 5
        }
139
140 5
        $objects = $searcher->search(
141 5
            $client,
142 5
            $this->metadata,
143 1
            [
144 5
                $apiCriteria,
145 5
                $apiOrder,
146 5
                $limit,
147 5
                $offset,
148
            ]
149 5
        );
150
151 4
        $entities = [];
152 4
        foreach ($objects as $object) {
153 4
            $entities[] = $this->manager->getUnitOfWork()->getOrCreateEntity($this->metadata->getName(), $object);
154 4
        }
155
156 4
        return new ArrayCollection($entities);
157
    }
158
159
    /**
160
     * Loads an entity by a list of field criteria.
161
     *
162
     * @param array       $criteria The criteria by which to load the entity.
163
     * @param object|null $entity   The entity to load the data into. If not specified, a new entity is created.
164
     * @param array|null  $assoc    The association that connects the entity to load to another entity, if any.
165
     * @param int|null    $limit    Limit number of results.
166
     * @param array|null  $orderBy  Criteria to order by.
167
     *
168
     * @return object|null The loaded and managed entity instance or NULL if the entity can not be found.
169
     */
170
    public function load(array $criteria,
171
                         $entity = null,
172
                         $assoc = null,
173
                         $limit = null,
174
                         array $orderBy = null)
175
    {
176
        // TODO: Implement load() method.
177
    }
178
179
    /**
180
     * Loads an entity of this persister's mapped class as part of a single-valued
181
     * association from another entity.
182
     *
183
     * @param array  $assoc        The association to load.
184
     * @param object $sourceEntity The entity that owns the association (not necessarily the "owning side").
185
     * @param array  $identifier   The identifier of the entity to load. Must be provided if
186
     *                             the association to load represents the owning side, otherwise
187
     *                             the identifier is derived from the $sourceEntity.
188
     *
189
     * @return object The loaded and managed entity instance or NULL if the entity can not be found.
190
     */
191
    public function loadOneToOneEntity(array $assoc, $sourceEntity, array $identifier = [])
192
    {
193
        if (false !== ($foundEntity = $this->manager->getUnitOfWork()->tryGetById($identifier, $assoc['target']))) {
194
            return $foundEntity;
195
        }
196
197
        // Get identifiers from entity if the entity is not the owning side
198
        if (!$assoc['isOwningSide']) {
199
            $identifier = $this->metadata->getIdentifierValues($sourceEntity);
200
        }
201
202
        return $this->loadById($identifier);
203
    }
204
205 11
    public function loadById(array $identifiers, $entity = null)
206
    {
207 11
        $finderClass = $this->metadata->getFinderClass();
208
        /** @var Finder $finder */
209 11
        $finder = new $finderClass($this->manager);
210 11
        $body   = $finder->find($this->client, $this->metadata, $identifiers);
211
212 11
        if (null === $body) {
213
            return null;
214
        }
215
216 11
        $entity = $this->manager->getUnitOfWork()->getOrCreateEntity($this->metadata->getName(), $body, $entity);
217
218 11
        return $entity;
219
    }
220
221
    /**
222
     * Refreshes a managed entity.
223
     *
224
     * @param array    $id       The identifier of the entity as an associative array from
225
     *                           column or field names to values.
226
     * @param object   $entity   The entity to refresh.
227
     * @param int|null $lockMode One of the \Doctrine\DBAL\LockMode::* constants
228
     *                           or NULL if no specific lock mode should be used
229
     *                           for refreshing the managed entity.
230
     *
231
     * @return void
232
     */
233
    public function refresh(array $id, $entity, $lockMode = null)
234
    {
235
        throw new \BadMethodCallException('Refresh method is not supported currently');
236
    }
237
238
    /**
239
     * Loads a collection of entities in a one-to-many association.
240
     *
241
     * @param array                  $assoc
242
     * @param object                 $sourceEntity
243
     * @param AbstractLazyCollection $collection The collection to load/fill.
244
     *
245
     * @return Collection
246
     */
247
    public function loadOneToManyCollection(array $assoc, $sourceEntity, AbstractLazyCollection $collection)
248
    {
249
        if ($collection instanceof ApiCollection) {
250
            foreach ($collection->getIterator() as $entity) {
251
                $this->metadata->getReflectionProperty($assoc['mappedBy'])->setValue($entity, $sourceEntity);
252
            }
253
        }
254
255
        return $collection;
256
    }
257
258
    /**
259
     * Returns an array with (sliced or full list) of elements in the specified collection.
260
     *
261
     * @param array    $assoc
262
     * @param object   $sourceEntity
263
     * @param int|null $limit
264
     *
265
     * @param int|null $offset
266
     *
267
     * @return Collection
268
     */
269 9
    public function getOneToManyCollection(array $assoc, $sourceEntity, $limit = null, $offset = null)
270
    {
271 9
        $targetClass = $assoc['target'];
272
        /** @var EntityMetadata $targetMetadata */
273 9
        $targetMetadata = $this->manager->getClassMetadata($targetClass);
274
275 9
        if ($this->metadata->isIdentifierComposite) {
276
            throw new \BadMethodCallException(__METHOD__ . ' on composite reference is not supported');
277
        }
278
279
        $criteria = [
280 9
            $assoc['mappedBy'] => $sourceEntity,
281 9
        ];
282
283 9
        $orderBy = isset($assoc['orderBy']) ? $assoc['orderBy'] : [];
284
285 9
        return new ApiCollection(
286 9
            $this->manager,
287 9
            $targetMetadata,
288 9
            [$criteria, $orderBy, $limit, $offset]
289 9
        );
290
    }
291
292 4
    public function getToOneEntity(array $mapping, $sourceEntity, array $identifiers)
293
    {
294 4
        $metadata = $this->manager->getClassMetadata(get_class($sourceEntity));
295
296 4
        if (!$mapping['isOwningSide']) {
297
            $identifiers = $metadata->getIdentifierValues($sourceEntity);
298
        }
299
300 4
        return $this->manager->getReference($mapping['target'], $identifiers);
301
    }
302
}
303