Completed
Pull Request — master (#1448)
by Andreas
10:20
created

Query::getClass()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
ccs 0
cts 2
cp 0
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 2
1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace Doctrine\ODM\MongoDB\Query;
21
22
use Doctrine\MongoDB\Collection;
23
use Doctrine\MongoDB\Cursor as BaseCursor;
24
use Doctrine\MongoDB\CursorInterface;
25
use Doctrine\ODM\MongoDB\Cursor;
26
use Doctrine\ODM\MongoDB\DocumentManager;
27
use Doctrine\ODM\MongoDB\EagerCursor;
28
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
29
use Doctrine\ODM\MongoDB\MongoDBException;
30
31
/**
32
 * ODM Query wraps the raw Doctrine MongoDB queries to add additional functionality
33
 * and to hydrate the raw arrays of data to Doctrine document objects.
34
 *
35
 * @since       1.0
36
 */
37
class Query extends \Doctrine\MongoDB\Query\Query
38
{
39
    const HINT_REFRESH = 1;
40
    const HINT_SLAVE_OKAY = 2;
41
    const HINT_READ_PREFERENCE = 3;
42
    const HINT_READ_PREFERENCE_TAGS = 4;
43
    const HINT_READ_ONLY = 5;
44
45
    /**
46
     * The DocumentManager instance.
47
     *
48
     * @var DocumentManager
49
     */
50
    private $dm;
51
52
    /**
53
     * The ClassMetadata instance.
54
     *
55
     * @var ClassMetadata
56
     */
57
    private $class;
58
59
    /**
60
     * Whether to hydrate results as document class instances.
61
     *
62
     * @var boolean
63
     */
64
    private $hydrate = true;
65
66
    /**
67
     * Array of primer Closure instances.
68
     *
69
     * @var array
70
     */
71
    private $primers = array();
72
73
    /**
74
     * Whether or not to require indexes.
75
     *
76
     * @var boolean
77
     */
78
    private $requireIndexes;
79
80
    /**
81
     * Hints for UnitOfWork behavior.
82
     *
83
     * @var array
84
     */
85
    private $unitOfWorkHints = array();
86
87
    /**
88
     * Constructor.
89
     *
90
     * Please note that $requireIndexes was deprecated in 1.2 and will be removed in 2.0
91
     *
92
     * @param DocumentManager $dm
93
     * @param ClassMetadata $class
94
     * @param Collection $collection
95
     * @param array $query
96
     * @param array $options
97
     * @param boolean $hydrate
98
     * @param boolean $refresh
99
     * @param array $primers
100
     * @param null $requireIndexes deprecated
101
     * @param boolean $readOnly
102
     */
103 191
    public function __construct(DocumentManager $dm, ClassMetadata $class, Collection $collection, array $query = array(), array $options = array(), $hydrate = true, $refresh = false, array $primers = array(), $requireIndexes = null, $readOnly = false)
104
    {
105 191
        $primers = array_filter($primers);
106
107 191
        if ( ! empty($primers)) {
108 19
            $query['eagerCursor'] = true;
109
        }
110
111 191
        if ( ! empty($query['eagerCursor'])) {
112 19
            $query['useIdentifierKeys'] = false;
113
        }
114
115 191
        parent::__construct($collection, $query, $options);
116 191
        $this->dm = $dm;
117 191
        $this->class = $class;
118 191
        $this->hydrate = $hydrate;
119 191
        $this->primers = $primers;
120 191
        $this->requireIndexes = $requireIndexes;
121
122 191
        $this->setReadOnly($readOnly);
123 191
        $this->setRefresh($refresh);
124
125 191
        if (isset($query['slaveOkay'])) {
126 4
            $this->unitOfWorkHints[self::HINT_SLAVE_OKAY] = $query['slaveOkay'];
127
        }
128
129 191
        if (isset($query['readPreference'])) {
130 3
            $this->unitOfWorkHints[self::HINT_READ_PREFERENCE] = $query['readPreference'];
131 3
            $this->unitOfWorkHints[self::HINT_READ_PREFERENCE_TAGS] = $query['readPreferenceTags'];
132
        }
133 191
    }
134
135
    /**
136
     * Gets the DocumentManager instance.
137
     *
138
     * @return DocumentManager $dm
139
     */
140
    public function getDocumentManager()
141
    {
142
        return $this->dm;
143
    }
144
145
    /**
146
     * Gets the ClassMetadata instance.
147
     *
148
     * @return ClassMetadata $class
149
     */
150
    public function getClass()
151
    {
152
        return $this->class;
153
    }
154
155
    /**
156
     * Sets whether or not to hydrate the documents to objects.
157
     *
158
     * @param boolean $hydrate
159
     */
160
    public function setHydrate($hydrate)
161
    {
162
        $this->hydrate = (boolean) $hydrate;
163
    }
164
165
    /**
166
     * Set whether documents should be registered in UnitOfWork. If document would
167
     * already be managed it will be left intact and new instance returned.
168
     * 
169
     * This option has no effect if hydration is disabled.
170
     * 
171
     * @param boolean $readOnly
172
     */
173 191
    public function setReadOnly($readOnly)
174
    {
175 191
        $this->unitOfWorkHints[Query::HINT_READ_ONLY] = (boolean) $readOnly;
176 191
    }
177
178
    /**
179
     * Set whether to refresh hydrated documents that are already in the
180
     * identity map.
181
     *
182
     * This option has no effect if hydration is disabled.
183
     *
184
     * @param boolean $refresh
185
     */
186 191
    public function setRefresh($refresh)
187
    {
188 191
        $this->unitOfWorkHints[Query::HINT_REFRESH] = (boolean) $refresh;
189 191
    }
190
191
    /**
192
     * Gets the fields involved in this query.
193
     *
194
     * @return array $fields An array of fields names used in this query.
195
     *
196
     * @deprecated method was deprecated in 1.2 and will be removed in 2.0
197
     */
198 22
    public function getFieldsInQuery()
199
    {
200 22
        $query = isset($this->query['query']) ? $this->query['query'] : array();
201 22
        $sort = isset($this->query['sort']) ? $this->query['sort'] : array();
202
203 22
        $extractor = new FieldExtractor($query, $sort);
0 ignored issues
show
Deprecated Code introduced by
The class Doctrine\ODM\MongoDB\Query\FieldExtractor has been deprecated with message: class was deprecated in 1.2 and will be removed in 2.0

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...
204 22
        return $extractor->getFields();
205
    }
206
207
    /**
208
     * Check if this query is indexed.
209
     *
210
     * @return bool
211
     *
212
     * @deprecated method was deprecated in 1.2 and will be removed in 2.0
213
     */
214 8
    public function isIndexed()
215
    {
216 8
        $fields = $this->getFieldsInQuery();
0 ignored issues
show
Deprecated Code introduced by
The method Doctrine\ODM\MongoDB\Que...ery::getFieldsInQuery() has been deprecated with message: method was deprecated in 1.2 and will be removed in 2.0

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...
217 8
        foreach ($fields as $field) {
218 8
            if ( ! $this->collection->isFieldIndexed($field)) {
219 8
                return false;
220
            }
221
        }
222 2
        return true;
223
    }
224
225
    /**
226
     * Gets an array of the unindexed fields in this query.
227
     *
228
     * @return array
229
     *
230
     * @deprecated method was deprecated in 1.2 and will be removed in 2.0
231
     */
232 6
    public function getUnindexedFields()
233
    {
234 6
        $unindexedFields = array();
235 6
        $fields = $this->getFieldsInQuery();
0 ignored issues
show
Deprecated Code introduced by
The method Doctrine\ODM\MongoDB\Que...ery::getFieldsInQuery() has been deprecated with message: method was deprecated in 1.2 and will be removed in 2.0

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 6
        foreach ($fields as $field) {
237 6
            if ( ! $this->collection->isFieldIndexed($field)) {
238 6
                $unindexedFields[] = $field;
239
            }
240
        }
241 6
        return $unindexedFields;
242
    }
243
244
    /**
245
     * Execute the query and returns the results.
246
     *
247
     * @throws \Doctrine\ODM\MongoDB\MongoDBException
248
     * @return mixed
249
     */
250 151
    public function execute()
251
    {
252 151
        if ($this->isIndexRequired() && ! $this->isIndexed()) {
0 ignored issues
show
Deprecated Code introduced by
The method Doctrine\ODM\MongoDB\Query\Query::isIndexed() has been deprecated with message: method was deprecated in 1.2 and will be removed in 2.0

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...
253 5
            throw MongoDBException::queryNotIndexed($this->class->name, $this->getUnindexedFields());
0 ignored issues
show
Documentation introduced by
$this->getUnindexedFields() is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Deprecated Code introduced by
The method Doctrine\ODM\MongoDB\Que...y::getUnindexedFields() has been deprecated with message: method was deprecated in 1.2 and will be removed in 2.0

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...
Deprecated Code introduced by
The method Doctrine\ODM\MongoDB\Mon...tion::queryNotIndexed() has been deprecated with message: method was deprecated in 1.2 and will be removed in 2.0

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...
254
        }
255
256 146
        $results = parent::execute();
257
258 145
        if ( ! $this->hydrate) {
259 10
            return $results;
260
        }
261
262 138
        $uow = $this->dm->getUnitOfWork();
263
264
        /* A geoNear command returns an ArrayIterator, where each result is an
265
         * object with "dis" (computed distance) and "obj" (original document)
266
         * properties. If hydration is enabled, eagerly hydrate these results.
267
         *
268
         * Other commands results are not handled, since their results may not
269
         * resemble documents in the collection.
270
         */
271 138
        if ($this->query['type'] === self::TYPE_GEO_NEAR) {
272 2
            foreach ($results as $key => $result) {
273 2
                $document = $result['obj'];
274 2
                if ($this->class->distance !== null) {
275 2
                    $document[$this->class->distance] = $result['dis'];
276
                }
277 2
                $results[$key] = $uow->getOrCreateDocument($this->class->name, $document, $this->unitOfWorkHints);
278
            }
279 2
            $results->reset();
280
        }
281
282
        /* If a single document is returned from a findAndModify command and it
283
         * includes the identifier field, attempt hydration.
284
         */
285 138
        if (($this->query['type'] === self::TYPE_FIND_AND_UPDATE ||
286 138
             $this->query['type'] === self::TYPE_FIND_AND_REMOVE) &&
287 138
            is_array($results) && isset($results['_id'])) {
288
289 5
            $results = $uow->getOrCreateDocument($this->class->name, $results, $this->unitOfWorkHints);
290
291 5
            if ( ! empty($this->primers)) {
292 1
                $referencePrimer = new ReferencePrimer($this->dm, $uow);
293
294 1 View Code Duplication
                foreach ($this->primers as $fieldName => $primer) {
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...
295 1
                    $primer = is_callable($primer) ? $primer : null;
296 1
                    $referencePrimer->primeReferences($this->class, array($results), $fieldName, $this->unitOfWorkHints, $primer);
297
                }
298
            }
299
        }
300
301 138
        return $results;
302
    }
303
304
    /**
305
     * Prepare the Cursor returned by {@link Query::execute()}.
306
     *
307
     * This method will wrap the base Cursor with an ODM Cursor or EagerCursor,
308
     * and set the hydrate option and UnitOfWork hints. This occurs in addition
309
     * to any preparation done by the base Query class.
310
     *
311
     * @see \Doctrine\MongoDB\Cursor::prepareCursor()
312
     * @param BaseCursor $cursor
313
     * @return CursorInterface
314
     */
315 130
    protected function prepareCursor(BaseCursor $cursor)
316
    {
317 130
        $cursor = parent::prepareCursor($cursor);
318
319
        // Convert the base Cursor into an ODM Cursor
320 130
        $cursorClass = ( ! empty($this->query['eagerCursor'])) ? EagerCursor::class : Cursor::class;
321 130
        $cursor = new $cursorClass($cursor, $this->dm->getUnitOfWork(), $this->class);
322
323 130
        $cursor->hydrate($this->hydrate);
324 130
        $cursor->setHints($this->unitOfWorkHints);
325
326 130
        if ( ! empty($this->primers)) {
327 17
            $referencePrimer = new ReferencePrimer($this->dm, $this->dm->getUnitOfWork());
328 17
            $cursor->enableReferencePriming($this->primers, $referencePrimer);
329
        }
330
331 130
        return $cursor;
332
    }
333
334
    /**
335
     * Return whether queries on this document should require indexes.
336
     *
337
     * @return boolean
338
     */
339 151
    private function isIndexRequired()
340
    {
341 151
        return $this->requireIndexes !== null ? $this->requireIndexes : $this->class->requireIndexes;
0 ignored issues
show
Deprecated Code introduced by
The property Doctrine\ODM\MongoDB\Map...taInfo::$requireIndexes has been deprecated with message: property was deprecated in 1.2 and will be removed in 2.0

This property 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 property will be removed from the class and what other property to use instead.

Loading history...
342
    }
343
}
344