Completed
Pull Request — master (#5)
by Jacob
02:31
created

Persister::getRetrieveCritiera()   B

Complexity

Conditions 5
Paths 8

Size

Total Lines 17
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 17
rs 8.8571
cc 5
eloc 11
nc 8
nop 2
1
<?php
2
3
namespace As3\Modlr\Persister\MongoDb;
4
5
use As3\Modlr\Store\Store;
6
use As3\Modlr\Models\Model;
7
use As3\Modlr\Models\Collection;
8
use As3\Modlr\Metadata\EntityMetadata;
9
use As3\Modlr\Metadata\AttributeMetadata;
10
use As3\Modlr\Metadata\RelationshipMetadata;
11
use As3\Modlr\Persister\PersisterInterface;
12
use As3\Modlr\Persister\PersisterException;
13
use As3\Modlr\Persister\Record;
14
use Doctrine\MongoDB\Connection;
15
use \MongoId;
16
17
/**
18
 * Persists and retrieves models to/from a MongoDB database.
19
 *
20
 * @author Jacob Bare <[email protected]>
21
 */
22
final class Persister implements PersisterInterface
23
{
24
    const IDENTIFIER_KEY    = '_id';
25
    const POLYMORPHIC_KEY   = '_type';
26
    const PERSISTER_KEY     = 'mongodb';
27
28
    /**
29
     * The Doctine MongoDB connection.
30
     *
31
     * @var Connection
32
     */
33
    private $connection;
34
35
    /**
36
     * The query/database operations formatter.
37
     *
38
     * @var Formatter
39
     */
40
    private $formatter;
41
42
    /**
43
     * The raw result hydrator.
44
     *
45
     * @var Hydrator
46
     */
47
    private $hydrator;
48
49
    /**
50
     * @var StorageMetadataFactory
51
     */
52
    private $smf;
53
54
    /**
55
     * Constructor.
56
     *
57
     * @param   Connection              $connection
58
     * @param   StorageMetadataFactory  $smf
59
     */
60
    public function __construct(Connection $connection, StorageMetadataFactory $smf)
61
    {
62
        $this->connection = $connection;
63
        $this->formatter = new Formatter();
64
        $this->hydrator = new Hydrator();
65
        $this->smf = $smf;
66
67
    }
68
69
    /**
70
     * {@inheritDoc}
71
     */
72
    public function getPersisterKey()
73
    {
74
        return self::PERSISTER_KEY;
75
    }
76
77
    /**
78
     * {@inheritDoc}
79
     */
80
    public function getPersistenceMetadataFactory()
81
    {
82
        return $this->smf;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->smf; (As3\Modlr\Persister\MongoDb\StorageMetadataFactory) is incompatible with the return type declared by the interface As3\Modlr\Persister\Pers...sistenceMetadataFactory of type As3\Modlr\Metadata\Inter...etadataFactoryInterface.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
83
    }
84
85
    /**
86
     * {@inheritDoc}
87
     * @todo    Implement sorting and pagination (limit/skip).
88
     */
89
    public function all(EntityMetadata $metadata, Store $store, array $identifiers = [])
90
    {
91
        $criteria = $this->getRetrieveCritiera($metadata, $identifiers);
92
        $cursor = $this->doQuery($metadata, $store, $criteria);
93
        return $this->getHydrator()->hydrateMany($metadata, $cursor->toArray(), $store);
94
    }
95
96
    /**
97
     * {@inheritDoc}
98
     */
99
    public function query(EntityMetadata $metadata, Store $store, array $criteria, array $fields = [], array $sort = [], $offset = 0, $limit = 0)
100
    {
101
        $cursor = $this->doQuery($metadata, $store, $criteria);
102
        return $this->getHydrator()->hydrateMany($metadata, $cursor->toArray(), $store);
103
    }
104
105
    /**
106
     * {@inheritDoc}
107
     */
108
    public function inverse(EntityMetadata $owner, EntityMetadata $rel, Store $store, array $identifiers, $inverseField)
109
    {
110
        $criteria = $this->getInverseCriteria($owner, $rel, $identifiers, $inverseField);
111
        $cursor = $this->doQuery($rel, $store, $criteria);
112
        return $this->getHydrator()->hydrateMany($rel, $cursor->toArray(), $store);
113
    }
114
115
    /**
116
     * {@inheritDoc}
117
     */
118
    public function retrieve(EntityMetadata $metadata, $identifier, Store $store)
119
    {
120
        $criteria = $this->getRetrieveCritiera($metadata, $identifier);
121
        $result = $this->doQuery($metadata, $store, $criteria)->getSingleResult();
122
        if (null === $result) {
123
            return;
124
        }
125
        return $this->getHydrator()->hydrateOne($metadata, $result, $store);
0 ignored issues
show
Bug introduced by
It seems like $result defined by $this->doQuery($metadata...ria)->getSingleResult() on line 121 can also be of type object; however, As3\Modlr\Persister\MongoDb\Hydrator::hydrateOne() does only seem to accept array, 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...
126
    }
127
128
    /**
129
     * {@inheritDoc}
130
     * @todo    Optimize the changeset to query generation.
131
     */
132
    public function create(Model $model)
133
    {
134
        $metadata = $model->getMetadata();
135
        $insert[$this->getIdentifierKey()] = $this->convertId($model->getId());
0 ignored issues
show
Coding Style Comprehensibility introduced by
$insert was never initialized. Although not strictly required by PHP, it is generally a good practice to add $insert = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
136
        if (true === $metadata->isChildEntity()) {
137
            $insert[$this->getPolymorphicKey()] = $metadata->type;
138
        }
139
140
        $changeset = $model->getChangeSet();
141 View Code Duplication
        foreach ($changeset['attributes'] as $key => $values) {
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...
142
            $value = $this->getFormatter()->getAttributeDbValue($metadata->getAttribute($key), $values['new']);
0 ignored issues
show
Bug introduced by
It seems like $metadata->getAttribute($key) can be null; however, getAttributeDbValue() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
143
            if (null === $value) {
144
                continue;
145
            }
146
            $insert[$key] = $value;
147
        }
148 View Code Duplication
        foreach ($changeset['hasOne'] as $key => $values) {
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...
149
            $value = $this->getFormatter()->getHasOneDbValue($metadata->getRelationship($key), $values['new']);
0 ignored issues
show
Bug introduced by
It seems like $metadata->getRelationship($key) can be null; however, getHasOneDbValue() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
150
            if (null === $value) {
151
                continue;
152
            }
153
            $insert[$key] = $value;
154
        }
155 View Code Duplication
        foreach ($changeset['hasMany'] as $key => $values) {
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...
156
            $value = $this->getFormatter()->getHasManyDbValue($metadata->getRelationship($key), $values['new']);
0 ignored issues
show
Bug introduced by
It seems like $metadata->getRelationship($key) can be null; however, getHasManyDbValue() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
157
            if (null === $value) {
158
                continue;
159
            }
160
            $insert[$key] = $value;
161
        }
162
        $this->createQueryBuilder($metadata)
163
            ->insert()
164
            ->setNewObj($insert)
165
            ->getQuery()
166
            ->execute()
167
        ;
168
        return $model;
169
    }
170
171
    /**
172
     * {@inheritDoc}
173
     * @todo    Optimize the changeset to query generation.
174
     */
175
    public function update(Model $model)
176
    {
177
        $metadata = $model->getMetadata();
178
        $criteria = $this->getRetrieveCritiera($metadata, $model->getId());
179
        $changeset = $model->getChangeSet();
180
181
        $update = [];
182 View Code Duplication
        foreach ($changeset['attributes'] as $key => $values) {
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...
183
            if (null === $values['new']) {
184
                $op = '$unset';
185
                $value = 1;
186
            } else {
187
                $op = '$set';
188
                $value = $this->getFormatter()->getAttributeDbValue($metadata->getAttribute($key), $values['new']);
0 ignored issues
show
Bug introduced by
It seems like $metadata->getAttribute($key) can be null; however, getAttributeDbValue() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
189
            }
190
            $update[$op][$key] = $value;
191
        }
192
193
        // @todo Must prevent inverse relationships from persisting
194 View Code Duplication
        foreach ($changeset['hasOne'] as $key => $values) {
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...
195
            if (null === $values['new']) {
196
                $op = '$unset';
197
                $value = 1;
198
            } else {
199
                $op = '$set';
200
                $value = $this->getFormatter()->getHasOneDbValue($metadata->getRelationship($key), $values['new']);
0 ignored issues
show
Bug introduced by
It seems like $metadata->getRelationship($key) can be null; however, getHasOneDbValue() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
201
            }
202
            $update[$op][$key] = $value;
203
        }
204
205 View Code Duplication
        foreach ($changeset['hasMany'] as $key => $values) {
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...
206
            if (null === $values['new']) {
207
                $op = '$unset';
208
                $value = 1;
209
            } else {
210
                $op = '$set';
211
                $value = $this->getFormatter()->getHasManyDbValue($metadata->getRelationship($key), $values['new']);
0 ignored issues
show
Bug introduced by
It seems like $metadata->getRelationship($key) can be null; however, getHasManyDbValue() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
212
            }
213
            $update[$op][$key] = $value;
214
        }
215
216
        if (empty($update)) {
217
            return $model;
218
        }
219
220
        $this->createQueryBuilder($metadata)
221
            ->update()
222
            ->setQueryArray($criteria)
223
            ->setNewObj($update)
224
            ->getQuery()
225
            ->execute();
226
        ;
227
        return $model;
228
    }
229
230
    /**
231
     * {@inheritDoc}
232
     */
233
    public function delete(Model $model)
234
    {
235
        $metadata = $model->getMetadata();
236
        $criteria = $this->getRetrieveCritiera($metadata, $model->getId());
237
238
        $this->createQueryBuilder($metadata)
239
            ->remove()
240
            ->setQueryArray($criteria)
241
            ->getQuery()
242
            ->execute();
243
        ;
244
        return $model;
245
    }
246
247
    /**
248
     * {@inheritDoc}
249
     */
250
    public function generateId($strategy = null)
251
    {
252
        if (false === $this->getFormatter()->isIdStrategySupported($strategy)) {
253
            throw PersisterException::nyi('ID generation currently only supports an object strategy, or none at all.');
254
        }
255
        return new MongoId();
256
    }
257
258
    /**
259
     * @return  Formatter
260
     */
261
    public function getFormatter()
262
    {
263
        return $this->formatter;
264
    }
265
266
    /**
267
     * @return  Hydrator
268
     */
269
    public function getHydrator()
270
    {
271
        return $this->hydrator;
272
    }
273
274
    /**
275
     * {@inheritDoc}
276
     */
277
    public function convertId($identifier, $strategy = null)
278
    {
279
        return $this->getFormatter()->getIdentifierDbValue($identifier, $strategy);
280
    }
281
282
    /**
283
     * {@inheritDoc}
284
     */
285
    public function getIdentifierKey()
286
    {
287
        return self::IDENTIFIER_KEY;
288
    }
289
290
    /**
291
     * {@inheritDoc}
292
     */
293
    public function getPolymorphicKey()
294
    {
295
        return self::POLYMORPHIC_KEY;
296
    }
297
298
    /**
299
     * {@inheritDoc}
300
     */
301
    public function extractType(EntityMetadata $metadata, array $data)
302
    {
303
        return $this->getHydrator()->extractType($metadata, $data);
304
    }
305
306
    /**
307
     * Finds records from the database based on the provided metadata and criteria.
308
     *
309
     * @param   EntityMetadata  $metadata   The model metadata that the database should query against.
310
     * @param   Store           $store      The store.
311
     * @param   array           $criteria   The query criteria.
312
     * @param   array           $fields     Fields to include/exclude.
313
     * @param   array           $sort       The sort criteria.
314
     * @param   int             $offset     The starting offset, aka the number of Models to skip.
315
     * @param   int             $limit      The number of Models to limit.
316
     * @return  \Doctrine\MongoDB\Cursor
317
     */
318
    protected function doQuery(EntityMetadata $metadata, Store $store, array $criteria, array $fields = [], array $sort = [], $offset = 0, $limit = 0)
0 ignored issues
show
Unused Code introduced by
The parameter $fields is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $sort is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $offset is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $limit is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
319
    {
320
        $criteria = $this->getFormatter()->formatQuery($metadata, $store, $criteria);
321
        return $this->createQueryBuilder($metadata)
322
            ->find()
323
            ->setQueryArray($criteria)
324
            ->getQuery()
325
            ->execute()
326
        ;
327
    }
328
329
    /**
330
     * Gets standard database retrieval criteria for an inverse relationship.
331
     *
332
     * @param   EntityMetadata  $metadata       The entity to retrieve database records for.
0 ignored issues
show
Bug introduced by
There is no parameter named $metadata. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
333
     * @param   string|array    $identifiers    The IDs to query.
334
     * @return  array
335
     */
336
    protected function getInverseCriteria(EntityMetadata $owner, EntityMetadata $related, $identifiers, $inverseField)
337
    {
338
        $criteria[$inverseField] = (array) $identifiers;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$criteria was never initialized. Although not strictly required by PHP, it is generally a good practice to add $criteria = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
339
        if (true === $owner->isChildEntity()) {
340
            // The owner is owned by a polymorphic model. Must include the type with the inverse field criteria.
341
            $criteria[$inverseField] = [
342
                $this->getIdentifierKey()   => $criteria[$inverseField],
343
                $this->getPolymorphicKey()  => $owner->type,
344
            ];
345
        }
346
        if (true === $related->isChildEntity()) {
347
            // The relationship is owned by a polymorphic model. Must include the type in the root criteria.
348
            $criteria[$this->getPolymorphicKey()] = $related->type;
349
        }
350
        return $criteria;
351
    }
352
353
    /**
354
     * Gets standard database retrieval criteria for an entity and the provided identifiers.
355
     *
356
     * @param   EntityMetadata      $metadata       The entity to retrieve database records for.
357
     * @param   string|array|null   $identifiers    The IDs to query.
358
     * @return  array
359
     */
360
    protected function getRetrieveCritiera(EntityMetadata $metadata, $identifiers = null)
361
    {
362
        $criteria = [];
363
        if (true === $metadata->isChildEntity()) {
364
            $criteria[$this->getPolymorphicKey()] = $metadata->type;
365
        }
366
367
        if (null === $identifiers) {
368
            return $criteria;
369
        }
370
        $identifiers = (array) $identifiers;
371
        if (empty($identifiers)) {
372
            return $criteria;
373
        }
374
        $criteria[$this->getIdentifierKey()] = (1 === count($identifiers)) ? $identifiers[0] : $identifiers;
375
        return $criteria;
376
    }
377
378
    /**
379
     * Creates a builder object for querying MongoDB based on the provided metadata.
380
     *
381
     * @param   EntityMetadata  $metadata
382
     * @return  \Doctrine\MongoDB\Query\Builder
383
     */
384
    protected function createQueryBuilder(EntityMetadata $metadata)
385
    {
386
        return $this->getModelCollection($metadata)->createQueryBuilder();
387
    }
388
389
    /**
390
     * Gets the MongoDB Collection object for a Model.
391
     *
392
     * @param   EntityMetadata  $metadata
393
     * @return  \Doctrine\MongoDB\Collection
394
     */
395
    protected function getModelCollection(EntityMetadata $metadata)
396
    {
397
        return $this->connection->selectCollection($metadata->persistence->db, $metadata->persistence->collection);
0 ignored issues
show
Bug introduced by
Accessing db on the interface As3\Modlr\Metadata\Inter...s\StorageLayerInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
Bug introduced by
Accessing collection on the interface As3\Modlr\Metadata\Inter...s\StorageLayerInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
398
    }
399
}
400