InnerResultIterator::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 14
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 12
nc 1
nop 10

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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