Completed
Pull Request — 4.2 (#126)
by
unknown
05:16
created
src/Mouf/Database/TDBM/TDBMObject.php 1 patch
Indentation   +34 added lines, -34 removed lines patch added patch discarded remove patch
@@ -33,42 +33,42 @@
 block discarded – undo
33 33
  */
34 34
 class TDBMObject extends AbstractTDBMObject
35 35
 {
36
-    public function getProperty($var, $tableName = null)
37
-    {
38
-        return $this->get($var, $tableName);
39
-    }
36
+	public function getProperty($var, $tableName = null)
37
+	{
38
+		return $this->get($var, $tableName);
39
+	}
40 40
 
41
-    public function setProperty($var, $value, $tableName = null)
42
-    {
43
-        $this->set($var, $value, $tableName);
44
-    }
41
+	public function setProperty($var, $value, $tableName = null)
42
+	{
43
+		$this->set($var, $value, $tableName);
44
+	}
45 45
 
46
-    /**
47
-     * Specify data which should be serialized to JSON.
48
-     *
49
-     * @link http://php.net/manual/en/jsonserializable.jsonserialize.php
50
-     *
51
-     * @return mixed data which can be serialized by <b>json_encode</b>,
52
-     *               which is a value of any type other than a resource
53
-     *
54
-     * @since 5.4.0
55
-     */
56
-    public function jsonSerialize()
57
-    {
58
-        throw new TDBMException('Json serialization is only implemented for generated beans.');
59
-    }
46
+	/**
47
+	 * Specify data which should be serialized to JSON.
48
+	 *
49
+	 * @link http://php.net/manual/en/jsonserializable.jsonserialize.php
50
+	 *
51
+	 * @return mixed data which can be serialized by <b>json_encode</b>,
52
+	 *               which is a value of any type other than a resource
53
+	 *
54
+	 * @since 5.4.0
55
+	 */
56
+	public function jsonSerialize()
57
+	{
58
+		throw new TDBMException('Json serialization is only implemented for generated beans.');
59
+	}
60 60
 
61
-    /**
62
-     * Returns an array of used tables by this bean (from parent to child relationship).
63
-     *
64
-     * @return string[]
65
-     */
66
-    protected function getUsedTables()
67
-    {
68
-        $tableNames = array_keys($this->dbRows);
69
-        $tableNames = $this->tdbmService->_getLinkBetweenInheritedTables($tableNames);
70
-        $tableNames = array_reverse($tableNames);
61
+	/**
62
+	 * Returns an array of used tables by this bean (from parent to child relationship).
63
+	 *
64
+	 * @return string[]
65
+	 */
66
+	protected function getUsedTables()
67
+	{
68
+		$tableNames = array_keys($this->dbRows);
69
+		$tableNames = $this->tdbmService->_getLinkBetweenInheritedTables($tableNames);
70
+		$tableNames = array_reverse($tableNames);
71 71
 
72
-        return $tableNames;
73
-    }
72
+		return $tableNames;
73
+	}
74 74
 }
Please login to merge, or discard this patch.
src/Mouf/Database/TDBM/InnerResultIterator.php 1 patch
Indentation   +263 added lines, -263 removed lines patch added patch discarded remove patch
@@ -29,267 +29,267 @@
 block discarded – undo
29 29
  */
30 30
 class InnerResultIterator implements \Iterator, \Countable, \ArrayAccess
31 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>>>
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
-    }
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>>>
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 295
 }
Please login to merge, or discard this patch.
src/Mouf/Database/TDBM/OrderByAnalyzer.php 2 patches
Indentation   +118 added lines, -118 removed lines patch added patch discarded remove patch
@@ -12,122 +12,122 @@
 block discarded – undo
12 12
  */
13 13
 class OrderByAnalyzer
14 14
 {
15
-    /**
16
-     * The content of the cache variable.
17
-     *
18
-     * @var Cache
19
-     */
20
-    private $cache;
21
-
22
-    /**
23
-     * @var string
24
-     */
25
-    private $cachePrefix;
26
-
27
-    /**
28
-     * OrderByAnalyzer constructor.
29
-     *
30
-     * @param Cache       $cache
31
-     * @param string|null $cachePrefix
32
-     */
33
-    public function __construct(Cache $cache, $cachePrefix = null)
34
-    {
35
-        $this->cache = $cache;
36
-        $this->cachePrefix = $cachePrefix;
37
-    }
38
-
39
-    /**
40
-     * Returns an array for each sorted "column" in the form:.
41
-     *
42
-     * [
43
-     *      [
44
-     *          'type' => 'colref',
45
-     *          'table' => null,
46
-     *          'column' => 'a',
47
-     *          'direction' => 'ASC'
48
-     *      ],
49
-     *      [
50
-     *          'type' => 'expr',
51
-     *          'expr' => 'RAND()',
52
-     *          'direction' => 'DESC'
53
-     *      ]
54
-     * ]
55
-     *
56
-     * @param string $orderBy
57
-     *
58
-     * @return array
59
-     */
60
-    public function analyzeOrderBy(string $orderBy) : array
61
-    {
62
-        $key = $this->cachePrefix.'_order_by_analysis_'.$orderBy;
63
-        $results = $this->cache->fetch($key);
64
-        if ($results !== false) {
65
-            return $results;
66
-        }
67
-        $results = $this->analyzeOrderByNoCache($orderBy);
68
-        $this->cache->save($key, $results);
69
-
70
-        return $results;
71
-    }
72
-
73
-    private function analyzeOrderByNoCache(string $orderBy) : array
74
-    {
75
-        $sqlParser = new PHPSQLParser();
76
-        $sql = 'SELECT 1 FROM a ORDER BY '.$orderBy;
77
-        $parsed = $sqlParser->parse($sql, true);
78
-
79
-        $results = [];
80
-
81
-        for ($i = 0, $count = count($parsed['ORDER']); $i < $count; ++$i) {
82
-            $orderItem = $parsed['ORDER'][$i];
83
-            if ($orderItem['expr_type'] === 'colref') {
84
-                $parts = $orderItem['no_quotes']['parts'];
85
-                $columnName = array_pop($parts);
86
-                if (!empty($parts)) {
87
-                    $tableName = array_pop($parts);
88
-                } else {
89
-                    $tableName = null;
90
-                }
91
-
92
-                $results[] = [
93
-                    'type' => 'colref',
94
-                    'table' => $tableName,
95
-                    'column' => $columnName,
96
-                    'direction' => $orderItem['direction'],
97
-                ];
98
-            } else {
99
-                $position = $orderItem['position'];
100
-                if ($i + 1 < $count) {
101
-                    $nextPosition = $parsed['ORDER'][$i + 1]['position'];
102
-                    $str = substr($sql, $position, $nextPosition - $position);
103
-                } else {
104
-                    $str = substr($sql, $position);
105
-                }
106
-
107
-                $str = trim($str, " \t\r\n,");
108
-
109
-                $results[] = [
110
-                    'type' => 'expr',
111
-                    'expr' => $this->trimDirection($str),
112
-                    'direction' => $orderItem['direction'],
113
-                ];
114
-            }
115
-        }
116
-
117
-        return $results;
118
-    }
119
-
120
-    /**
121
-     * Trims the ASC/DESC direction at the end of the string.
122
-     *
123
-     * @param string $sql
124
-     *
125
-     * @return string
126
-     */
127
-    private function trimDirection(string $sql) : string
128
-    {
129
-        preg_match('/^(.*)(\s+(DESC|ASC|))*$/Ui', $sql, $matches);
130
-
131
-        return $matches[1];
132
-    }
15
+	/**
16
+	 * The content of the cache variable.
17
+	 *
18
+	 * @var Cache
19
+	 */
20
+	private $cache;
21
+
22
+	/**
23
+	 * @var string
24
+	 */
25
+	private $cachePrefix;
26
+
27
+	/**
28
+	 * OrderByAnalyzer constructor.
29
+	 *
30
+	 * @param Cache       $cache
31
+	 * @param string|null $cachePrefix
32
+	 */
33
+	public function __construct(Cache $cache, $cachePrefix = null)
34
+	{
35
+		$this->cache = $cache;
36
+		$this->cachePrefix = $cachePrefix;
37
+	}
38
+
39
+	/**
40
+	 * Returns an array for each sorted "column" in the form:.
41
+	 *
42
+	 * [
43
+	 *      [
44
+	 *          'type' => 'colref',
45
+	 *          'table' => null,
46
+	 *          'column' => 'a',
47
+	 *          'direction' => 'ASC'
48
+	 *      ],
49
+	 *      [
50
+	 *          'type' => 'expr',
51
+	 *          'expr' => 'RAND()',
52
+	 *          'direction' => 'DESC'
53
+	 *      ]
54
+	 * ]
55
+	 *
56
+	 * @param string $orderBy
57
+	 *
58
+	 * @return array
59
+	 */
60
+	public function analyzeOrderBy(string $orderBy) : array
61
+	{
62
+		$key = $this->cachePrefix.'_order_by_analysis_'.$orderBy;
63
+		$results = $this->cache->fetch($key);
64
+		if ($results !== false) {
65
+			return $results;
66
+		}
67
+		$results = $this->analyzeOrderByNoCache($orderBy);
68
+		$this->cache->save($key, $results);
69
+
70
+		return $results;
71
+	}
72
+
73
+	private function analyzeOrderByNoCache(string $orderBy) : array
74
+	{
75
+		$sqlParser = new PHPSQLParser();
76
+		$sql = 'SELECT 1 FROM a ORDER BY '.$orderBy;
77
+		$parsed = $sqlParser->parse($sql, true);
78
+
79
+		$results = [];
80
+
81
+		for ($i = 0, $count = count($parsed['ORDER']); $i < $count; ++$i) {
82
+			$orderItem = $parsed['ORDER'][$i];
83
+			if ($orderItem['expr_type'] === 'colref') {
84
+				$parts = $orderItem['no_quotes']['parts'];
85
+				$columnName = array_pop($parts);
86
+				if (!empty($parts)) {
87
+					$tableName = array_pop($parts);
88
+				} else {
89
+					$tableName = null;
90
+				}
91
+
92
+				$results[] = [
93
+					'type' => 'colref',
94
+					'table' => $tableName,
95
+					'column' => $columnName,
96
+					'direction' => $orderItem['direction'],
97
+				];
98
+			} else {
99
+				$position = $orderItem['position'];
100
+				if ($i + 1 < $count) {
101
+					$nextPosition = $parsed['ORDER'][$i + 1]['position'];
102
+					$str = substr($sql, $position, $nextPosition - $position);
103
+				} else {
104
+					$str = substr($sql, $position);
105
+				}
106
+
107
+				$str = trim($str, " \t\r\n,");
108
+
109
+				$results[] = [
110
+					'type' => 'expr',
111
+					'expr' => $this->trimDirection($str),
112
+					'direction' => $orderItem['direction'],
113
+				];
114
+			}
115
+		}
116
+
117
+		return $results;
118
+	}
119
+
120
+	/**
121
+	 * Trims the ASC/DESC direction at the end of the string.
122
+	 *
123
+	 * @param string $sql
124
+	 *
125
+	 * @return string
126
+	 */
127
+	private function trimDirection(string $sql) : string
128
+	{
129
+		preg_match('/^(.*)(\s+(DESC|ASC|))*$/Ui', $sql, $matches);
130
+
131
+		return $matches[1];
132
+	}
133 133
 }
Please login to merge, or discard this patch.
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -78,7 +78,7 @@  discard block
 block discarded – undo
78 78
 
79 79
         $results = [];
80 80
 
81
-        for ($i = 0, $count = count($parsed['ORDER']); $i < $count; ++$i) {
81
+        for ($i = 0, $count = count($parsed['ORDER']); $i<$count; ++$i) {
82 82
             $orderItem = $parsed['ORDER'][$i];
83 83
             if ($orderItem['expr_type'] === 'colref') {
84 84
                 $parts = $orderItem['no_quotes']['parts'];
@@ -97,9 +97,9 @@  discard block
 block discarded – undo
97 97
                 ];
98 98
             } else {
99 99
                 $position = $orderItem['position'];
100
-                if ($i + 1 < $count) {
101
-                    $nextPosition = $parsed['ORDER'][$i + 1]['position'];
102
-                    $str = substr($sql, $position, $nextPosition - $position);
100
+                if ($i+1<$count) {
101
+                    $nextPosition = $parsed['ORDER'][$i+1]['position'];
102
+                    $str = substr($sql, $position, $nextPosition-$position);
103 103
                 } else {
104 104
                     $str = substr($sql, $position);
105 105
                 }
Please login to merge, or discard this patch.
src/Mouf/Database/TDBM/UncheckedOrderBy.php 1 patch
Indentation   +18 added lines, -18 removed lines patch added patch discarded remove patch
@@ -20,24 +20,24 @@
 block discarded – undo
20 20
  */
21 21
 class UncheckedOrderBy
22 22
 {
23
-    /**
24
-     * @var string
25
-     */
26
-    private $orderBy;
23
+	/**
24
+	 * @var string
25
+	 */
26
+	private $orderBy;
27 27
 
28
-    /**
29
-     * @param $orderBy
30
-     */
31
-    public function __construct(string $orderBy)
32
-    {
33
-        $this->orderBy = $orderBy;
34
-    }
28
+	/**
29
+	 * @param $orderBy
30
+	 */
31
+	public function __construct(string $orderBy)
32
+	{
33
+		$this->orderBy = $orderBy;
34
+	}
35 35
 
36
-    /**
37
-     * @return string
38
-     */
39
-    public function getOrderBy() : string
40
-    {
41
-        return $this->orderBy;
42
-    }
36
+	/**
37
+	 * @return string
38
+	 */
39
+	public function getOrderBy() : string
40
+	{
41
+		return $this->orderBy;
42
+	}
43 43
 }
Please login to merge, or discard this patch.
src/Mouf/Database/TDBM/QueryFactory/FindObjectsQueryFactory.php 2 patches
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -39,7 +39,7 @@
 block discarded – undo
39 39
         $sql = 'SELECT DISTINCT '.implode(', ', $columnsList).' FROM MAGICJOIN('.$this->mainTable.')';
40 40
 
41 41
         $pkColumnNames = $this->schema->getTable($this->mainTable)->getPrimaryKeyColumns();
42
-        $pkColumnNames = array_map(function ($pkColumn) {
42
+        $pkColumnNames = array_map(function($pkColumn) {
43 43
             return $this->tdbmService->getConnection()->quoteIdentifier($this->mainTable).'.'.$this->tdbmService->getConnection()->quoteIdentifier($pkColumn);
44 44
         }, $pkColumnNames);
45 45
 
Please login to merge, or discard this patch.
Indentation   +38 added lines, -38 removed lines patch added patch discarded remove patch
@@ -11,44 +11,44 @@
 block discarded – undo
11 11
  */
12 12
 class FindObjectsQueryFactory extends AbstractQueryFactory
13 13
 {
14
-    private $mainTable;
15
-    private $additionalTablesFetch;
16
-    private $filterString;
17
-
18
-    public function __construct(string $mainTable, array $additionalTablesFetch, $filterString, $orderBy, TDBMService $tdbmService, Schema $schema, OrderByAnalyzer $orderByAnalyzer)
19
-    {
20
-        parent::__construct($tdbmService, $schema, $orderByAnalyzer, $orderBy);
21
-        $this->mainTable = $mainTable;
22
-        $this->additionalTablesFetch = $additionalTablesFetch;
23
-        $this->filterString = $filterString;
24
-    }
25
-
26
-    protected function compute()
27
-    {
28
-        list($columnDescList, $columnsList, $orderString) = $this->getColumnsList($this->mainTable, $this->additionalTablesFetch, $this->orderBy);
29
-
30
-        $sql = 'SELECT DISTINCT '.implode(', ', $columnsList).' FROM MAGICJOIN('.$this->mainTable.')';
31
-
32
-        $pkColumnNames = $this->schema->getTable($this->mainTable)->getPrimaryKeyColumns();
33
-        $pkColumnNames = array_map(function ($pkColumn) {
34
-            return $this->tdbmService->getConnection()->quoteIdentifier($this->mainTable).'.'.$this->tdbmService->getConnection()->quoteIdentifier($pkColumn);
35
-        }, $pkColumnNames);
36
-
37
-        $countSql = 'SELECT COUNT(DISTINCT '.implode(', ', $pkColumnNames).') FROM MAGICJOIN('.$this->mainTable.')';
38
-
39
-        if (!empty($this->filterString)) {
40
-            $sql .= ' WHERE '.$this->filterString;
41
-            $countSql .= ' WHERE '.$this->filterString;
42
-        }
43
-
44
-        if (!empty($orderString)) {
45
-            $sql .= ' ORDER BY '.$orderString;
46
-        }
47
-
48
-        $this->magicSql = $sql;
49
-        $this->magicSqlCount = $countSql;
50
-        $this->columnDescList = $columnDescList;
51
-    }
14
+	private $mainTable;
15
+	private $additionalTablesFetch;
16
+	private $filterString;
17
+
18
+	public function __construct(string $mainTable, array $additionalTablesFetch, $filterString, $orderBy, TDBMService $tdbmService, Schema $schema, OrderByAnalyzer $orderByAnalyzer)
19
+	{
20
+		parent::__construct($tdbmService, $schema, $orderByAnalyzer, $orderBy);
21
+		$this->mainTable = $mainTable;
22
+		$this->additionalTablesFetch = $additionalTablesFetch;
23
+		$this->filterString = $filterString;
24
+	}
25
+
26
+	protected function compute()
27
+	{
28
+		list($columnDescList, $columnsList, $orderString) = $this->getColumnsList($this->mainTable, $this->additionalTablesFetch, $this->orderBy);
29
+
30
+		$sql = 'SELECT DISTINCT '.implode(', ', $columnsList).' FROM MAGICJOIN('.$this->mainTable.')';
31
+
32
+		$pkColumnNames = $this->schema->getTable($this->mainTable)->getPrimaryKeyColumns();
33
+		$pkColumnNames = array_map(function ($pkColumn) {
34
+			return $this->tdbmService->getConnection()->quoteIdentifier($this->mainTable).'.'.$this->tdbmService->getConnection()->quoteIdentifier($pkColumn);
35
+		}, $pkColumnNames);
36
+
37
+		$countSql = 'SELECT COUNT(DISTINCT '.implode(', ', $pkColumnNames).') FROM MAGICJOIN('.$this->mainTable.')';
38
+
39
+		if (!empty($this->filterString)) {
40
+			$sql .= ' WHERE '.$this->filterString;
41
+			$countSql .= ' WHERE '.$this->filterString;
42
+		}
43
+
44
+		if (!empty($orderString)) {
45
+			$sql .= ' ORDER BY '.$orderString;
46
+		}
47
+
48
+		$this->magicSql = $sql;
49
+		$this->magicSqlCount = $countSql;
50
+		$this->columnDescList = $columnDescList;
51
+	}
52 52
 
53 53
 
54 54
 }
Please login to merge, or discard this patch.
src/Mouf/Database/TDBM/QueryFactory/QueryFactory.php 1 patch
Indentation   +18 added lines, -18 removed lines patch added patch discarded remove patch
@@ -9,25 +9,25 @@
 block discarded – undo
9 9
  */
10 10
 interface QueryFactory
11 11
 {
12
-    /**
13
-     * Sets the ORDER BY directive executed in SQL.
14
-     *
15
-     * For instance:
16
-     *
17
-     *  $queryFactory->sort('label ASC, status DESC');
18
-     *
19
-     * **Important:** TDBM does its best to protect you from SQL injection. In particular, it will only allow column names in the "ORDER BY" clause. This means you are safe to pass input from the user directly in the ORDER BY parameter.
20
-     * If you want to pass an expression to the ORDER BY clause, you will need to tell TDBM to stop checking for SQL injections. You do this by passing a `UncheckedOrderBy` object as a parameter:
21
-     *
22
-     *  $queryFactory->sort(new UncheckedOrderBy('RAND()'))
23
-     *
24
-     * @param string|UncheckedOrderBy|null $orderBy
25
-     */
26
-    public function sort($orderBy);
12
+	/**
13
+	 * Sets the ORDER BY directive executed in SQL.
14
+	 *
15
+	 * For instance:
16
+	 *
17
+	 *  $queryFactory->sort('label ASC, status DESC');
18
+	 *
19
+	 * **Important:** TDBM does its best to protect you from SQL injection. In particular, it will only allow column names in the "ORDER BY" clause. This means you are safe to pass input from the user directly in the ORDER BY parameter.
20
+	 * If you want to pass an expression to the ORDER BY clause, you will need to tell TDBM to stop checking for SQL injections. You do this by passing a `UncheckedOrderBy` object as a parameter:
21
+	 *
22
+	 *  $queryFactory->sort(new UncheckedOrderBy('RAND()'))
23
+	 *
24
+	 * @param string|UncheckedOrderBy|null $orderBy
25
+	 */
26
+	public function sort($orderBy);
27 27
 
28
-    public function getMagicSql() : string;
28
+	public function getMagicSql() : string;
29 29
 
30
-    public function getMagicSqlCount() : string;
30
+	public function getMagicSqlCount() : string;
31 31
 
32
-    public function getColumnDescriptors() : array;
32
+	public function getColumnDescriptors() : array;
33 33
 }
Please login to merge, or discard this patch.
src/Mouf/Database/TDBM/Utils/ScalarBeanPropertyDescriptor.php 1 patch
Indentation   +167 added lines, -167 removed lines patch added patch discarded remove patch
@@ -11,125 +11,125 @@  discard block
 block discarded – undo
11 11
  */
12 12
 class ScalarBeanPropertyDescriptor extends AbstractBeanPropertyDescriptor
13 13
 {
14
-    /**
15
-     * @var Column
16
-     */
17
-    private $column;
18
-
19
-    public function __construct(Table $table, Column $column)
20
-    {
21
-        parent::__construct($table);
22
-        $this->table = $table;
23
-        $this->column = $column;
24
-    }
25
-
26
-    /**
27
-     * Returns the foreign-key the column is part of, if any. null otherwise.
28
-     *
29
-     * @return ForeignKeyConstraint|null
30
-     */
31
-    public function getForeignKey()
32
-    {
33
-        return false;
34
-    }
35
-
36
-    /**
37
-     * Returns the param annotation for this property (useful for constructor).
38
-     *
39
-     * @return string
40
-     */
41
-    public function getParamAnnotation()
42
-    {
43
-        $className = $this->getClassName();
44
-        $paramType = $className ?: TDBMDaoGenerator::dbalTypeToPhpType($this->column->getType());
45
-
46
-        $str = '     * @param %s %s';
47
-
48
-        return sprintf($str, $paramType, $this->getVariableName());
49
-    }
50
-
51
-    public function getUpperCamelCaseName()
52
-    {
53
-        return TDBMDaoGenerator::toCamelCase($this->column->getName());
54
-    }
55
-
56
-    /**
57
-     * Returns the name of the class linked to this property or null if this is not a foreign key.
58
-     *
59
-     * @return null|string
60
-     */
61
-    public function getClassName()
62
-    {
63
-        return;
64
-    }
65
-
66
-    /**
67
-     * Returns true if the property is compulsory (and therefore should be fetched in the constructor).
68
-     *
69
-     * @return bool
70
-     */
71
-    public function isCompulsory()
72
-    {
73
-        return $this->column->getNotnull() && !$this->column->getAutoincrement() && $this->column->getDefault() === null;
74
-    }
75
-
76
-    /**
77
-     * Returns true if the property has a default value.
78
-     *
79
-     * @return bool
80
-     */
81
-    public function hasDefault()
82
-    {
83
-        return $this->column->getDefault() !== null;
84
-    }
85
-
86
-    /**
87
-     * Returns the code that assigns a value to its default value.
88
-     *
89
-     * @return string
90
-     */
91
-    public function assignToDefaultCode()
92
-    {
93
-        $str = '        $this->%s(%s);';
94
-
95
-        $default = $this->column->getDefault();
96
-
97
-        if (strtoupper($default) === 'CURRENT_TIMESTAMP') {
98
-            $defaultCode = 'new \DateTimeImmutable()';
99
-        } else {
100
-            $defaultCode = var_export($this->column->getDefault(), true);
101
-        }
102
-
103
-        return sprintf($str, $this->getSetterName(), $defaultCode);
104
-    }
105
-
106
-    /**
107
-     * Returns true if the property is the primary key.
108
-     *
109
-     * @return bool
110
-     */
111
-    public function isPrimaryKey()
112
-    {
113
-        return in_array($this->column->getName(), $this->table->getPrimaryKeyColumns());
114
-    }
115
-
116
-    /**
117
-     * Returns the PHP code for getters and setters.
118
-     *
119
-     * @return string
120
-     */
121
-    public function getGetterSetterCode()
122
-    {
123
-        $type = $this->column->getType();
124
-        $normalizedType = TDBMDaoGenerator::dbalTypeToPhpType($type);
125
-
126
-        $columnGetterName = $this->getGetterName();
127
-        $columnSetterName = $this->getSetterName();
128
-
129
-        // A column type can be forced if it is not nullable and not auto-incrmentable (for auto-increment columns, we can get "null" as long as the bean is not saved).
130
-        $canForceGetterReturnType = $this->column->getNotnull() && !$this->column->getAutoincrement();
131
-
132
-        $getterAndSetterCode = '    /**
14
+	/**
15
+	 * @var Column
16
+	 */
17
+	private $column;
18
+
19
+	public function __construct(Table $table, Column $column)
20
+	{
21
+		parent::__construct($table);
22
+		$this->table = $table;
23
+		$this->column = $column;
24
+	}
25
+
26
+	/**
27
+	 * Returns the foreign-key the column is part of, if any. null otherwise.
28
+	 *
29
+	 * @return ForeignKeyConstraint|null
30
+	 */
31
+	public function getForeignKey()
32
+	{
33
+		return false;
34
+	}
35
+
36
+	/**
37
+	 * Returns the param annotation for this property (useful for constructor).
38
+	 *
39
+	 * @return string
40
+	 */
41
+	public function getParamAnnotation()
42
+	{
43
+		$className = $this->getClassName();
44
+		$paramType = $className ?: TDBMDaoGenerator::dbalTypeToPhpType($this->column->getType());
45
+
46
+		$str = '     * @param %s %s';
47
+
48
+		return sprintf($str, $paramType, $this->getVariableName());
49
+	}
50
+
51
+	public function getUpperCamelCaseName()
52
+	{
53
+		return TDBMDaoGenerator::toCamelCase($this->column->getName());
54
+	}
55
+
56
+	/**
57
+	 * Returns the name of the class linked to this property or null if this is not a foreign key.
58
+	 *
59
+	 * @return null|string
60
+	 */
61
+	public function getClassName()
62
+	{
63
+		return;
64
+	}
65
+
66
+	/**
67
+	 * Returns true if the property is compulsory (and therefore should be fetched in the constructor).
68
+	 *
69
+	 * @return bool
70
+	 */
71
+	public function isCompulsory()
72
+	{
73
+		return $this->column->getNotnull() && !$this->column->getAutoincrement() && $this->column->getDefault() === null;
74
+	}
75
+
76
+	/**
77
+	 * Returns true if the property has a default value.
78
+	 *
79
+	 * @return bool
80
+	 */
81
+	public function hasDefault()
82
+	{
83
+		return $this->column->getDefault() !== null;
84
+	}
85
+
86
+	/**
87
+	 * Returns the code that assigns a value to its default value.
88
+	 *
89
+	 * @return string
90
+	 */
91
+	public function assignToDefaultCode()
92
+	{
93
+		$str = '        $this->%s(%s);';
94
+
95
+		$default = $this->column->getDefault();
96
+
97
+		if (strtoupper($default) === 'CURRENT_TIMESTAMP') {
98
+			$defaultCode = 'new \DateTimeImmutable()';
99
+		} else {
100
+			$defaultCode = var_export($this->column->getDefault(), true);
101
+		}
102
+
103
+		return sprintf($str, $this->getSetterName(), $defaultCode);
104
+	}
105
+
106
+	/**
107
+	 * Returns true if the property is the primary key.
108
+	 *
109
+	 * @return bool
110
+	 */
111
+	public function isPrimaryKey()
112
+	{
113
+		return in_array($this->column->getName(), $this->table->getPrimaryKeyColumns());
114
+	}
115
+
116
+	/**
117
+	 * Returns the PHP code for getters and setters.
118
+	 *
119
+	 * @return string
120
+	 */
121
+	public function getGetterSetterCode()
122
+	{
123
+		$type = $this->column->getType();
124
+		$normalizedType = TDBMDaoGenerator::dbalTypeToPhpType($type);
125
+
126
+		$columnGetterName = $this->getGetterName();
127
+		$columnSetterName = $this->getSetterName();
128
+
129
+		// A column type can be forced if it is not nullable and not auto-incrmentable (for auto-increment columns, we can get "null" as long as the bean is not saved).
130
+		$canForceGetterReturnType = $this->column->getNotnull() && !$this->column->getAutoincrement();
131
+
132
+		$getterAndSetterCode = '    /**
133 133
      * The getter for the "%s" column.
134 134
      *
135 135
      * @return %s
@@ -151,52 +151,52 @@  discard block
 block discarded – undo
151 151
 
152 152
 ';
153 153
 
154
-        return sprintf($getterAndSetterCode,
155
-            // Getter
156
-            $this->column->getName(),
157
-            $normalizedType.($canForceGetterReturnType ? '' : '|null'),
158
-            $columnGetterName,
159
-            ($canForceGetterReturnType ? ' : '.$normalizedType : ''),
160
-            var_export($this->column->getName(), true),
161
-            var_export($this->table->getName(), true),
162
-            // Setter
163
-            $this->column->getName(),
164
-            $normalizedType,
165
-            $this->column->getName(),
166
-            $columnSetterName,
167
-            $normalizedType,
168
-            //$castTo,
169
-            $this->column->getName().($this->column->getNotnull() ? '' : ' = null'),
170
-            var_export($this->column->getName(), true),
171
-            $this->column->getName(),
172
-            var_export($this->table->getName(), true)
173
-        );
174
-    }
175
-
176
-    /**
177
-     * Returns the part of code useful when doing json serialization.
178
-     *
179
-     * @return string
180
-     */
181
-    public function getJsonSerializeCode()
182
-    {
183
-        $type = $this->column->getType();
184
-        $normalizedType = TDBMDaoGenerator::dbalTypeToPhpType($type);
185
-
186
-        if ($normalizedType == '\\DateTimeInterface') {
187
-            return '        $array['.var_export($this->getLowerCamelCaseName(), true).'] = ($this->'.$this->getGetterName().'() === null) ? null : $this->'.$this->getGetterName()."()->format('c');\n";
188
-        } else {
189
-            return '        $array['.var_export($this->getLowerCamelCaseName(), true).'] = $this->'.$this->getGetterName()."();\n";
190
-        }
191
-    }
192
-
193
-    /**
194
-     * Returns the column name.
195
-     *
196
-     * @return string
197
-     */
198
-    public function getColumnName()
199
-    {
200
-        return $this->column->getName();
201
-    }
154
+		return sprintf($getterAndSetterCode,
155
+			// Getter
156
+			$this->column->getName(),
157
+			$normalizedType.($canForceGetterReturnType ? '' : '|null'),
158
+			$columnGetterName,
159
+			($canForceGetterReturnType ? ' : '.$normalizedType : ''),
160
+			var_export($this->column->getName(), true),
161
+			var_export($this->table->getName(), true),
162
+			// Setter
163
+			$this->column->getName(),
164
+			$normalizedType,
165
+			$this->column->getName(),
166
+			$columnSetterName,
167
+			$normalizedType,
168
+			//$castTo,
169
+			$this->column->getName().($this->column->getNotnull() ? '' : ' = null'),
170
+			var_export($this->column->getName(), true),
171
+			$this->column->getName(),
172
+			var_export($this->table->getName(), true)
173
+		);
174
+	}
175
+
176
+	/**
177
+	 * Returns the part of code useful when doing json serialization.
178
+	 *
179
+	 * @return string
180
+	 */
181
+	public function getJsonSerializeCode()
182
+	{
183
+		$type = $this->column->getType();
184
+		$normalizedType = TDBMDaoGenerator::dbalTypeToPhpType($type);
185
+
186
+		if ($normalizedType == '\\DateTimeInterface') {
187
+			return '        $array['.var_export($this->getLowerCamelCaseName(), true).'] = ($this->'.$this->getGetterName().'() === null) ? null : $this->'.$this->getGetterName()."()->format('c');\n";
188
+		} else {
189
+			return '        $array['.var_export($this->getLowerCamelCaseName(), true).'] = $this->'.$this->getGetterName()."();\n";
190
+		}
191
+	}
192
+
193
+	/**
194
+	 * Returns the column name.
195
+	 *
196
+	 * @return string
197
+	 */
198
+	public function getColumnName()
199
+	{
200
+		return $this->column->getName();
201
+	}
202 202
 }
Please login to merge, or discard this patch.
src/Mouf/Database/TDBM/QueryFactory/AbstractQueryFactory.php 1 patch
Indentation   +210 added lines, -210 removed lines patch added patch discarded remove patch
@@ -10,214 +10,214 @@
 block discarded – undo
10 10
 
11 11
 abstract class AbstractQueryFactory implements QueryFactory
12 12
 {
13
-    /**
14
-     * @var TDBMService
15
-     */
16
-    protected $tdbmService;
17
-
18
-    /**
19
-     * @var Schema
20
-     */
21
-    protected $schema;
22
-
23
-    /**
24
-     * @var OrderByAnalyzer
25
-     */
26
-    protected $orderByAnalyzer;
27
-
28
-    /**
29
-     * @var string|UncheckedOrderBy|null
30
-     */
31
-    protected $orderBy;
32
-
33
-    protected $magicSql;
34
-    protected $magicSqlCount;
35
-    protected $columnDescList;
36
-
37
-    /**
38
-     * @param TDBMService $tdbmService
39
-     */
40
-    public function __construct(TDBMService $tdbmService, Schema $schema, OrderByAnalyzer $orderByAnalyzer, $orderBy)
41
-    {
42
-        $this->tdbmService = $tdbmService;
43
-        $this->schema = $schema;
44
-        $this->orderByAnalyzer = $orderByAnalyzer;
45
-        $this->orderBy = $orderBy;
46
-    }
47
-
48
-    /**
49
-     * Returns the column list that must be fetched for the SQL request.
50
-     *
51
-     * Note: MySQL dictates that ORDER BYed columns should appear in the SELECT clause.
52
-     *
53
-     * @param string                       $mainTable
54
-     * @param array                        $additionalTablesFetch
55
-     * @param string|UncheckedOrderBy|null $orderBy
56
-     *
57
-     * @return array
58
-     *
59
-     * @throws \Doctrine\DBAL\Schema\SchemaException
60
-     */
61
-    protected function getColumnsList(string $mainTable, array $additionalTablesFetch = array(), $orderBy = null)
62
-    {
63
-        // From the table name and the additional tables we want to fetch, let's build a list of all tables
64
-        // that must be part of the select columns.
65
-
66
-        $connection = $this->tdbmService->getConnection();
67
-
68
-        $tableGroups = [];
69
-        $allFetchedTables = $this->tdbmService->_getRelatedTablesByInheritance($mainTable);
70
-        $tableGroupName = $this->getTableGroupName($allFetchedTables);
71
-        foreach ($allFetchedTables as $table) {
72
-            $tableGroups[$table] = $tableGroupName;
73
-        }
74
-
75
-        $columnsList = [];
76
-        $columnDescList = [];
77
-        $sortColumn = 0;
78
-        $reconstructedOrderBy = null;
79
-
80
-        if (is_string($orderBy)) {
81
-            $orderBy = trim($orderBy);
82
-            if ($orderBy === '') {
83
-                $orderBy = null;
84
-            }
85
-        }
86
-
87
-        // Now, let's deal with "order by columns"
88
-        if ($orderBy !== null) {
89
-            if ($orderBy instanceof UncheckedOrderBy) {
90
-                $securedOrderBy = false;
91
-                $orderBy = $orderBy->getOrderBy();
92
-                $reconstructedOrderBy = $orderBy;
93
-            } else {
94
-                $securedOrderBy = true;
95
-                $reconstructedOrderBys = [];
96
-            }
97
-            $orderByColumns = $this->orderByAnalyzer->analyzeOrderBy($orderBy);
98
-
99
-            // If we sort by a column, there is a high chance we will fetch the bean containing this column.
100
-            // Hence, we should add the table to the $additionalTablesFetch
101
-            foreach ($orderByColumns as $orderByColumn) {
102
-                if ($orderByColumn['type'] === 'colref') {
103
-                    if ($orderByColumn['table'] !== null) {
104
-                        $additionalTablesFetch[] = $orderByColumn['table'];
105
-                    }
106
-                    if ($securedOrderBy) {
107
-                        $reconstructedOrderBys[] = ($orderByColumn['table'] !== null ? $connection->quoteIdentifier($orderByColumn['table']).'.' : '').$connection->quoteIdentifier($orderByColumn['column']).' '.$orderByColumn['direction'];
108
-                    }
109
-                } elseif ($orderByColumn['type'] === 'expr') {
110
-                    $sortColumnName = 'sort_column_'.$sortColumn;
111
-                    $columnsList[] = $orderByColumn['expr'].' as '.$sortColumnName;
112
-                    $columnDescList[] = [
113
-                        'tableGroup' => null,
114
-                    ];
115
-                    ++$sortColumn;
116
-
117
-                    if ($securedOrderBy) {
118
-                        throw new TDBMInvalidArgumentException('Invalid ORDER BY column: "'.$orderByColumn['expr'].'". If you want to use expression in your ORDER BY clause, you must wrap them in a UncheckedOrderBy object. For instance: new UncheckedOrderBy("col1 + col2 DESC")');
119
-                    }
120
-                }
121
-            }
122
-
123
-            if ($reconstructedOrderBy === null) {
124
-                $reconstructedOrderBy = implode(', ', $reconstructedOrderBys);
125
-            }
126
-        }
127
-
128
-        foreach ($additionalTablesFetch as $additionalTable) {
129
-            $relatedTables = $this->tdbmService->_getRelatedTablesByInheritance($additionalTable);
130
-            $tableGroupName = $this->getTableGroupName($relatedTables);
131
-            foreach ($relatedTables as $table) {
132
-                $tableGroups[$table] = $tableGroupName;
133
-            }
134
-            $allFetchedTables = array_merge($allFetchedTables, $relatedTables);
135
-        }
136
-
137
-        // Let's remove any duplicate
138
-        $allFetchedTables = array_flip(array_flip($allFetchedTables));
139
-
140
-        // Now, let's build the column list
141
-        foreach ($allFetchedTables as $table) {
142
-            foreach ($this->schema->getTable($table)->getColumns() as $column) {
143
-                $columnName = $column->getName();
144
-                $columnDescList[] = [
145
-                    'as' => $table.'____'.$columnName,
146
-                    'table' => $table,
147
-                    'column' => $columnName,
148
-                    'type' => $column->getType(),
149
-                    'tableGroup' => $tableGroups[$table],
150
-                ];
151
-                $columnsList[] = $connection->quoteIdentifier($table).'.'.$connection->quoteIdentifier($columnName).' as '.
152
-                    $connection->quoteIdentifier($table.'____'.$columnName);
153
-            }
154
-        }
155
-
156
-        return [$columnDescList, $columnsList, $reconstructedOrderBy];
157
-    }
158
-
159
-    abstract protected function compute();
160
-
161
-    /**
162
-     * Returns an identifier for the group of tables passed in parameter.
163
-     *
164
-     * @param string[] $relatedTables
165
-     *
166
-     * @return string
167
-     */
168
-    protected function getTableGroupName(array $relatedTables)
169
-    {
170
-        sort($relatedTables);
171
-
172
-        return implode('_``_', $relatedTables);
173
-    }
174
-
175
-    public function getMagicSql() : string
176
-    {
177
-        if ($this->magicSql === null) {
178
-            $this->compute();
179
-        }
180
-
181
-        return $this->magicSql;
182
-    }
183
-
184
-    public function getMagicSqlCount() : string
185
-    {
186
-        if ($this->magicSqlCount === null) {
187
-            $this->compute();
188
-        }
189
-
190
-        return $this->magicSqlCount;
191
-    }
192
-
193
-    public function getColumnDescriptors() : array
194
-    {
195
-        if ($this->columnDescList === null) {
196
-            $this->compute();
197
-        }
198
-
199
-        return $this->columnDescList;
200
-    }
201
-
202
-    /**
203
-     * Sets the ORDER BY directive executed in SQL.
204
-     *
205
-     * For instance:
206
-     *
207
-     *  $queryFactory->sort('label ASC, status DESC');
208
-     *
209
-     * **Important:** TDBM does its best to protect you from SQL injection. In particular, it will only allow column names in the "ORDER BY" clause. This means you are safe to pass input from the user directly in the ORDER BY parameter.
210
-     * If you want to pass an expression to the ORDER BY clause, you will need to tell TDBM to stop checking for SQL injections. You do this by passing a `UncheckedOrderBy` object as a parameter:
211
-     *
212
-     *  $queryFactory->sort(new UncheckedOrderBy('RAND()'))
213
-     *
214
-     * @param string|UncheckedOrderBy|null $orderBy
215
-     */
216
-    public function sort($orderBy)
217
-    {
218
-        $this->orderBy = $orderBy;
219
-        $this->magicSql = null;
220
-        $this->magicSqlCount = null;
221
-        $this->columnDescList = null;
222
-    }
13
+	/**
14
+	 * @var TDBMService
15
+	 */
16
+	protected $tdbmService;
17
+
18
+	/**
19
+	 * @var Schema
20
+	 */
21
+	protected $schema;
22
+
23
+	/**
24
+	 * @var OrderByAnalyzer
25
+	 */
26
+	protected $orderByAnalyzer;
27
+
28
+	/**
29
+	 * @var string|UncheckedOrderBy|null
30
+	 */
31
+	protected $orderBy;
32
+
33
+	protected $magicSql;
34
+	protected $magicSqlCount;
35
+	protected $columnDescList;
36
+
37
+	/**
38
+	 * @param TDBMService $tdbmService
39
+	 */
40
+	public function __construct(TDBMService $tdbmService, Schema $schema, OrderByAnalyzer $orderByAnalyzer, $orderBy)
41
+	{
42
+		$this->tdbmService = $tdbmService;
43
+		$this->schema = $schema;
44
+		$this->orderByAnalyzer = $orderByAnalyzer;
45
+		$this->orderBy = $orderBy;
46
+	}
47
+
48
+	/**
49
+	 * Returns the column list that must be fetched for the SQL request.
50
+	 *
51
+	 * Note: MySQL dictates that ORDER BYed columns should appear in the SELECT clause.
52
+	 *
53
+	 * @param string                       $mainTable
54
+	 * @param array                        $additionalTablesFetch
55
+	 * @param string|UncheckedOrderBy|null $orderBy
56
+	 *
57
+	 * @return array
58
+	 *
59
+	 * @throws \Doctrine\DBAL\Schema\SchemaException
60
+	 */
61
+	protected function getColumnsList(string $mainTable, array $additionalTablesFetch = array(), $orderBy = null)
62
+	{
63
+		// From the table name and the additional tables we want to fetch, let's build a list of all tables
64
+		// that must be part of the select columns.
65
+
66
+		$connection = $this->tdbmService->getConnection();
67
+
68
+		$tableGroups = [];
69
+		$allFetchedTables = $this->tdbmService->_getRelatedTablesByInheritance($mainTable);
70
+		$tableGroupName = $this->getTableGroupName($allFetchedTables);
71
+		foreach ($allFetchedTables as $table) {
72
+			$tableGroups[$table] = $tableGroupName;
73
+		}
74
+
75
+		$columnsList = [];
76
+		$columnDescList = [];
77
+		$sortColumn = 0;
78
+		$reconstructedOrderBy = null;
79
+
80
+		if (is_string($orderBy)) {
81
+			$orderBy = trim($orderBy);
82
+			if ($orderBy === '') {
83
+				$orderBy = null;
84
+			}
85
+		}
86
+
87
+		// Now, let's deal with "order by columns"
88
+		if ($orderBy !== null) {
89
+			if ($orderBy instanceof UncheckedOrderBy) {
90
+				$securedOrderBy = false;
91
+				$orderBy = $orderBy->getOrderBy();
92
+				$reconstructedOrderBy = $orderBy;
93
+			} else {
94
+				$securedOrderBy = true;
95
+				$reconstructedOrderBys = [];
96
+			}
97
+			$orderByColumns = $this->orderByAnalyzer->analyzeOrderBy($orderBy);
98
+
99
+			// If we sort by a column, there is a high chance we will fetch the bean containing this column.
100
+			// Hence, we should add the table to the $additionalTablesFetch
101
+			foreach ($orderByColumns as $orderByColumn) {
102
+				if ($orderByColumn['type'] === 'colref') {
103
+					if ($orderByColumn['table'] !== null) {
104
+						$additionalTablesFetch[] = $orderByColumn['table'];
105
+					}
106
+					if ($securedOrderBy) {
107
+						$reconstructedOrderBys[] = ($orderByColumn['table'] !== null ? $connection->quoteIdentifier($orderByColumn['table']).'.' : '').$connection->quoteIdentifier($orderByColumn['column']).' '.$orderByColumn['direction'];
108
+					}
109
+				} elseif ($orderByColumn['type'] === 'expr') {
110
+					$sortColumnName = 'sort_column_'.$sortColumn;
111
+					$columnsList[] = $orderByColumn['expr'].' as '.$sortColumnName;
112
+					$columnDescList[] = [
113
+						'tableGroup' => null,
114
+					];
115
+					++$sortColumn;
116
+
117
+					if ($securedOrderBy) {
118
+						throw new TDBMInvalidArgumentException('Invalid ORDER BY column: "'.$orderByColumn['expr'].'". If you want to use expression in your ORDER BY clause, you must wrap them in a UncheckedOrderBy object. For instance: new UncheckedOrderBy("col1 + col2 DESC")');
119
+					}
120
+				}
121
+			}
122
+
123
+			if ($reconstructedOrderBy === null) {
124
+				$reconstructedOrderBy = implode(', ', $reconstructedOrderBys);
125
+			}
126
+		}
127
+
128
+		foreach ($additionalTablesFetch as $additionalTable) {
129
+			$relatedTables = $this->tdbmService->_getRelatedTablesByInheritance($additionalTable);
130
+			$tableGroupName = $this->getTableGroupName($relatedTables);
131
+			foreach ($relatedTables as $table) {
132
+				$tableGroups[$table] = $tableGroupName;
133
+			}
134
+			$allFetchedTables = array_merge($allFetchedTables, $relatedTables);
135
+		}
136
+
137
+		// Let's remove any duplicate
138
+		$allFetchedTables = array_flip(array_flip($allFetchedTables));
139
+
140
+		// Now, let's build the column list
141
+		foreach ($allFetchedTables as $table) {
142
+			foreach ($this->schema->getTable($table)->getColumns() as $column) {
143
+				$columnName = $column->getName();
144
+				$columnDescList[] = [
145
+					'as' => $table.'____'.$columnName,
146
+					'table' => $table,
147
+					'column' => $columnName,
148
+					'type' => $column->getType(),
149
+					'tableGroup' => $tableGroups[$table],
150
+				];
151
+				$columnsList[] = $connection->quoteIdentifier($table).'.'.$connection->quoteIdentifier($columnName).' as '.
152
+					$connection->quoteIdentifier($table.'____'.$columnName);
153
+			}
154
+		}
155
+
156
+		return [$columnDescList, $columnsList, $reconstructedOrderBy];
157
+	}
158
+
159
+	abstract protected function compute();
160
+
161
+	/**
162
+	 * Returns an identifier for the group of tables passed in parameter.
163
+	 *
164
+	 * @param string[] $relatedTables
165
+	 *
166
+	 * @return string
167
+	 */
168
+	protected function getTableGroupName(array $relatedTables)
169
+	{
170
+		sort($relatedTables);
171
+
172
+		return implode('_``_', $relatedTables);
173
+	}
174
+
175
+	public function getMagicSql() : string
176
+	{
177
+		if ($this->magicSql === null) {
178
+			$this->compute();
179
+		}
180
+
181
+		return $this->magicSql;
182
+	}
183
+
184
+	public function getMagicSqlCount() : string
185
+	{
186
+		if ($this->magicSqlCount === null) {
187
+			$this->compute();
188
+		}
189
+
190
+		return $this->magicSqlCount;
191
+	}
192
+
193
+	public function getColumnDescriptors() : array
194
+	{
195
+		if ($this->columnDescList === null) {
196
+			$this->compute();
197
+		}
198
+
199
+		return $this->columnDescList;
200
+	}
201
+
202
+	/**
203
+	 * Sets the ORDER BY directive executed in SQL.
204
+	 *
205
+	 * For instance:
206
+	 *
207
+	 *  $queryFactory->sort('label ASC, status DESC');
208
+	 *
209
+	 * **Important:** TDBM does its best to protect you from SQL injection. In particular, it will only allow column names in the "ORDER BY" clause. This means you are safe to pass input from the user directly in the ORDER BY parameter.
210
+	 * If you want to pass an expression to the ORDER BY clause, you will need to tell TDBM to stop checking for SQL injections. You do this by passing a `UncheckedOrderBy` object as a parameter:
211
+	 *
212
+	 *  $queryFactory->sort(new UncheckedOrderBy('RAND()'))
213
+	 *
214
+	 * @param string|UncheckedOrderBy|null $orderBy
215
+	 */
216
+	public function sort($orderBy)
217
+	{
218
+		$this->orderBy = $orderBy;
219
+		$this->magicSql = null;
220
+		$this->magicSqlCount = null;
221
+		$this->columnDescList = null;
222
+	}
223 223
 }
Please login to merge, or discard this patch.
src/Mouf/Database/TDBM/QueryFactory/FindObjectsFromSqlQueryFactory.php 2 patches
Indentation   +187 added lines, -187 removed lines patch added patch discarded remove patch
@@ -15,191 +15,191 @@
 block discarded – undo
15 15
  */
16 16
 class FindObjectsFromSqlQueryFactory extends AbstractQueryFactory
17 17
 {
18
-    private $mainTable;
19
-    private $from;
20
-    private $filterString;
21
-    private $cache;
22
-    private $cachePrefix;
23
-
24
-    public function __construct(string $mainTable, string $from, $filterString, $orderBy, TDBMService $tdbmService, Schema $schema, OrderByAnalyzer $orderByAnalyzer, SchemaAnalyzer $schemaAnalyzer, Cache $cache, string $cachePrefix)
25
-    {
26
-        parent::__construct($tdbmService, $schema, $orderByAnalyzer, $orderBy);
27
-        $this->mainTable = $mainTable;
28
-        $this->from = $from;
29
-        $this->filterString = $filterString;
30
-        $this->schemaAnalyzer = $schemaAnalyzer;
31
-        $this->cache = $cache;
32
-        $this->cachePrefix = $cachePrefix;
33
-    }
34
-
35
-    protected function compute()
36
-    {
37
-        $connection = $this->tdbmService->getConnection();
38
-
39
-        $columnsList = null;
40
-
41
-        $allFetchedTables = $this->tdbmService->_getRelatedTablesByInheritance($this->mainTable);
42
-
43
-        $columnDescList = [];
44
-
45
-        $tableGroupName = $this->getTableGroupName($allFetchedTables);
46
-
47
-        foreach ($this->schema->getTable($this->mainTable)->getColumns() as $column) {
48
-            $columnName = $column->getName();
49
-            $columnDescList[] = [
50
-                'as' => $columnName,
51
-                'table' => $this->mainTable,
52
-                'column' => $columnName,
53
-                'type' => $column->getType(),
54
-                'tableGroup' => $tableGroupName,
55
-            ];
56
-        }
57
-
58
-        $sql = 'SELECT DISTINCT '.implode(', ', array_map(function ($columnDesc) {
59
-            return $this->tdbmService->getConnection()->quoteIdentifier($this->mainTable).'.'.$this->tdbmService->getConnection()->quoteIdentifier($columnDesc['column']);
60
-        }, $columnDescList)).' FROM '.$this->from;
61
-
62
-        if (count($allFetchedTables) > 1) {
63
-            list($columnDescList, $columnsList, $orderString) = $this->getColumnsList($this->mainTable, [], $this->orderBy);
64
-        } elseif ($this->orderBy) {
65
-            list(, , $orderString) = $this->getColumnsList($this->mainTable, [], $this->orderBy);
66
-        }
67
-
68
-        // Let's compute the COUNT.
69
-        $pkColumnNames = $this->schema->getTable($this->mainTable)->getPrimaryKeyColumns();
70
-        $pkColumnNames = array_map(function ($pkColumn) {
71
-            return $this->tdbmService->getConnection()->quoteIdentifier($this->mainTable).'.'.$this->tdbmService->getConnection()->quoteIdentifier($pkColumn);
72
-        }, $pkColumnNames);
73
-
74
-        $countSql = 'SELECT COUNT(DISTINCT '.implode(', ', $pkColumnNames).') FROM '.$this->from;
75
-
76
-        if (!empty($this->filterString)) {
77
-            $sql .= ' WHERE '.$this->filterString;
78
-            $countSql .= ' WHERE '.$this->filterString;
79
-        }
80
-
81
-        if (!empty($orderString)) {
82
-            $sql .= ' ORDER BY '.$orderString;
83
-        }
84
-
85
-        if (stripos($countSql, 'GROUP BY') !== false) {
86
-            throw new TDBMException('Unsupported use of GROUP BY in SQL request.');
87
-        }
88
-
89
-        if ($columnsList !== null) {
90
-            $joinSql = '';
91
-            $parentFks = $this->getParentRelationshipForeignKeys($this->mainTable);
92
-            foreach ($parentFks as $fk) {
93
-                $joinSql .= sprintf(' JOIN %s ON (%s.%s = %s.%s)',
94
-                    $connection->quoteIdentifier($fk->getForeignTableName()),
95
-                    $connection->quoteIdentifier($fk->getLocalTableName()),
96
-                    $connection->quoteIdentifier($fk->getLocalColumns()[0]),
97
-                    $connection->quoteIdentifier($fk->getForeignTableName()),
98
-                    $connection->quoteIdentifier($fk->getForeignColumns()[0])
99
-                );
100
-            }
101
-
102
-            $childrenFks = $this->getChildrenRelationshipForeignKeys($this->mainTable);
103
-            foreach ($childrenFks as $fk) {
104
-                $joinSql .= sprintf(' LEFT JOIN %s ON (%s.%s = %s.%s)',
105
-                    $connection->quoteIdentifier($fk->getLocalTableName()),
106
-                    $connection->quoteIdentifier($fk->getForeignTableName()),
107
-                    $connection->quoteIdentifier($fk->getForeignColumns()[0]),
108
-                    $connection->quoteIdentifier($fk->getLocalTableName()),
109
-                    $connection->quoteIdentifier($fk->getLocalColumns()[0])
110
-                );
111
-            }
112
-
113
-            $sql = 'SELECT '.implode(', ', $columnsList).' FROM ('.$sql.') AS '.$this->mainTable.' '.$joinSql;
114
-            if (!empty($orderString)) {
115
-                $sql .= ' ORDER BY '.$orderString;
116
-            }
117
-        }
118
-
119
-        $this->magicSql = $sql;
120
-        $this->magicSqlCount = $countSql;
121
-        $this->columnDescList = $columnDescList;
122
-    }
123
-
124
-    /**
125
-     * @param string $tableName
126
-     *
127
-     * @return ForeignKeyConstraint[]
128
-     */
129
-    private function getParentRelationshipForeignKeys($tableName)
130
-    {
131
-        return $this->fromCache($this->cachePrefix.'_parentrelationshipfks_'.$tableName, function () use ($tableName) {
132
-            return $this->getParentRelationshipForeignKeysWithoutCache($tableName);
133
-        });
134
-    }
135
-
136
-    /**
137
-     * @param string $tableName
138
-     *
139
-     * @return ForeignKeyConstraint[]
140
-     */
141
-    private function getParentRelationshipForeignKeysWithoutCache($tableName)
142
-    {
143
-        $parentFks = [];
144
-        $currentTable = $tableName;
145
-        while ($currentFk = $this->schemaAnalyzer->getParentRelationship($currentTable)) {
146
-            $currentTable = $currentFk->getForeignTableName();
147
-            $parentFks[] = $currentFk;
148
-        }
149
-
150
-        return $parentFks;
151
-    }
152
-
153
-    /**
154
-     * @param string $tableName
155
-     *
156
-     * @return ForeignKeyConstraint[]
157
-     */
158
-    private function getChildrenRelationshipForeignKeys(string $tableName) : array
159
-    {
160
-        return $this->fromCache($this->cachePrefix.'_childrenrelationshipfks_'.$tableName, function () use ($tableName) {
161
-            return $this->getChildrenRelationshipForeignKeysWithoutCache($tableName);
162
-        });
163
-    }
164
-
165
-    /**
166
-     * @param string $tableName
167
-     *
168
-     * @return ForeignKeyConstraint[]
169
-     */
170
-    private function getChildrenRelationshipForeignKeysWithoutCache(string $tableName) : array
171
-    {
172
-        $children = $this->schemaAnalyzer->getChildrenRelationships($tableName);
173
-
174
-        if (!empty($children)) {
175
-            $fksTables = array_map(function (ForeignKeyConstraint $fk) {
176
-                return $this->getChildrenRelationshipForeignKeys($fk->getLocalTableName());
177
-            }, $children);
178
-
179
-            $fks = array_merge($children, call_user_func_array('array_merge', $fksTables));
180
-
181
-            return $fks;
182
-        } else {
183
-            return [];
184
-        }
185
-    }
186
-
187
-    /**
188
-     * Returns an item from cache or computes it using $closure and puts it in cache.
189
-     *
190
-     * @param string   $key
191
-     * @param callable $closure
192
-     *
193
-     * @return mixed
194
-     */
195
-    protected function fromCache(string $key, callable $closure)
196
-    {
197
-        $item = $this->cache->fetch($key);
198
-        if ($item === false) {
199
-            $item = $closure();
200
-            $this->cache->save($key, $item);
201
-        }
202
-
203
-        return $item;
204
-    }
18
+	private $mainTable;
19
+	private $from;
20
+	private $filterString;
21
+	private $cache;
22
+	private $cachePrefix;
23
+
24
+	public function __construct(string $mainTable, string $from, $filterString, $orderBy, TDBMService $tdbmService, Schema $schema, OrderByAnalyzer $orderByAnalyzer, SchemaAnalyzer $schemaAnalyzer, Cache $cache, string $cachePrefix)
25
+	{
26
+		parent::__construct($tdbmService, $schema, $orderByAnalyzer, $orderBy);
27
+		$this->mainTable = $mainTable;
28
+		$this->from = $from;
29
+		$this->filterString = $filterString;
30
+		$this->schemaAnalyzer = $schemaAnalyzer;
31
+		$this->cache = $cache;
32
+		$this->cachePrefix = $cachePrefix;
33
+	}
34
+
35
+	protected function compute()
36
+	{
37
+		$connection = $this->tdbmService->getConnection();
38
+
39
+		$columnsList = null;
40
+
41
+		$allFetchedTables = $this->tdbmService->_getRelatedTablesByInheritance($this->mainTable);
42
+
43
+		$columnDescList = [];
44
+
45
+		$tableGroupName = $this->getTableGroupName($allFetchedTables);
46
+
47
+		foreach ($this->schema->getTable($this->mainTable)->getColumns() as $column) {
48
+			$columnName = $column->getName();
49
+			$columnDescList[] = [
50
+				'as' => $columnName,
51
+				'table' => $this->mainTable,
52
+				'column' => $columnName,
53
+				'type' => $column->getType(),
54
+				'tableGroup' => $tableGroupName,
55
+			];
56
+		}
57
+
58
+		$sql = 'SELECT DISTINCT '.implode(', ', array_map(function ($columnDesc) {
59
+			return $this->tdbmService->getConnection()->quoteIdentifier($this->mainTable).'.'.$this->tdbmService->getConnection()->quoteIdentifier($columnDesc['column']);
60
+		}, $columnDescList)).' FROM '.$this->from;
61
+
62
+		if (count($allFetchedTables) > 1) {
63
+			list($columnDescList, $columnsList, $orderString) = $this->getColumnsList($this->mainTable, [], $this->orderBy);
64
+		} elseif ($this->orderBy) {
65
+			list(, , $orderString) = $this->getColumnsList($this->mainTable, [], $this->orderBy);
66
+		}
67
+
68
+		// Let's compute the COUNT.
69
+		$pkColumnNames = $this->schema->getTable($this->mainTable)->getPrimaryKeyColumns();
70
+		$pkColumnNames = array_map(function ($pkColumn) {
71
+			return $this->tdbmService->getConnection()->quoteIdentifier($this->mainTable).'.'.$this->tdbmService->getConnection()->quoteIdentifier($pkColumn);
72
+		}, $pkColumnNames);
73
+
74
+		$countSql = 'SELECT COUNT(DISTINCT '.implode(', ', $pkColumnNames).') FROM '.$this->from;
75
+
76
+		if (!empty($this->filterString)) {
77
+			$sql .= ' WHERE '.$this->filterString;
78
+			$countSql .= ' WHERE '.$this->filterString;
79
+		}
80
+
81
+		if (!empty($orderString)) {
82
+			$sql .= ' ORDER BY '.$orderString;
83
+		}
84
+
85
+		if (stripos($countSql, 'GROUP BY') !== false) {
86
+			throw new TDBMException('Unsupported use of GROUP BY in SQL request.');
87
+		}
88
+
89
+		if ($columnsList !== null) {
90
+			$joinSql = '';
91
+			$parentFks = $this->getParentRelationshipForeignKeys($this->mainTable);
92
+			foreach ($parentFks as $fk) {
93
+				$joinSql .= sprintf(' JOIN %s ON (%s.%s = %s.%s)',
94
+					$connection->quoteIdentifier($fk->getForeignTableName()),
95
+					$connection->quoteIdentifier($fk->getLocalTableName()),
96
+					$connection->quoteIdentifier($fk->getLocalColumns()[0]),
97
+					$connection->quoteIdentifier($fk->getForeignTableName()),
98
+					$connection->quoteIdentifier($fk->getForeignColumns()[0])
99
+				);
100
+			}
101
+
102
+			$childrenFks = $this->getChildrenRelationshipForeignKeys($this->mainTable);
103
+			foreach ($childrenFks as $fk) {
104
+				$joinSql .= sprintf(' LEFT JOIN %s ON (%s.%s = %s.%s)',
105
+					$connection->quoteIdentifier($fk->getLocalTableName()),
106
+					$connection->quoteIdentifier($fk->getForeignTableName()),
107
+					$connection->quoteIdentifier($fk->getForeignColumns()[0]),
108
+					$connection->quoteIdentifier($fk->getLocalTableName()),
109
+					$connection->quoteIdentifier($fk->getLocalColumns()[0])
110
+				);
111
+			}
112
+
113
+			$sql = 'SELECT '.implode(', ', $columnsList).' FROM ('.$sql.') AS '.$this->mainTable.' '.$joinSql;
114
+			if (!empty($orderString)) {
115
+				$sql .= ' ORDER BY '.$orderString;
116
+			}
117
+		}
118
+
119
+		$this->magicSql = $sql;
120
+		$this->magicSqlCount = $countSql;
121
+		$this->columnDescList = $columnDescList;
122
+	}
123
+
124
+	/**
125
+	 * @param string $tableName
126
+	 *
127
+	 * @return ForeignKeyConstraint[]
128
+	 */
129
+	private function getParentRelationshipForeignKeys($tableName)
130
+	{
131
+		return $this->fromCache($this->cachePrefix.'_parentrelationshipfks_'.$tableName, function () use ($tableName) {
132
+			return $this->getParentRelationshipForeignKeysWithoutCache($tableName);
133
+		});
134
+	}
135
+
136
+	/**
137
+	 * @param string $tableName
138
+	 *
139
+	 * @return ForeignKeyConstraint[]
140
+	 */
141
+	private function getParentRelationshipForeignKeysWithoutCache($tableName)
142
+	{
143
+		$parentFks = [];
144
+		$currentTable = $tableName;
145
+		while ($currentFk = $this->schemaAnalyzer->getParentRelationship($currentTable)) {
146
+			$currentTable = $currentFk->getForeignTableName();
147
+			$parentFks[] = $currentFk;
148
+		}
149
+
150
+		return $parentFks;
151
+	}
152
+
153
+	/**
154
+	 * @param string $tableName
155
+	 *
156
+	 * @return ForeignKeyConstraint[]
157
+	 */
158
+	private function getChildrenRelationshipForeignKeys(string $tableName) : array
159
+	{
160
+		return $this->fromCache($this->cachePrefix.'_childrenrelationshipfks_'.$tableName, function () use ($tableName) {
161
+			return $this->getChildrenRelationshipForeignKeysWithoutCache($tableName);
162
+		});
163
+	}
164
+
165
+	/**
166
+	 * @param string $tableName
167
+	 *
168
+	 * @return ForeignKeyConstraint[]
169
+	 */
170
+	private function getChildrenRelationshipForeignKeysWithoutCache(string $tableName) : array
171
+	{
172
+		$children = $this->schemaAnalyzer->getChildrenRelationships($tableName);
173
+
174
+		if (!empty($children)) {
175
+			$fksTables = array_map(function (ForeignKeyConstraint $fk) {
176
+				return $this->getChildrenRelationshipForeignKeys($fk->getLocalTableName());
177
+			}, $children);
178
+
179
+			$fks = array_merge($children, call_user_func_array('array_merge', $fksTables));
180
+
181
+			return $fks;
182
+		} else {
183
+			return [];
184
+		}
185
+	}
186
+
187
+	/**
188
+	 * Returns an item from cache or computes it using $closure and puts it in cache.
189
+	 *
190
+	 * @param string   $key
191
+	 * @param callable $closure
192
+	 *
193
+	 * @return mixed
194
+	 */
195
+	protected function fromCache(string $key, callable $closure)
196
+	{
197
+		$item = $this->cache->fetch($key);
198
+		if ($item === false) {
199
+			$item = $closure();
200
+			$this->cache->save($key, $item);
201
+		}
202
+
203
+		return $item;
204
+	}
205 205
 }
Please login to merge, or discard this patch.
Spacing   +7 added lines, -7 removed lines patch added patch discarded remove patch
@@ -55,19 +55,19 @@  discard block
 block discarded – undo
55 55
             ];
56 56
         }
57 57
 
58
-        $sql = 'SELECT DISTINCT '.implode(', ', array_map(function ($columnDesc) {
58
+        $sql = 'SELECT DISTINCT '.implode(', ', array_map(function($columnDesc) {
59 59
             return $this->tdbmService->getConnection()->quoteIdentifier($this->mainTable).'.'.$this->tdbmService->getConnection()->quoteIdentifier($columnDesc['column']);
60 60
         }, $columnDescList)).' FROM '.$this->from;
61 61
 
62
-        if (count($allFetchedTables) > 1) {
62
+        if (count($allFetchedTables)>1) {
63 63
             list($columnDescList, $columnsList, $orderString) = $this->getColumnsList($this->mainTable, [], $this->orderBy);
64 64
         } elseif ($this->orderBy) {
65
-            list(, , $orderString) = $this->getColumnsList($this->mainTable, [], $this->orderBy);
65
+            list(,, $orderString) = $this->getColumnsList($this->mainTable, [], $this->orderBy);
66 66
         }
67 67
 
68 68
         // Let's compute the COUNT.
69 69
         $pkColumnNames = $this->schema->getTable($this->mainTable)->getPrimaryKeyColumns();
70
-        $pkColumnNames = array_map(function ($pkColumn) {
70
+        $pkColumnNames = array_map(function($pkColumn) {
71 71
             return $this->tdbmService->getConnection()->quoteIdentifier($this->mainTable).'.'.$this->tdbmService->getConnection()->quoteIdentifier($pkColumn);
72 72
         }, $pkColumnNames);
73 73
 
@@ -128,7 +128,7 @@  discard block
 block discarded – undo
128 128
      */
129 129
     private function getParentRelationshipForeignKeys($tableName)
130 130
     {
131
-        return $this->fromCache($this->cachePrefix.'_parentrelationshipfks_'.$tableName, function () use ($tableName) {
131
+        return $this->fromCache($this->cachePrefix.'_parentrelationshipfks_'.$tableName, function() use ($tableName) {
132 132
             return $this->getParentRelationshipForeignKeysWithoutCache($tableName);
133 133
         });
134 134
     }
@@ -157,7 +157,7 @@  discard block
 block discarded – undo
157 157
      */
158 158
     private function getChildrenRelationshipForeignKeys(string $tableName) : array
159 159
     {
160
-        return $this->fromCache($this->cachePrefix.'_childrenrelationshipfks_'.$tableName, function () use ($tableName) {
160
+        return $this->fromCache($this->cachePrefix.'_childrenrelationshipfks_'.$tableName, function() use ($tableName) {
161 161
             return $this->getChildrenRelationshipForeignKeysWithoutCache($tableName);
162 162
         });
163 163
     }
@@ -172,7 +172,7 @@  discard block
 block discarded – undo
172 172
         $children = $this->schemaAnalyzer->getChildrenRelationships($tableName);
173 173
 
174 174
         if (!empty($children)) {
175
-            $fksTables = array_map(function (ForeignKeyConstraint $fk) {
175
+            $fksTables = array_map(function(ForeignKeyConstraint $fk) {
176 176
                 return $this->getChildrenRelationshipForeignKeys($fk->getLocalTableName());
177 177
             }, $children);
178 178
 
Please login to merge, or discard this patch.