Completed
Pull Request — master (#1668)
by Andreas
04:58
created

Query::getDocumentManager()   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
    /** @deprecated */
41
    const HINT_SLAVE_OKAY = 2;
42
    const HINT_READ_PREFERENCE = 3;
43
    const HINT_READ_PREFERENCE_TAGS = 4;
44
    const HINT_READ_ONLY = 5;
45
46
    /**
47
     * The DocumentManager instance.
48
     *
49
     * @var DocumentManager
50
     */
51
    private $dm;
52
53
    /**
54
     * The ClassMetadata instance.
55
     *
56
     * @var ClassMetadata
57
     */
58
    private $class;
59
60
    /**
61
     * Whether to hydrate results as document class instances.
62
     *
63
     * @var boolean
64
     */
65
    private $hydrate = true;
66
67
    /**
68
     * Array of primer Closure instances.
69
     *
70
     * @var array
71
     */
72
    private $primers = array();
73
74
    /**
75
     * Hints for UnitOfWork behavior.
76
     *
77
     * @var array
78
     */
79
    private $unitOfWorkHints = array();
80
81
    /**
82
     * Constructor.
83
     *
84
     * Please note that $requireIndexes was deprecated in 1.2 and will be removed in 2.0
85
     *
86
     * @param DocumentManager $dm
87
     * @param ClassMetadata $class
88
     * @param Collection $collection
89
     * @param array $query
90
     * @param array $options
91
     * @param boolean $hydrate
92
     * @param boolean $refresh
93
     * @param array $primers
94
     * @param boolean $readOnly
95
     */
96 178
    public function __construct(DocumentManager $dm, ClassMetadata $class, Collection $collection, array $query = array(), array $options = array(), $hydrate = true, $refresh = false, array $primers = array(), $readOnly = false)
97
    {
98 178
        $primers = array_filter($primers);
99
100 178
        if ( ! empty($primers)) {
101 23
            $query['eagerCursor'] = true;
102
        }
103
104 178
        if ( ! empty($query['eagerCursor'])) {
105 24
            $query['useIdentifierKeys'] = false;
106
        }
107
108 178
        parent::__construct($collection, $query, $options);
109 178
        $this->dm = $dm;
110 178
        $this->class = $class;
111 178
        $this->hydrate = $hydrate;
112 178
        $this->primers = $primers;
113
114 178
        $this->setReadOnly($readOnly);
115 178
        $this->setRefresh($refresh);
116
117 178
        if (isset($query['slaveOkay'])) {
118 4
            $this->unitOfWorkHints[self::HINT_SLAVE_OKAY] = $query['slaveOkay'];
0 ignored issues
show
Deprecated Code introduced by
The constant Doctrine\ODM\MongoDB\Query\Query::HINT_SLAVE_OKAY has been deprecated.

This class constant has been deprecated.

Loading history...
119
        }
120
121 178
        if (isset($query['readPreference'])) {
122 5
            $this->unitOfWorkHints[self::HINT_READ_PREFERENCE] = $query['readPreference'];
123 5
            $this->unitOfWorkHints[self::HINT_READ_PREFERENCE_TAGS] = $query['readPreferenceTags'];
124
        }
125 178
    }
126
127
    /**
128
     * Gets the DocumentManager instance.
129
     *
130
     * @return DocumentManager $dm
131
     */
132
    public function getDocumentManager()
133
    {
134
        return $this->dm;
135
    }
136
137
    /**
138
     * Gets the ClassMetadata instance.
139
     *
140
     * @return ClassMetadata $class
141
     */
142
    public function getClass()
143
    {
144
        return $this->class;
145
    }
146
147
    /**
148
     * Sets whether or not to hydrate the documents to objects.
149
     *
150
     * @param boolean $hydrate
151
     */
152
    public function setHydrate($hydrate)
153
    {
154
        $this->hydrate = (boolean) $hydrate;
155
    }
156
157
    /**
158
     * Set whether documents should be registered in UnitOfWork. If document would
159
     * already be managed it will be left intact and new instance returned.
160
     * 
161
     * This option has no effect if hydration is disabled.
162
     * 
163
     * @param boolean $readOnly
164
     */
165 178
    public function setReadOnly($readOnly)
166
    {
167 178
        $this->unitOfWorkHints[Query::HINT_READ_ONLY] = (boolean) $readOnly;
168 178
    }
169
170
    /**
171
     * Set whether to refresh hydrated documents that are already in the
172
     * identity map.
173
     *
174
     * This option has no effect if hydration is disabled.
175
     *
176
     * @param boolean $refresh
177
     */
178 178
    public function setRefresh($refresh)
179
    {
180 178
        $this->unitOfWorkHints[Query::HINT_REFRESH] = (boolean) $refresh;
181 178
    }
182
183
    /**
184
     * Execute the query and returns the results.
185
     *
186
     * @throws \Doctrine\ODM\MongoDB\MongoDBException
187
     * @return mixed
188
     */
189 148
    public function execute()
190
    {
191 148
        $results = parent::execute();
192
193 147
        if ( ! $this->hydrate) {
194 10
            return $results;
195
        }
196
197 140
        $uow = $this->dm->getUnitOfWork();
198
199
        /* A geoNear command returns an ArrayIterator, where each result is an
200
         * object with "dis" (computed distance) and "obj" (original document)
201
         * properties. If hydration is enabled, eagerly hydrate these results.
202
         *
203
         * Other commands results are not handled, since their results may not
204
         * resemble documents in the collection.
205
         */
206 140
        if ($this->query['type'] === self::TYPE_GEO_NEAR) {
207 2
            foreach ($results as $key => $result) {
208 2
                $document = $result['obj'];
209 2
                if ($this->class->distance !== null) {
210 2
                    $document[$this->class->distance] = $result['dis'];
211
                }
212 2
                $results[$key] = $uow->getOrCreateDocument($this->class->name, $document, $this->unitOfWorkHints);
213
            }
214 2
            $results->reset();
215
        }
216
217
        /* If a single document is returned from a findAndModify command and it
218
         * includes the identifier field, attempt hydration.
219
         */
220 140
        if (($this->query['type'] === self::TYPE_FIND_AND_UPDATE ||
221 140
             $this->query['type'] === self::TYPE_FIND_AND_REMOVE) &&
222 140
            is_array($results) && isset($results['_id'])) {
223
224 5
            $results = $uow->getOrCreateDocument($this->class->name, $results, $this->unitOfWorkHints);
225
226 5
            if ( ! empty($this->primers)) {
227 1
                $referencePrimer = new ReferencePrimer($this->dm, $uow);
228
229 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...
230 1
                    $primer = is_callable($primer) ? $primer : null;
231 1
                    $referencePrimer->primeReferences($this->class, array($results), $fieldName, $this->unitOfWorkHints, $primer);
232
                }
233
            }
234
        }
235
236 140
        return $results;
237
    }
238
239
    /**
240
     * Prepare the Cursor returned by {@link Query::execute()}.
241
     *
242
     * This method will wrap the base Cursor with an ODM Cursor or EagerCursor,
243
     * and set the hydrate option and UnitOfWork hints. This occurs in addition
244
     * to any preparation done by the base Query class.
245
     *
246
     * @see \Doctrine\MongoDB\Cursor::prepareCursor()
247
     * @param BaseCursor $cursor
248
     * @return CursorInterface
249
     */
250 132
    protected function prepareCursor(BaseCursor $cursor)
251
    {
252 132
        $cursor = parent::prepareCursor($cursor);
253
254
        // Convert the base Cursor into an ODM Cursor
255 132
        $cursorClass = ( ! empty($this->query['eagerCursor'])) ? EagerCursor::class : Cursor::class;
256 132
        $cursor = new $cursorClass($cursor, $this->dm->getUnitOfWork(), $this->class);
257
258 132
        $cursor->hydrate($this->hydrate);
259 132
        $cursor->setHints($this->unitOfWorkHints);
260
261 132
        if ( ! empty($this->primers)) {
262 21
            $referencePrimer = new ReferencePrimer($this->dm, $this->dm->getUnitOfWork());
263 21
            $cursor->enableReferencePriming($this->primers, $referencePrimer);
264
        }
265
266 132
        return $cursor;
267
    }
268
}
269