Completed
Pull Request — 4.3 (#149)
by Dorian
13:16
created

InnerResultIterator::next()   D

Complexity

Conditions 12
Paths 149

Size

Total Lines 76
Code Lines 37

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 76
rs 4.8998
c 0
b 0
f 0
cc 12
eloc 37
nc 149
nop 0

How to fix   Long Method    Complexity   

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 Mouf\Database\TDBM;
4
5
use Doctrine\DBAL\Statement;
6
use Mouf\Database\MagicQuery;
7
use Psr\Log\LoggerInterface;
8
9
/*
10
 Copyright (C) 2006-2016 David Négrier - THE CODING MACHINE
11
12
 This program is free software; you can redistribute it and/or modify
13
 it under the terms of the GNU General Public License as published by
14
 the Free Software Foundation; either version 2 of the License, or
15
 (at your option) any later version.
16
17
 This program is distributed in the hope that it will be useful,
18
 but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 GNU General Public License for more details.
21
22
 You should have received a copy of the GNU General Public License
23
 along with this program; if not, write to the Free Software
24
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
25
 */
26
27
/**
28
 * Iterator used to retrieve results.
29
 */
30
class InnerResultIterator implements \Iterator, \Countable, \ArrayAccess
31
{
32
    /**
33
     * @var Statement
34
     */
35
    protected $statement;
36
37
    protected $fetchStarted = false;
38
    private $objectStorage;
39
    private $className;
40
41
    private $tdbmService;
42
    private $magicSql;
43
    private $parameters;
44
    private $limit;
45
    private $offset;
46
    private $columnDescriptors;
47
    private $magicQuery;
48
49
    /**
50
     * The key of the current retrieved object.
51
     *
52
     * @var int
53
     */
54
    protected $key = -1;
55
56
    protected $current = null;
57
58
    private $databasePlatform;
59
60
    /**
61
     * @var LoggerInterface
62
     */
63
    private $logger;
64
65
    public function __construct($magicSql, array $parameters, $limit, $offset, array $columnDescriptors, $objectStorage, $className, TDBMService $tdbmService, MagicQuery $magicQuery, LoggerInterface $logger)
66
    {
67
        $this->magicSql = $magicSql;
68
        $this->objectStorage = $objectStorage;
69
        $this->className = $className;
70
        $this->tdbmService = $tdbmService;
71
        $this->parameters = $parameters;
72
        $this->limit = $limit;
73
        $this->offset = $offset;
74
        $this->columnDescriptors = $columnDescriptors;
75
        $this->magicQuery = $magicQuery;
76
        $this->databasePlatform = $this->tdbmService->getConnection()->getDatabasePlatform();
77
        $this->logger = $logger;
78
    }
79
80
    protected function executeQuery()
81
    {
82
        $sql = $this->magicQuery->build($this->magicSql, $this->parameters);
83
        $sql = $this->tdbmService->getConnection()->getDatabasePlatform()->modifyLimitQuery($sql, $this->limit, $this->offset);
84
85
        $this->logger->debug('Running SQL request: '.$sql);
86
87
        $this->statement = $this->tdbmService->getConnection()->executeQuery($sql, $this->parameters);
88
89
        $this->fetchStarted = true;
90
    }
91
92
    /**
93
     * Counts found records (this is the number of records fetched, taking into account the LIMIT and OFFSET settings).
94
     *
95
     * @return int
96
     */
97
    public function count()
98
    {
99
        if (!$this->fetchStarted) {
100
            $this->executeQuery();
101
        }
102
103
        return $this->statement->rowCount();
104
    }
105
106
    /**
107
     * Fetches record at current cursor.
108
     *
109
     * @return AbstractTDBMObject|null
110
     */
111
    public function current()
112
    {
113
        return $this->current;
114
    }
115
116
    /**
117
     * Returns the current result's key.
118
     *
119
     * @return int
120
     */
121
    public function key()
122
    {
123
        return $this->key;
124
    }
125
126
    /**
127
     * Advances the cursor to the next result.
128
     * Casts the database result into one (or several) beans.
129
     */
130
    public function next()
131
    {
132
        $row = $this->statement->fetch(\PDO::FETCH_LAZY);
133
        if ($row) {
134
135
            // array<tablegroup, array<table, array<column, value>>>
0 ignored issues
show
Unused Code Comprehensibility introduced by
37% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
136
            $beansData = [];
137
            foreach ($row as $key => $value) {
138
                if (!isset($this->columnDescriptors[$key])) {
139
                    continue;
140
                }
141
142
                $columnDescriptor = $this->columnDescriptors[$key];
143
144
                if ($columnDescriptor['tableGroup'] === null) {
145
                    // A column can have no tableGroup (if it comes from an ORDER BY expression)
146
                    continue;
147
                }
148
149
                // Let's cast the value according to its type
150
                $value = $columnDescriptor['type']->convertToPHPValue($value, $this->databasePlatform);
151
152
                $beansData[$columnDescriptor['tableGroup']][$columnDescriptor['table']][$columnDescriptor['column']] = $value;
153
            }
154
155
            $reflectionClassCache = [];
156
            $firstBean = true;
157
            foreach ($beansData as $beanData) {
158
159
                // Let's find the bean class name associated to the bean.
160
161
                list($actualClassName, $mainBeanTableName, $tablesUsed) = $this->tdbmService->_getClassNameFromBeanData($beanData);
162
163
                if ($this->className !== null) {
164
                    $actualClassName = $this->className;
165
                }
166
167
                // Let's filter out the beanData that is not used (because it belongs to a part of the hierarchy that is not fetched:
168
                foreach ($beanData as $tableName => $descriptors) {
169
                    if (!in_array($tableName, $tablesUsed)) {
170
                        unset($beanData[$tableName]);
171
                    }
172
                }
173
174
                // Must we create the bean? Let's see in the cache if we have a mapping DbRow?
175
                // Let's get the first object mapping a row:
176
                // We do this loop only for the first table
177
178
                $primaryKeys = $this->tdbmService->_getPrimaryKeysFromObjectData($mainBeanTableName, $beanData[$mainBeanTableName]);
179
                $hash = $this->tdbmService->getObjectHash($primaryKeys);
180
181
                if ($this->objectStorage->has($mainBeanTableName, $hash)) {
182
                    $dbRow = $this->objectStorage->get($mainBeanTableName, $hash);
183
                    $bean = $dbRow->getTDBMObject();
184
                } else {
185
                    // Let's construct the bean
186
                    if (!isset($reflectionClassCache[$actualClassName])) {
187
                        $reflectionClassCache[$actualClassName] = new \ReflectionClass($actualClassName);
188
                    }
189
                    // Let's bypass the constructor when creating the bean!
190
                    $bean = $reflectionClassCache[$actualClassName]->newInstanceWithoutConstructor();
191
                    $bean->_constructFromData($beanData, $this->tdbmService);
192
                }
193
194
                // The first bean is the one containing the main table.
195
                if ($firstBean) {
196
                    $firstBean = false;
197
                    $this->current = $bean;
198
                }
199
            }
200
201
            ++$this->key;
202
        } else {
203
            $this->current = null;
204
        }
205
    }
206
207
    /**
208
     * Moves the cursor to the beginning of the result set.
209
     */
210
    public function rewind()
211
    {
212
        $this->executeQuery();
213
        $this->key = -1;
214
        $this->next();
215
    }
216
    /**
217
     * Checks if the cursor is reading a valid result.
218
     *
219
     * @return bool
220
     */
221
    public function valid()
222
    {
223
        return $this->current !== null;
224
    }
225
226
    /**
227
     * Whether a offset exists.
228
     *
229
     * @link http://php.net/manual/en/arrayaccess.offsetexists.php
230
     *
231
     * @param mixed $offset <p>
232
     *                      An offset to check for.
233
     *                      </p>
234
     *
235
     * @return bool true on success or false on failure.
236
     *              </p>
237
     *              <p>
238
     *              The return value will be casted to boolean if non-boolean was returned
239
     *
240
     * @since 5.0.0
241
     */
242
    public function offsetExists($offset)
243
    {
244
        throw new TDBMInvalidOperationException('You cannot access this result set via index because it was fetched in CURSOR mode. Use ARRAY_MODE instead.');
245
    }
246
247
    /**
248
     * Offset to retrieve.
249
     *
250
     * @link http://php.net/manual/en/arrayaccess.offsetget.php
251
     *
252
     * @param mixed $offset <p>
253
     *                      The offset to retrieve.
254
     *                      </p>
255
     *
256
     * @return mixed Can return all value types
257
     *
258
     * @since 5.0.0
259
     */
260
    public function offsetGet($offset)
261
    {
262
        throw new TDBMInvalidOperationException('You cannot access this result set via index because it was fetched in CURSOR mode. Use ARRAY_MODE instead.');
263
    }
264
265
    /**
266
     * Offset to set.
267
     *
268
     * @link http://php.net/manual/en/arrayaccess.offsetset.php
269
     *
270
     * @param mixed $offset <p>
271
     *                      The offset to assign the value to.
272
     *                      </p>
273
     * @param mixed $value  <p>
274
     *                      The value to set.
275
     *                      </p>
276
     *
277
     * @since 5.0.0
278
     */
279
    public function offsetSet($offset, $value)
280
    {
281
        throw new TDBMInvalidOperationException('You can set values in a TDBM result set.');
282
    }
283
284
    /**
285
     * Offset to unset.
286
     *
287
     * @link http://php.net/manual/en/arrayaccess.offsetunset.php
288
     *
289
     * @param mixed $offset <p>
290
     *                      The offset to unset.
291
     *                      </p>
292
     *
293
     * @since 5.0.0
294
     */
295
    public function offsetUnset($offset)
296
    {
297
        throw new TDBMInvalidOperationException('You can unset values in a TDBM result set.');
298
    }
299
}
300