Completed
Push — master ( 790593...516252 )
by Fabien
12:05
created
Classes/DataHandler/CoreDataHandler.php 2 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -94,7 +94,7 @@
 block discarded – undo
94 94
      *
95 95
      * @param Content $content
96 96
      * @param string $target
97
-     * @return bool
97
+     * @return boolean|null
98 98
      */
99 99
     public function processCopy(Content $content, $target)
100 100
     {
Please login to merge, or discard this patch.
Indentation   +135 added lines, -135 removed lines patch added patch discarded remove patch
@@ -18,140 +18,140 @@
 block discarded – undo
18 18
 class CoreDataHandler extends AbstractDataHandler
19 19
 {
20 20
 
21
-    /**
22
-     * @var array
23
-     */
24
-    protected $dataHandler;
25
-
26
-    /**
27
-     * Process Content with action "update".
28
-     *
29
-     * @param Content $content
30
-     * @throws \Exception
31
-     * @return bool
32
-     */
33
-    public function processUpdate(Content $content)
34
-    {
35
-
36
-        $values = [];
37
-
38
-        // Check the field to be updated exists
39
-        foreach ($content->toArray() as $fieldName => $value) {
40
-            if (!Tca::table($content->getDataType())->hasField($fieldName)) {
41
-                $message = sprintf('It looks field "%s" does not exist for data type "%s"', $fieldName, $content->getDataType());
42
-                throw new \Exception($message, 1390668497);
43
-            }
44
-
45
-            // Flatten value if array given which is required for the DataHandler.
46
-            if (is_array($value)) {
47
-                $value = implode(',', $value);
48
-            }
49
-            $values[$fieldName] = $value;
50
-        }
51
-
52
-        $data[$content->getDataType()][$content->getUid()] = $values;
53
-
54
-        $dataHandler = $this->getDataHandler();
55
-        $dataHandler->start($data, array());
56
-        $dataHandler->process_datamap();
57
-        $this->errorMessages = $dataHandler->errorLog;
58
-
59
-        // Returns true is log does not contain errors.
60
-        return empty($dataHandler->errorLog);
61
-    }
62
-
63
-    /**
64
-     * Process Content with action "remove".
65
-     *
66
-     * @param Content $content
67
-     * @return bool
68
-     */
69
-    public function processRemove(Content $content)
70
-    {
71
-
72
-        // Build command
73
-        $cmd[$content->getDataType()][$content->getUid()]['delete'] = 1;
74
-
75
-        /** @var $dataHandler \TYPO3\CMS\Core\DataHandling\DataHandler */
76
-        $dataHandler = $this->getDataHandler();
77
-        $dataHandler->start([], $cmd);
78
-        $dataHandler->process_datamap();
79
-        $dataHandler->process_cmdmap();
80
-        $this->errorMessages = $dataHandler->errorLog;
81
-
82
-        // Returns true is log does not contain errors.
83
-        return empty($dataHandler->errorLog);
84
-    }
85
-
86
-    /**
87
-     * Process Content with action "copy".
88
-     *
89
-     * @param Content $content
90
-     * @param string $target
91
-     * @return bool
92
-     */
93
-    public function processCopy(Content $content, $target)
94
-    {
95
-        // TODO: Implement processCopy() method.
96
-    }
97
-
98
-    /**
99
-     * Process Content with action "move".
100
-     * The $target corresponds to the pid to move the records to.
101
-     * It can also be a negative value in case of sorting. The negative value would be the uid of its predecessor.
102
-     *
103
-     * @param Content $content
104
-     * @param int $target corresponds
105
-     * @return bool
106
-     */
107
-    public function processMove(Content $content, $target)
108
-    {
109
-
110
-        // Build command
111
-        $cmd[$content->getDataType()][$content->getUid()]['move'] = $target;
112
-
113
-        /** @var $dataHandler \TYPO3\CMS\Core\DataHandling\DataHandler */
114
-        $dataHandler = $this->getDataHandler();
115
-        $dataHandler->start([], $cmd);
116
-        $dataHandler->process_datamap();
117
-        $dataHandler->process_cmdmap();
118
-        $this->errorMessages = $dataHandler->errorLog;
119
-
120
-        // Returns true is log does not contain errors.
121
-        return empty($dataHandler->errorLog);
122
-    }
123
-
124
-    /**
125
-     * Process Content with action "localize".
126
-     *
127
-     * @param Content $content
128
-     * @param int $language
129
-     * @return bool
130
-     */
131
-    public function processLocalize(Content $content, $language)
132
-    {
133
-
134
-        $command[$content->getDataType()][$content->getUid()]['localize'] = $language;
135
-
136
-        $dataHandler = $this->getDataHandler();
137
-        $dataHandler->start([], $command);
138
-        $dataHandler->process_datamap();
139
-        $dataHandler->process_cmdmap();
140
-        $this->errorMessages = $dataHandler->errorLog;
141
-
142
-        // Returns true is log does not contain errors.
143
-        return empty($dataHandler->errorLog);
144
-    }
145
-
146
-    /**
147
-     * @return \TYPO3\CMS\Core\DataHandling\DataHandler
148
-     */
149
-    protected function getDataHandler()
150
-    {
151
-        if (!$this->dataHandler) {
152
-            $this->dataHandler = GeneralUtility::makeInstance('TYPO3\CMS\Core\DataHandling\DataHandler');
153
-        }
154
-        return $this->dataHandler;
155
-    }
21
+	/**
22
+	 * @var array
23
+	 */
24
+	protected $dataHandler;
25
+
26
+	/**
27
+	 * Process Content with action "update".
28
+	 *
29
+	 * @param Content $content
30
+	 * @throws \Exception
31
+	 * @return bool
32
+	 */
33
+	public function processUpdate(Content $content)
34
+	{
35
+
36
+		$values = [];
37
+
38
+		// Check the field to be updated exists
39
+		foreach ($content->toArray() as $fieldName => $value) {
40
+			if (!Tca::table($content->getDataType())->hasField($fieldName)) {
41
+				$message = sprintf('It looks field "%s" does not exist for data type "%s"', $fieldName, $content->getDataType());
42
+				throw new \Exception($message, 1390668497);
43
+			}
44
+
45
+			// Flatten value if array given which is required for the DataHandler.
46
+			if (is_array($value)) {
47
+				$value = implode(',', $value);
48
+			}
49
+			$values[$fieldName] = $value;
50
+		}
51
+
52
+		$data[$content->getDataType()][$content->getUid()] = $values;
53
+
54
+		$dataHandler = $this->getDataHandler();
55
+		$dataHandler->start($data, array());
56
+		$dataHandler->process_datamap();
57
+		$this->errorMessages = $dataHandler->errorLog;
58
+
59
+		// Returns true is log does not contain errors.
60
+		return empty($dataHandler->errorLog);
61
+	}
62
+
63
+	/**
64
+	 * Process Content with action "remove".
65
+	 *
66
+	 * @param Content $content
67
+	 * @return bool
68
+	 */
69
+	public function processRemove(Content $content)
70
+	{
71
+
72
+		// Build command
73
+		$cmd[$content->getDataType()][$content->getUid()]['delete'] = 1;
74
+
75
+		/** @var $dataHandler \TYPO3\CMS\Core\DataHandling\DataHandler */
76
+		$dataHandler = $this->getDataHandler();
77
+		$dataHandler->start([], $cmd);
78
+		$dataHandler->process_datamap();
79
+		$dataHandler->process_cmdmap();
80
+		$this->errorMessages = $dataHandler->errorLog;
81
+
82
+		// Returns true is log does not contain errors.
83
+		return empty($dataHandler->errorLog);
84
+	}
85
+
86
+	/**
87
+	 * Process Content with action "copy".
88
+	 *
89
+	 * @param Content $content
90
+	 * @param string $target
91
+	 * @return bool
92
+	 */
93
+	public function processCopy(Content $content, $target)
94
+	{
95
+		// TODO: Implement processCopy() method.
96
+	}
97
+
98
+	/**
99
+	 * Process Content with action "move".
100
+	 * The $target corresponds to the pid to move the records to.
101
+	 * It can also be a negative value in case of sorting. The negative value would be the uid of its predecessor.
102
+	 *
103
+	 * @param Content $content
104
+	 * @param int $target corresponds
105
+	 * @return bool
106
+	 */
107
+	public function processMove(Content $content, $target)
108
+	{
109
+
110
+		// Build command
111
+		$cmd[$content->getDataType()][$content->getUid()]['move'] = $target;
112
+
113
+		/** @var $dataHandler \TYPO3\CMS\Core\DataHandling\DataHandler */
114
+		$dataHandler = $this->getDataHandler();
115
+		$dataHandler->start([], $cmd);
116
+		$dataHandler->process_datamap();
117
+		$dataHandler->process_cmdmap();
118
+		$this->errorMessages = $dataHandler->errorLog;
119
+
120
+		// Returns true is log does not contain errors.
121
+		return empty($dataHandler->errorLog);
122
+	}
123
+
124
+	/**
125
+	 * Process Content with action "localize".
126
+	 *
127
+	 * @param Content $content
128
+	 * @param int $language
129
+	 * @return bool
130
+	 */
131
+	public function processLocalize(Content $content, $language)
132
+	{
133
+
134
+		$command[$content->getDataType()][$content->getUid()]['localize'] = $language;
135
+
136
+		$dataHandler = $this->getDataHandler();
137
+		$dataHandler->start([], $command);
138
+		$dataHandler->process_datamap();
139
+		$dataHandler->process_cmdmap();
140
+		$this->errorMessages = $dataHandler->errorLog;
141
+
142
+		// Returns true is log does not contain errors.
143
+		return empty($dataHandler->errorLog);
144
+	}
145
+
146
+	/**
147
+	 * @return \TYPO3\CMS\Core\DataHandling\DataHandler
148
+	 */
149
+	protected function getDataHandler()
150
+	{
151
+		if (!$this->dataHandler) {
152
+			$this->dataHandler = GeneralUtility::makeInstance('TYPO3\CMS\Core\DataHandling\DataHandler');
153
+		}
154
+		return $this->dataHandler;
155
+	}
156 156
 
157 157
 }
Please login to merge, or discard this patch.
Classes/Domain/Model/Content.php 3 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -385,7 +385,7 @@
 block discarded – undo
385 385
     /**
386 386
      * Return the properties of this object.
387 387
      *
388
-     * @return array
388
+     * @return string[]
389 389
      */
390 390
     public function toFields()
391 391
     {
Please login to merge, or discard this patch.
Indentation   +445 added lines, -445 removed lines patch added patch discarded remove patch
@@ -23,450 +23,450 @@
 block discarded – undo
23 23
 class Content implements \ArrayAccess
24 24
 {
25 25
 
26
-    /**
27
-     * @var int
28
-     */
29
-    protected $uid;
30
-
31
-    /**
32
-     * @var string
33
-     */
34
-    protected $dataType;
35
-
36
-    /**
37
-     * Constructor for a Content object.
38
-     *
39
-     * @param string $dataType will basically correspond to a table name, e.g fe_users, tt_content, ...
40
-     * @param array $contentData
41
-     * @return \Fab\Vidi\Domain\Model\Content
42
-     * @throws \InvalidArgumentException
43
-     * @throws \Fab\Vidi\Exception\NotExistingClassException
44
-     */
45
-    public function __construct($dataType, array $contentData = array())
46
-    {
47
-
48
-        $this->dataType = $dataType;
49
-        $this->uid = empty($contentData['uid']) ? null : (int)$contentData['uid'];
50
-
51
-        /** @var \Fab\Vidi\Tca\TableService $table */
52
-        $table = Tca::table($dataType);
53
-
54
-        // Initialize the array containing the allowed fields to be filled-in.
55
-        $fields = array('pid');
56
-
57
-        // If a creation time stamp has been defined for this data type.
58
-        if ($table->getTimeCreationField()) {
59
-            $fields[] = $table->getTimeCreationField();
60
-        }
61
-
62
-        // If an update time stamp has been defined for this data type.
63
-        if ($table->getTimeModificationField()) {
64
-            $fields[] = $table->getTimeModificationField();
65
-        }
66
-
67
-        // Merge the other fields allowed for this data type.
68
-        $fields = array_merge($fields, $table->getFields());
69
-
70
-        // Fetch excluded fields from the grid.
71
-        if ($this->isBackendMode()) {
72
-            $fields = $this->filterForConfiguration($fields);
73
-            $fields = $this->filterForBackendUser($fields);
74
-        }
75
-
76
-        // Get column to be displayed
77
-        foreach ($fields as $fieldName) {
78
-            if (array_key_exists($fieldName, $contentData)) {
79
-                $propertyName = Field::name($fieldName)->of($dataType)->toPropertyName();
80
-                $this->$propertyName = $contentData[$fieldName];
81
-            }
82
-        }
83
-    }
84
-
85
-    /**
86
-     * Dispatches magic methods (findBy[Property]())
87
-     *
88
-     * @param string $methodName The name of the magic method
89
-     * @param string $arguments The arguments of the magic method
90
-     * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\UnsupportedMethodException
91
-     * @return mixed
92
-     * @api
93
-     */
94
-    public function __call($methodName, $arguments)
95
-    {
96
-        $value = null;
97
-        if (substr($methodName, 0, 3) === 'get' && strlen($methodName) > 4) {
98
-            $propertyName = strtolower(substr(substr($methodName, 3), 0, 1)) . substr(substr($methodName, 3), 1);
99
-
100
-            $fieldName = Property::name($propertyName)->of($this)->toFieldName();
101
-            $field = Tca::table($this->dataType)->field($fieldName);
102
-
103
-            $value = $this->$propertyName;
104
-
105
-            // true means it is a relation and it is not yet resolved.
106
-            if ($this->hasRelation($propertyName) && is_scalar($this->$propertyName)) {
107
-                $value = $this->resolveRelation($propertyName);
108
-            } elseif ($field->getType() === FieldType::RADIO || $field->getType() === FieldType::SELECT) {
109
-
110
-                // Attempt to convert the value into a label for radio and select fields.
111
-                $label = Tca::table($this->getDataType())->field($fieldName)->getLabelForItem($value);
112
-                if ($label) {
113
-                    $value = $label;
114
-                }
115
-            }
116
-
117
-        } elseif (substr($methodName, 0, 3) === 'set' && strlen($methodName) > 4 && isset($arguments[0])) {
118
-            $propertyName = strtolower(substr(substr($methodName, 3), 0, 1)) . substr(substr($methodName, 3), 1);
119
-            $this->$propertyName = $arguments[0];
120
-        }
121
-        return $value;
122
-    }
123
-
124
-    /**
125
-     * Tell whether the property has a relation.
126
-     *
127
-     * @param string $propertyName
128
-     * @return bool
129
-     */
130
-    protected function hasRelation($propertyName)
131
-    {
132
-        $fieldName = Property::name($propertyName)->of($this)->toFieldName();
133
-        return Tca::table($this->dataType)->field($fieldName)->hasRelation();
134
-    }
135
-
136
-    /**
137
-     * Try to "resolve" the property whether it has a relation.
138
-     * If the property has not relation it simply returns the same value.
139
-     *
140
-     * @throws \RuntimeException
141
-     * @param string $propertyName
142
-     * @return mixed
143
-     */
144
-    protected function resolveRelation($propertyName)
145
-    {
146
-
147
-        // Convert property name to field name and get the foreign data type.
148
-        $fieldName = Property::name($propertyName)->of($this)->toFieldName();
149
-        $foreignDataType = Tca::table($this->dataType)->field($fieldName)->relationDataType();
150
-
151
-        // Get the foreign repository instance form the factory
152
-        /** @var \Fab\Vidi\Domain\Repository\ContentRepository $foreignContentRepository */
153
-        $foreignContentRepository = ContentRepositoryFactory::getInstance($foreignDataType, $fieldName);
154
-
155
-        if (Tca::table($this->dataType)->field($fieldName)->hasRelationWithCommaSeparatedValues()) {
156
-
157
-            // Fetch values from repository
158
-            $values = GeneralUtility::trimExplode(',', $this->$propertyName);
159
-            $this->$propertyName = $foreignContentRepository->findIn('uid', $values);
160
-        } elseif (Tca::table($this->dataType)->field($fieldName)->hasMany()) {
161
-            // Include relation many-to-many and one-to-many
162
-            // Tca::table($this->dataType)->field($fieldName)->hasRelationOneToMany()
163
-            // Tca::table($this->dataType)->field($fieldName)->hasRelationManyToMany()
164
-
165
-            $foreignFieldName = Tca::table($this->dataType)->field($fieldName)->getForeignField();
166
-            if (empty($foreignFieldName)) {
167
-                $message = sprintf('Missing "foreign_field" key for field "%s" in table "%s".',
168
-                    $fieldName,
169
-                    $this->dataType
170
-                );
171
-                throw new \RuntimeException($message, 1376149186);
172
-            }
173
-
174
-            // Fetch values from repository.
175
-            $foreignPropertyName = Field::name($foreignFieldName)->of($this)->toPropertyName();
176
-            $findByProperty = 'findBy' . ucfirst($foreignPropertyName);
177
-
178
-            // Date picker (type == group) are special fields because property path must contain the table name
179
-            // to determine the relation type. Example for sys_category, property path will look like "items.sys_file"
180
-            $propertyValue = $this->uid;
181
-            if (Tca::table($foreignDataType)->field($foreignFieldName)->isGroup()) {
182
-                $propertyValue = $this->dataType . '.' . $this->uid;
183
-            }
184
-
185
-            $this->$propertyName = $foreignContentRepository->$findByProperty($propertyValue);
186
-
187
-        } elseif (Tca::table($this->dataType)->field($fieldName)->hasOne()) {
188
-
189
-            $fieldConfiguration = Tca::table($this->dataType)->field($fieldName)->getConfiguration();
190
-
191
-            // First case, we are on the "good side" of the relation, just query the repository
192
-            if (empty($fieldConfiguration['foreign_field'])) {
193
-                $this->$propertyName = $foreignContentRepository->findByUid($this->$propertyName);
194
-            } else {
195
-                // Second case, we are the "bad side" of the relation, query the foreign repository
196
-                // e.g. in case of one-to-one relation.
197
-
198
-                // We must query the opposite side to get the identifier of the foreign object.
199
-                $foreignDataType = Tca::table($this->dataType)->field($fieldName)->getForeignTable();
200
-                $foreignField = Tca::table($this->dataType)->field($fieldName)->getForeignField();
201
-                $foreignContentRepository = ContentRepositoryFactory::getInstance($foreignDataType);
202
-                $find = 'findOneBy' . GeneralUtility::underscoredToUpperCamelCase($foreignField);
203
-
204
-                /** @var Content $foreignObject */
205
-                $this->$propertyName = $foreignContentRepository->$find($this->getUid());
206
-            }
207
-
208
-        }
209
-        return $this->$propertyName;
210
-    }
211
-
212
-    /**
213
-     * @return int
214
-     */
215
-    public function getUid()
216
-    {
217
-        return $this->uid;
218
-    }
219
-
220
-    /**
221
-     * @return string
222
-     */
223
-    public function getDataType()
224
-    {
225
-        return $this->dataType;
226
-    }
227
-
228
-    /**
229
-     * Whether a offset exists
230
-     *
231
-     * @link http://php.net/manual/en/arrayaccess.offsetexists.php
232
-     * @param mixed $offset
233
-     * @return boolean true on success or false on failure.
234
-     * @throws \RuntimeException
235
-     * @throws \InvalidArgumentException
236
-     */
237
-    public function offsetExists($offset)
238
-    {
239
-        $offset = Field::name($offset)->of($this)->toPropertyName();
240
-        return isset($this->$offset);
241
-    }
242
-
243
-    /**
244
-     * Offset to retrieve
245
-     *
246
-     * @link http://php.net/manual/en/arrayaccess.offsetget.php
247
-     * @param mixed $offset
248
-     * @return mixed Can return all value types.
249
-     * @throws \RuntimeException
250
-     * @throws \InvalidArgumentException
251
-     */
252
-    public function offsetGet($offset)
253
-    {
254
-        $offset = Field::name($offset)->of($this)->toPropertyName();
255
-        $getter = 'get' . ucfirst($offset);
256
-        return $this->$getter();
257
-    }
258
-
259
-    /**
260
-     * Offset to set
261
-     *
262
-     * @link http://php.net/manual/en/arrayaccess.offsetset.php
263
-     * @param mixed $offset
264
-     * @param mixed $value
265
-     * @return $this
266
-     * @throws \RuntimeException
267
-     * @throws \InvalidArgumentException
268
-     */
269
-    public function offsetSet($offset, $value)
270
-    {
271
-        $offset = Field::name($offset)->of($this)->toPropertyName();
272
-        $setter = 'set' . ucfirst($offset);
273
-        $this->$setter($value);
274
-        return $this;
275
-    }
276
-
277
-    /**
278
-     * Offset to unset
279
-     *
280
-     * @link http://php.net/manual/en/arrayaccess.offsetunset.php
281
-     * @param mixed $offset
282
-     * @throws NotImplementedException
283
-     * @return void
284
-     */
285
-    public function offsetUnset($offset)
286
-    {
287
-        $message = 'Un-setting value for Array object is not supported';
288
-        throw new NotImplementedException($message, 1376132306);
289
-    }
290
-
291
-    /**
292
-     * Convert this to array
293
-     *
294
-     * @return array
295
-     * @throws \InvalidArgumentException
296
-     */
297
-    public function toArray()
298
-    {
299
-        $result['uid'] = $this->uid;
300
-        $propertiesAndValues = json_decode(json_encode($this), true);
301
-
302
-        foreach ($propertiesAndValues as $propertyName => $value) {
303
-            $fieldName = Property::name($propertyName)->of($this)->toFieldName();
304
-            $result[$fieldName] = $value;
305
-        }
306
-
307
-        return $result;
308
-    }
309
-
310
-    /**
311
-     * Convert this object to an array containing the resolved values.
312
-     *
313
-     * @param bool $resolveRelations
314
-     * @return array
315
-     * @throws \Exception
316
-     */
317
-    public function toValues($resolveRelations = true)
318
-    {
319
-        $result['uid'] = $this->uid;
320
-        $propertiesAndValues = json_decode(json_encode($this), true);
321
-
322
-        foreach ($propertiesAndValues as $propertyName => $value) {
323
-            $fieldName = Property::name($propertyName)->of($this)->toFieldName();
324
-
325
-            $result[$fieldName] = $value;
326
-            if ($resolveRelations) {
327
-                $field = Tca::table($this->dataType)->field($fieldName);
328
-
329
-                $resolvedValue = '';
330
-                if ($field->getType() === FieldType::FILE) {
331
-
332
-                    if ($field->hasMany()) {
333
-                        $files = FileReferenceService::getInstance()->findReferencedBy($propertyName, $this);
334
-
335
-                        $resolvedValue = [];
336
-                        foreach ($files as $file) {
337
-                            $resolvedValue[] = $file->getIdentifier();
338
-                        }
339
-                    } else {
340
-                        $files = FileReferenceService::getInstance()->findReferencedBy($propertyName, $this);
341
-                        if (!empty($files)) {
342
-                            $resolvedValue = current($files)->getIdentifier();
343
-                        }
344
-                    }
345
-
346
-                    // Reset value
347
-                    $result[$fieldName] = $resolvedValue;
348
-
349
-                } elseif (Tca::table($this->dataType)->field($fieldName)->hasRelation()) {
350
-                    $objects = $this[$fieldName];
351
-                    if (is_array($objects)) {
352
-                        $resolvedValue = [];
353
-                        foreach ($objects as $object) {
354
-                            /** @var $object Content */
355
-                            $labelField = Tca::table($object->getDataType())->getLabelField();
356
-                            $resolvedValue[] = $object[$labelField];
357
-                        }
358
-                    } elseif ($objects instanceof Content) {
359
-                        $labelField = Tca::table($objects->getDataType())->getLabelField();
360
-                        $resolvedValue = $objects[$labelField];
361
-                    }
362
-
363
-                    // Reset value
364
-                    $result[$fieldName] = $resolvedValue;
365
-                }
366
-            }
367
-        }
368
-
369
-        return $result;
370
-    }
371
-
372
-    /**
373
-     * Return the properties of this object.
374
-     *
375
-     * @return array
376
-     */
377
-    public function toProperties()
378
-    {
379
-        $result[] = 'uid';
380
-        $propertiesAndValues = json_decode(json_encode($this), true);
381
-
382
-        foreach ($propertiesAndValues as $propertyName => $value) {
383
-            $result[] = $propertyName;
384
-        }
385
-        return $result;
386
-    }
387
-
388
-    /**
389
-     * Return the properties of this object.
390
-     *
391
-     * @return array
392
-     */
393
-    public function toFields()
394
-    {
395
-        $result[] = 'uid';
396
-        $propertiesAndValues = json_decode(json_encode($this), true);
397
-
398
-        foreach ($propertiesAndValues as $propertyName => $value) {
399
-            $result[] = Property::name($propertyName)->of($this)->toFieldName();
400
-        }
401
-
402
-        return $result;
403
-    }
404
-
405
-    /**
406
-     * @return string
407
-     */
408
-    public function __toString()
409
-    {
410
-        $labelField = Tca::table($this->dataType)->getLabelField();
411
-        return $this[$labelField];
412
-    }
413
-
414
-    /**
415
-     * Remove fields according to BE User permission.
416
-     *
417
-     * @param $fields
418
-     * @return array
419
-     * @throws \Exception
420
-     */
421
-    protected function filterForBackendUser($fields)
422
-    {
423
-        if (!$this->getBackendUser()->isAdmin()) {
424
-            foreach ($fields as $key => $fieldName) {
425
-                if (Tca::table($this->dataType)->hasField($fieldName) && !Tca::table($this->dataType)->field($fieldName)->hasAccess()) {
426
-                    unset($fields[$key]);
427
-                }
428
-            }
429
-        }
430
-        return $fields;
431
-    }
432
-
433
-    /**
434
-     * Remove fields according to Grid configuration.
435
-     *
436
-     * @param $fields
437
-     * @return array
438
-     */
439
-    protected function filterForConfiguration($fields)
440
-    {
441
-
442
-        $excludedFields = Tca::grid($this->dataType)->getExcludedFields();
443
-        foreach ($fields as $key => $field) {
444
-            if (in_array($field, $excludedFields)) {
445
-                unset($fields[$key]);
446
-            }
447
-        }
448
-
449
-        return $fields;
450
-    }
451
-
452
-    /**
453
-     * Returns an instance of the current Backend User.
454
-     *
455
-     * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
456
-     */
457
-    protected function getBackendUser()
458
-    {
459
-        return $GLOBALS['BE_USER'];
460
-    }
461
-
462
-    /**
463
-     * Returns whether the current mode is Backend
464
-     *
465
-     * @return bool
466
-     */
467
-    protected function isBackendMode()
468
-    {
469
-        return TYPO3_MODE === 'BE';
470
-    }
26
+	/**
27
+	 * @var int
28
+	 */
29
+	protected $uid;
30
+
31
+	/**
32
+	 * @var string
33
+	 */
34
+	protected $dataType;
35
+
36
+	/**
37
+	 * Constructor for a Content object.
38
+	 *
39
+	 * @param string $dataType will basically correspond to a table name, e.g fe_users, tt_content, ...
40
+	 * @param array $contentData
41
+	 * @return \Fab\Vidi\Domain\Model\Content
42
+	 * @throws \InvalidArgumentException
43
+	 * @throws \Fab\Vidi\Exception\NotExistingClassException
44
+	 */
45
+	public function __construct($dataType, array $contentData = array())
46
+	{
47
+
48
+		$this->dataType = $dataType;
49
+		$this->uid = empty($contentData['uid']) ? null : (int)$contentData['uid'];
50
+
51
+		/** @var \Fab\Vidi\Tca\TableService $table */
52
+		$table = Tca::table($dataType);
53
+
54
+		// Initialize the array containing the allowed fields to be filled-in.
55
+		$fields = array('pid');
56
+
57
+		// If a creation time stamp has been defined for this data type.
58
+		if ($table->getTimeCreationField()) {
59
+			$fields[] = $table->getTimeCreationField();
60
+		}
61
+
62
+		// If an update time stamp has been defined for this data type.
63
+		if ($table->getTimeModificationField()) {
64
+			$fields[] = $table->getTimeModificationField();
65
+		}
66
+
67
+		// Merge the other fields allowed for this data type.
68
+		$fields = array_merge($fields, $table->getFields());
69
+
70
+		// Fetch excluded fields from the grid.
71
+		if ($this->isBackendMode()) {
72
+			$fields = $this->filterForConfiguration($fields);
73
+			$fields = $this->filterForBackendUser($fields);
74
+		}
75
+
76
+		// Get column to be displayed
77
+		foreach ($fields as $fieldName) {
78
+			if (array_key_exists($fieldName, $contentData)) {
79
+				$propertyName = Field::name($fieldName)->of($dataType)->toPropertyName();
80
+				$this->$propertyName = $contentData[$fieldName];
81
+			}
82
+		}
83
+	}
84
+
85
+	/**
86
+	 * Dispatches magic methods (findBy[Property]())
87
+	 *
88
+	 * @param string $methodName The name of the magic method
89
+	 * @param string $arguments The arguments of the magic method
90
+	 * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\UnsupportedMethodException
91
+	 * @return mixed
92
+	 * @api
93
+	 */
94
+	public function __call($methodName, $arguments)
95
+	{
96
+		$value = null;
97
+		if (substr($methodName, 0, 3) === 'get' && strlen($methodName) > 4) {
98
+			$propertyName = strtolower(substr(substr($methodName, 3), 0, 1)) . substr(substr($methodName, 3), 1);
99
+
100
+			$fieldName = Property::name($propertyName)->of($this)->toFieldName();
101
+			$field = Tca::table($this->dataType)->field($fieldName);
102
+
103
+			$value = $this->$propertyName;
104
+
105
+			// true means it is a relation and it is not yet resolved.
106
+			if ($this->hasRelation($propertyName) && is_scalar($this->$propertyName)) {
107
+				$value = $this->resolveRelation($propertyName);
108
+			} elseif ($field->getType() === FieldType::RADIO || $field->getType() === FieldType::SELECT) {
109
+
110
+				// Attempt to convert the value into a label for radio and select fields.
111
+				$label = Tca::table($this->getDataType())->field($fieldName)->getLabelForItem($value);
112
+				if ($label) {
113
+					$value = $label;
114
+				}
115
+			}
116
+
117
+		} elseif (substr($methodName, 0, 3) === 'set' && strlen($methodName) > 4 && isset($arguments[0])) {
118
+			$propertyName = strtolower(substr(substr($methodName, 3), 0, 1)) . substr(substr($methodName, 3), 1);
119
+			$this->$propertyName = $arguments[0];
120
+		}
121
+		return $value;
122
+	}
123
+
124
+	/**
125
+	 * Tell whether the property has a relation.
126
+	 *
127
+	 * @param string $propertyName
128
+	 * @return bool
129
+	 */
130
+	protected function hasRelation($propertyName)
131
+	{
132
+		$fieldName = Property::name($propertyName)->of($this)->toFieldName();
133
+		return Tca::table($this->dataType)->field($fieldName)->hasRelation();
134
+	}
135
+
136
+	/**
137
+	 * Try to "resolve" the property whether it has a relation.
138
+	 * If the property has not relation it simply returns the same value.
139
+	 *
140
+	 * @throws \RuntimeException
141
+	 * @param string $propertyName
142
+	 * @return mixed
143
+	 */
144
+	protected function resolveRelation($propertyName)
145
+	{
146
+
147
+		// Convert property name to field name and get the foreign data type.
148
+		$fieldName = Property::name($propertyName)->of($this)->toFieldName();
149
+		$foreignDataType = Tca::table($this->dataType)->field($fieldName)->relationDataType();
150
+
151
+		// Get the foreign repository instance form the factory
152
+		/** @var \Fab\Vidi\Domain\Repository\ContentRepository $foreignContentRepository */
153
+		$foreignContentRepository = ContentRepositoryFactory::getInstance($foreignDataType, $fieldName);
154
+
155
+		if (Tca::table($this->dataType)->field($fieldName)->hasRelationWithCommaSeparatedValues()) {
156
+
157
+			// Fetch values from repository
158
+			$values = GeneralUtility::trimExplode(',', $this->$propertyName);
159
+			$this->$propertyName = $foreignContentRepository->findIn('uid', $values);
160
+		} elseif (Tca::table($this->dataType)->field($fieldName)->hasMany()) {
161
+			// Include relation many-to-many and one-to-many
162
+			// Tca::table($this->dataType)->field($fieldName)->hasRelationOneToMany()
163
+			// Tca::table($this->dataType)->field($fieldName)->hasRelationManyToMany()
164
+
165
+			$foreignFieldName = Tca::table($this->dataType)->field($fieldName)->getForeignField();
166
+			if (empty($foreignFieldName)) {
167
+				$message = sprintf('Missing "foreign_field" key for field "%s" in table "%s".',
168
+					$fieldName,
169
+					$this->dataType
170
+				);
171
+				throw new \RuntimeException($message, 1376149186);
172
+			}
173
+
174
+			// Fetch values from repository.
175
+			$foreignPropertyName = Field::name($foreignFieldName)->of($this)->toPropertyName();
176
+			$findByProperty = 'findBy' . ucfirst($foreignPropertyName);
177
+
178
+			// Date picker (type == group) are special fields because property path must contain the table name
179
+			// to determine the relation type. Example for sys_category, property path will look like "items.sys_file"
180
+			$propertyValue = $this->uid;
181
+			if (Tca::table($foreignDataType)->field($foreignFieldName)->isGroup()) {
182
+				$propertyValue = $this->dataType . '.' . $this->uid;
183
+			}
184
+
185
+			$this->$propertyName = $foreignContentRepository->$findByProperty($propertyValue);
186
+
187
+		} elseif (Tca::table($this->dataType)->field($fieldName)->hasOne()) {
188
+
189
+			$fieldConfiguration = Tca::table($this->dataType)->field($fieldName)->getConfiguration();
190
+
191
+			// First case, we are on the "good side" of the relation, just query the repository
192
+			if (empty($fieldConfiguration['foreign_field'])) {
193
+				$this->$propertyName = $foreignContentRepository->findByUid($this->$propertyName);
194
+			} else {
195
+				// Second case, we are the "bad side" of the relation, query the foreign repository
196
+				// e.g. in case of one-to-one relation.
197
+
198
+				// We must query the opposite side to get the identifier of the foreign object.
199
+				$foreignDataType = Tca::table($this->dataType)->field($fieldName)->getForeignTable();
200
+				$foreignField = Tca::table($this->dataType)->field($fieldName)->getForeignField();
201
+				$foreignContentRepository = ContentRepositoryFactory::getInstance($foreignDataType);
202
+				$find = 'findOneBy' . GeneralUtility::underscoredToUpperCamelCase($foreignField);
203
+
204
+				/** @var Content $foreignObject */
205
+				$this->$propertyName = $foreignContentRepository->$find($this->getUid());
206
+			}
207
+
208
+		}
209
+		return $this->$propertyName;
210
+	}
211
+
212
+	/**
213
+	 * @return int
214
+	 */
215
+	public function getUid()
216
+	{
217
+		return $this->uid;
218
+	}
219
+
220
+	/**
221
+	 * @return string
222
+	 */
223
+	public function getDataType()
224
+	{
225
+		return $this->dataType;
226
+	}
227
+
228
+	/**
229
+	 * Whether a offset exists
230
+	 *
231
+	 * @link http://php.net/manual/en/arrayaccess.offsetexists.php
232
+	 * @param mixed $offset
233
+	 * @return boolean true on success or false on failure.
234
+	 * @throws \RuntimeException
235
+	 * @throws \InvalidArgumentException
236
+	 */
237
+	public function offsetExists($offset)
238
+	{
239
+		$offset = Field::name($offset)->of($this)->toPropertyName();
240
+		return isset($this->$offset);
241
+	}
242
+
243
+	/**
244
+	 * Offset to retrieve
245
+	 *
246
+	 * @link http://php.net/manual/en/arrayaccess.offsetget.php
247
+	 * @param mixed $offset
248
+	 * @return mixed Can return all value types.
249
+	 * @throws \RuntimeException
250
+	 * @throws \InvalidArgumentException
251
+	 */
252
+	public function offsetGet($offset)
253
+	{
254
+		$offset = Field::name($offset)->of($this)->toPropertyName();
255
+		$getter = 'get' . ucfirst($offset);
256
+		return $this->$getter();
257
+	}
258
+
259
+	/**
260
+	 * Offset to set
261
+	 *
262
+	 * @link http://php.net/manual/en/arrayaccess.offsetset.php
263
+	 * @param mixed $offset
264
+	 * @param mixed $value
265
+	 * @return $this
266
+	 * @throws \RuntimeException
267
+	 * @throws \InvalidArgumentException
268
+	 */
269
+	public function offsetSet($offset, $value)
270
+	{
271
+		$offset = Field::name($offset)->of($this)->toPropertyName();
272
+		$setter = 'set' . ucfirst($offset);
273
+		$this->$setter($value);
274
+		return $this;
275
+	}
276
+
277
+	/**
278
+	 * Offset to unset
279
+	 *
280
+	 * @link http://php.net/manual/en/arrayaccess.offsetunset.php
281
+	 * @param mixed $offset
282
+	 * @throws NotImplementedException
283
+	 * @return void
284
+	 */
285
+	public function offsetUnset($offset)
286
+	{
287
+		$message = 'Un-setting value for Array object is not supported';
288
+		throw new NotImplementedException($message, 1376132306);
289
+	}
290
+
291
+	/**
292
+	 * Convert this to array
293
+	 *
294
+	 * @return array
295
+	 * @throws \InvalidArgumentException
296
+	 */
297
+	public function toArray()
298
+	{
299
+		$result['uid'] = $this->uid;
300
+		$propertiesAndValues = json_decode(json_encode($this), true);
301
+
302
+		foreach ($propertiesAndValues as $propertyName => $value) {
303
+			$fieldName = Property::name($propertyName)->of($this)->toFieldName();
304
+			$result[$fieldName] = $value;
305
+		}
306
+
307
+		return $result;
308
+	}
309
+
310
+	/**
311
+	 * Convert this object to an array containing the resolved values.
312
+	 *
313
+	 * @param bool $resolveRelations
314
+	 * @return array
315
+	 * @throws \Exception
316
+	 */
317
+	public function toValues($resolveRelations = true)
318
+	{
319
+		$result['uid'] = $this->uid;
320
+		$propertiesAndValues = json_decode(json_encode($this), true);
321
+
322
+		foreach ($propertiesAndValues as $propertyName => $value) {
323
+			$fieldName = Property::name($propertyName)->of($this)->toFieldName();
324
+
325
+			$result[$fieldName] = $value;
326
+			if ($resolveRelations) {
327
+				$field = Tca::table($this->dataType)->field($fieldName);
328
+
329
+				$resolvedValue = '';
330
+				if ($field->getType() === FieldType::FILE) {
331
+
332
+					if ($field->hasMany()) {
333
+						$files = FileReferenceService::getInstance()->findReferencedBy($propertyName, $this);
334
+
335
+						$resolvedValue = [];
336
+						foreach ($files as $file) {
337
+							$resolvedValue[] = $file->getIdentifier();
338
+						}
339
+					} else {
340
+						$files = FileReferenceService::getInstance()->findReferencedBy($propertyName, $this);
341
+						if (!empty($files)) {
342
+							$resolvedValue = current($files)->getIdentifier();
343
+						}
344
+					}
345
+
346
+					// Reset value
347
+					$result[$fieldName] = $resolvedValue;
348
+
349
+				} elseif (Tca::table($this->dataType)->field($fieldName)->hasRelation()) {
350
+					$objects = $this[$fieldName];
351
+					if (is_array($objects)) {
352
+						$resolvedValue = [];
353
+						foreach ($objects as $object) {
354
+							/** @var $object Content */
355
+							$labelField = Tca::table($object->getDataType())->getLabelField();
356
+							$resolvedValue[] = $object[$labelField];
357
+						}
358
+					} elseif ($objects instanceof Content) {
359
+						$labelField = Tca::table($objects->getDataType())->getLabelField();
360
+						$resolvedValue = $objects[$labelField];
361
+					}
362
+
363
+					// Reset value
364
+					$result[$fieldName] = $resolvedValue;
365
+				}
366
+			}
367
+		}
368
+
369
+		return $result;
370
+	}
371
+
372
+	/**
373
+	 * Return the properties of this object.
374
+	 *
375
+	 * @return array
376
+	 */
377
+	public function toProperties()
378
+	{
379
+		$result[] = 'uid';
380
+		$propertiesAndValues = json_decode(json_encode($this), true);
381
+
382
+		foreach ($propertiesAndValues as $propertyName => $value) {
383
+			$result[] = $propertyName;
384
+		}
385
+		return $result;
386
+	}
387
+
388
+	/**
389
+	 * Return the properties of this object.
390
+	 *
391
+	 * @return array
392
+	 */
393
+	public function toFields()
394
+	{
395
+		$result[] = 'uid';
396
+		$propertiesAndValues = json_decode(json_encode($this), true);
397
+
398
+		foreach ($propertiesAndValues as $propertyName => $value) {
399
+			$result[] = Property::name($propertyName)->of($this)->toFieldName();
400
+		}
401
+
402
+		return $result;
403
+	}
404
+
405
+	/**
406
+	 * @return string
407
+	 */
408
+	public function __toString()
409
+	{
410
+		$labelField = Tca::table($this->dataType)->getLabelField();
411
+		return $this[$labelField];
412
+	}
413
+
414
+	/**
415
+	 * Remove fields according to BE User permission.
416
+	 *
417
+	 * @param $fields
418
+	 * @return array
419
+	 * @throws \Exception
420
+	 */
421
+	protected function filterForBackendUser($fields)
422
+	{
423
+		if (!$this->getBackendUser()->isAdmin()) {
424
+			foreach ($fields as $key => $fieldName) {
425
+				if (Tca::table($this->dataType)->hasField($fieldName) && !Tca::table($this->dataType)->field($fieldName)->hasAccess()) {
426
+					unset($fields[$key]);
427
+				}
428
+			}
429
+		}
430
+		return $fields;
431
+	}
432
+
433
+	/**
434
+	 * Remove fields according to Grid configuration.
435
+	 *
436
+	 * @param $fields
437
+	 * @return array
438
+	 */
439
+	protected function filterForConfiguration($fields)
440
+	{
441
+
442
+		$excludedFields = Tca::grid($this->dataType)->getExcludedFields();
443
+		foreach ($fields as $key => $field) {
444
+			if (in_array($field, $excludedFields)) {
445
+				unset($fields[$key]);
446
+			}
447
+		}
448
+
449
+		return $fields;
450
+	}
451
+
452
+	/**
453
+	 * Returns an instance of the current Backend User.
454
+	 *
455
+	 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
456
+	 */
457
+	protected function getBackendUser()
458
+	{
459
+		return $GLOBALS['BE_USER'];
460
+	}
461
+
462
+	/**
463
+	 * Returns whether the current mode is Backend
464
+	 *
465
+	 * @return bool
466
+	 */
467
+	protected function isBackendMode()
468
+	{
469
+		return TYPO3_MODE === 'BE';
470
+	}
471 471
 
472 472
 }
Please login to merge, or discard this patch.
Spacing   +7 added lines, -7 removed lines patch added patch discarded remove patch
@@ -95,7 +95,7 @@  discard block
 block discarded – undo
95 95
     {
96 96
         $value = null;
97 97
         if (substr($methodName, 0, 3) === 'get' && strlen($methodName) > 4) {
98
-            $propertyName = strtolower(substr(substr($methodName, 3), 0, 1)) . substr(substr($methodName, 3), 1);
98
+            $propertyName = strtolower(substr(substr($methodName, 3), 0, 1)).substr(substr($methodName, 3), 1);
99 99
 
100 100
             $fieldName = Property::name($propertyName)->of($this)->toFieldName();
101 101
             $field = Tca::table($this->dataType)->field($fieldName);
@@ -115,7 +115,7 @@  discard block
 block discarded – undo
115 115
             }
116 116
 
117 117
         } elseif (substr($methodName, 0, 3) === 'set' && strlen($methodName) > 4 && isset($arguments[0])) {
118
-            $propertyName = strtolower(substr(substr($methodName, 3), 0, 1)) . substr(substr($methodName, 3), 1);
118
+            $propertyName = strtolower(substr(substr($methodName, 3), 0, 1)).substr(substr($methodName, 3), 1);
119 119
             $this->$propertyName = $arguments[0];
120 120
         }
121 121
         return $value;
@@ -173,13 +173,13 @@  discard block
 block discarded – undo
173 173
 
174 174
             // Fetch values from repository.
175 175
             $foreignPropertyName = Field::name($foreignFieldName)->of($this)->toPropertyName();
176
-            $findByProperty = 'findBy' . ucfirst($foreignPropertyName);
176
+            $findByProperty = 'findBy'.ucfirst($foreignPropertyName);
177 177
 
178 178
             // Date picker (type == group) are special fields because property path must contain the table name
179 179
             // to determine the relation type. Example for sys_category, property path will look like "items.sys_file"
180 180
             $propertyValue = $this->uid;
181 181
             if (Tca::table($foreignDataType)->field($foreignFieldName)->isGroup()) {
182
-                $propertyValue = $this->dataType . '.' . $this->uid;
182
+                $propertyValue = $this->dataType.'.'.$this->uid;
183 183
             }
184 184
 
185 185
             $this->$propertyName = $foreignContentRepository->$findByProperty($propertyValue);
@@ -199,7 +199,7 @@  discard block
 block discarded – undo
199 199
                 $foreignDataType = Tca::table($this->dataType)->field($fieldName)->getForeignTable();
200 200
                 $foreignField = Tca::table($this->dataType)->field($fieldName)->getForeignField();
201 201
                 $foreignContentRepository = ContentRepositoryFactory::getInstance($foreignDataType);
202
-                $find = 'findOneBy' . GeneralUtility::underscoredToUpperCamelCase($foreignField);
202
+                $find = 'findOneBy'.GeneralUtility::underscoredToUpperCamelCase($foreignField);
203 203
 
204 204
                 /** @var Content $foreignObject */
205 205
                 $this->$propertyName = $foreignContentRepository->$find($this->getUid());
@@ -252,7 +252,7 @@  discard block
 block discarded – undo
252 252
     public function offsetGet($offset)
253 253
     {
254 254
         $offset = Field::name($offset)->of($this)->toPropertyName();
255
-        $getter = 'get' . ucfirst($offset);
255
+        $getter = 'get'.ucfirst($offset);
256 256
         return $this->$getter();
257 257
     }
258 258
 
@@ -269,7 +269,7 @@  discard block
 block discarded – undo
269 269
     public function offsetSet($offset, $value)
270 270
     {
271 271
         $offset = Field::name($offset)->of($this)->toPropertyName();
272
-        $setter = 'set' . ucfirst($offset);
272
+        $setter = 'set'.ucfirst($offset);
273 273
         $this->$setter($value);
274 274
         return $this;
275 275
     }
Please login to merge, or discard this patch.
Classes/Grid/GridAnalyserService.php 2 patches
Doc Comments   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -81,7 +81,7 @@  discard block
 block discarded – undo
81 81
      *
82 82
      * @param string $tableName
83 83
      * @param string $fieldName
84
-     * @return array
84
+     * @return string[]
85 85
      */
86 86
     protected function checkRelationManyToMany($tableName, $fieldName)
87 87
     {
@@ -115,7 +115,7 @@  discard block
 block discarded – undo
115 115
      * @param string $tableName
116 116
      * @param string $fieldName
117 117
      * @param string $relationType
118
-     * @return array
118
+     * @return string[]
119 119
      */
120 120
     protected function checkRelationOf($tableName, $fieldName, $relationType)
121 121
     {
Please login to merge, or discard this patch.
Indentation   +102 added lines, -102 removed lines patch added patch discarded remove patch
@@ -16,114 +16,114 @@
 block discarded – undo
16 16
 class GridAnalyserService
17 17
 {
18 18
 
19
-    /**
20
-     * Check relation for table.
21
-     *
22
-     * @param $tableName
23
-     * @return array
24
-     */
25
-    public function checkRelationForTable($tableName)
26
-    {
19
+	/**
20
+	 * Check relation for table.
21
+	 *
22
+	 * @param $tableName
23
+	 * @return array
24
+	 */
25
+	public function checkRelationForTable($tableName)
26
+	{
27 27
 
28
-        $relations = [];
29
-        $table = Tca::table($tableName);
28
+		$relations = [];
29
+		$table = Tca::table($tableName);
30 30
 
31
-        $missingOppositionRelationMessage = <<<EOF
31
+		$missingOppositionRelationMessage = <<<EOF
32 32
 
33 33
   WARNING! Could not define relation precisely. This is not necessarily a problem
34 34
   if the opposite relation is not required in a Grid. But consider adding the opposite
35 35
   TCA configuration if so.
36 36
 EOF;
37 37
 
38
-        foreach (Tca::grid($tableName)->getFields() as $fieldName => $configuration) {
39
-
40
-            if ($table->hasField($fieldName)) {
41
-                if ($table->field($fieldName)->hasMany()) {
42
-                    if ($table->field($fieldName)->hasRelationWithCommaSeparatedValues()) {
43
-                        $_relations = $this->checkRelationOf($tableName, $fieldName, 'comma separated values');
44
-                        $relations = array_merge($relations, $_relations);
45
-                    } elseif ($table->field($fieldName)->hasRelationManyToMany()) {
46
-                        $_relations = $this->checkRelationManyToMany($tableName, $fieldName);
47
-                        $relations = array_merge($relations, $_relations);
48
-
49
-                    } elseif ($table->field($fieldName)->hasRelationOneToMany()) {
50
-                        $_relations = $this->checkRelationOf($tableName, $fieldName, 'one-to-many');
51
-                        $relations = array_merge($relations, $_relations);
52
-                    } else {
53
-                        $relations[] = sprintf('* field: "%s", relation: ?-to-many%s', $fieldName, $missingOppositionRelationMessage);
54
-                    }
55
-                    $relations[] = '';
56
-                } elseif ($table->field($fieldName)->hasOne()) {
57
-
58
-                    if ($table->field($fieldName)->hasRelationOneToOne()) {
59
-                        $relations[] = sprintf('* one-to-one "%s"', $fieldName);
60
-                    } elseif ($table->field($fieldName)->hasRelationManyToOne()) {
61
-                        $_relations = $this->checkRelationOf($tableName, $fieldName, 'many-to-one');
62
-                        $relations = array_merge($relations, $_relations);
63
-                    } else {
64
-                        $relations[] = sprintf('* field: "%s", relation: ?-to-one%s', $fieldName, $missingOppositionRelationMessage);
65
-                    }
66
-                    $relations[] = '';
67
-                }
68
-            }
69
-        }
70
-        return $relations;
71
-    }
72
-
73
-    /**
74
-     * Convenience method for printing out relation many-to-many.
75
-     *
76
-     * @param string $tableName
77
-     * @param string $fieldName
78
-     * @return array
79
-     */
80
-    protected function checkRelationManyToMany($tableName, $fieldName)
81
-    {
82
-
83
-        $output = [];
84
-
85
-        $table = Tca::table($tableName);
86
-        $output[] = sprintf('* field: "%s", relation: many-to-many', $fieldName);
87
-
88
-        $foreignTable = $table->field($fieldName)->getForeignTable();
89
-        $manyToManyTable = $table->field($fieldName)->getManyToManyTable();
90
-        $foreignField = $table->field($fieldName)->getForeignField();
91
-
92
-        if (!$foreignField) {
93
-            $output[] = sprintf('  ERROR! Can not found foreign field for "%s". Perhaps missing opposite configuration?', $fieldName);
94
-        } elseif (!$foreignTable) {
95
-            $output[] = sprintf('  ERROR! Can not found foreign table for "%s". Perhaps missing opposite configuration?', $fieldName);
96
-        } elseif (!$manyToManyTable) {
97
-            $output[] = sprintf('  ERROR! Can not found relation table (MM) for "%s". Perhaps missing opposite configuration?', $fieldName);
98
-        } else {
99
-            $output[] = sprintf('  %s.%s <--> %s <--> %s.%s', $tableName, $fieldName, $manyToManyTable, $foreignTable, $foreignField);
100
-        }
101
-
102
-        $output[] = '';
103
-        return $output;
104
-    }
105
-
106
-    /**
107
-     * Convenience method for printing out relation.
108
-     *
109
-     * @param string $tableName
110
-     * @param string $fieldName
111
-     * @param string $relationType
112
-     * @return array
113
-     */
114
-    protected function checkRelationOf($tableName, $fieldName, $relationType)
115
-    {
116
-
117
-        $output = [];
118
-
119
-        $table = Tca::table($tableName);
120
-        $output[] = sprintf('* field: "%s", relation: %s', $fieldName, $relationType);
121
-
122
-        $foreignTable = $table->field($fieldName)->getForeignTable();
123
-        $foreignField = $table->field($fieldName)->getForeignField();
124
-        $output[] = sprintf('  %s.%s <--> %s.%s', $tableName, $fieldName, $foreignTable, $foreignField);
125
-        $output[] = '';
126
-
127
-        return $output;
128
-    }
38
+		foreach (Tca::grid($tableName)->getFields() as $fieldName => $configuration) {
39
+
40
+			if ($table->hasField($fieldName)) {
41
+				if ($table->field($fieldName)->hasMany()) {
42
+					if ($table->field($fieldName)->hasRelationWithCommaSeparatedValues()) {
43
+						$_relations = $this->checkRelationOf($tableName, $fieldName, 'comma separated values');
44
+						$relations = array_merge($relations, $_relations);
45
+					} elseif ($table->field($fieldName)->hasRelationManyToMany()) {
46
+						$_relations = $this->checkRelationManyToMany($tableName, $fieldName);
47
+						$relations = array_merge($relations, $_relations);
48
+
49
+					} elseif ($table->field($fieldName)->hasRelationOneToMany()) {
50
+						$_relations = $this->checkRelationOf($tableName, $fieldName, 'one-to-many');
51
+						$relations = array_merge($relations, $_relations);
52
+					} else {
53
+						$relations[] = sprintf('* field: "%s", relation: ?-to-many%s', $fieldName, $missingOppositionRelationMessage);
54
+					}
55
+					$relations[] = '';
56
+				} elseif ($table->field($fieldName)->hasOne()) {
57
+
58
+					if ($table->field($fieldName)->hasRelationOneToOne()) {
59
+						$relations[] = sprintf('* one-to-one "%s"', $fieldName);
60
+					} elseif ($table->field($fieldName)->hasRelationManyToOne()) {
61
+						$_relations = $this->checkRelationOf($tableName, $fieldName, 'many-to-one');
62
+						$relations = array_merge($relations, $_relations);
63
+					} else {
64
+						$relations[] = sprintf('* field: "%s", relation: ?-to-one%s', $fieldName, $missingOppositionRelationMessage);
65
+					}
66
+					$relations[] = '';
67
+				}
68
+			}
69
+		}
70
+		return $relations;
71
+	}
72
+
73
+	/**
74
+	 * Convenience method for printing out relation many-to-many.
75
+	 *
76
+	 * @param string $tableName
77
+	 * @param string $fieldName
78
+	 * @return array
79
+	 */
80
+	protected function checkRelationManyToMany($tableName, $fieldName)
81
+	{
82
+
83
+		$output = [];
84
+
85
+		$table = Tca::table($tableName);
86
+		$output[] = sprintf('* field: "%s", relation: many-to-many', $fieldName);
87
+
88
+		$foreignTable = $table->field($fieldName)->getForeignTable();
89
+		$manyToManyTable = $table->field($fieldName)->getManyToManyTable();
90
+		$foreignField = $table->field($fieldName)->getForeignField();
91
+
92
+		if (!$foreignField) {
93
+			$output[] = sprintf('  ERROR! Can not found foreign field for "%s". Perhaps missing opposite configuration?', $fieldName);
94
+		} elseif (!$foreignTable) {
95
+			$output[] = sprintf('  ERROR! Can not found foreign table for "%s". Perhaps missing opposite configuration?', $fieldName);
96
+		} elseif (!$manyToManyTable) {
97
+			$output[] = sprintf('  ERROR! Can not found relation table (MM) for "%s". Perhaps missing opposite configuration?', $fieldName);
98
+		} else {
99
+			$output[] = sprintf('  %s.%s <--> %s <--> %s.%s', $tableName, $fieldName, $manyToManyTable, $foreignTable, $foreignField);
100
+		}
101
+
102
+		$output[] = '';
103
+		return $output;
104
+	}
105
+
106
+	/**
107
+	 * Convenience method for printing out relation.
108
+	 *
109
+	 * @param string $tableName
110
+	 * @param string $fieldName
111
+	 * @param string $relationType
112
+	 * @return array
113
+	 */
114
+	protected function checkRelationOf($tableName, $fieldName, $relationType)
115
+	{
116
+
117
+		$output = [];
118
+
119
+		$table = Tca::table($tableName);
120
+		$output[] = sprintf('* field: "%s", relation: %s', $fieldName, $relationType);
121
+
122
+		$foreignTable = $table->field($fieldName)->getForeignTable();
123
+		$foreignField = $table->field($fieldName)->getForeignField();
124
+		$output[] = sprintf('  %s.%s <--> %s.%s', $tableName, $fieldName, $foreignTable, $foreignField);
125
+		$output[] = '';
126
+
127
+		return $output;
128
+	}
129 129
 }
Please login to merge, or discard this patch.
Classes/Language/LanguageService.php 2 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -109,7 +109,7 @@
 block discarded – undo
109 109
      *
110 110
      * @param Content $object
111 111
      * @param int $language
112
-     * @return string
112
+     * @return boolean
113 113
      */
114 114
     public function hasLocalization(Content $object, $language)
115 115
     {
Please login to merge, or discard this patch.
Indentation   +173 added lines, -173 removed lines patch added patch discarded remove patch
@@ -19,178 +19,178 @@
 block discarded – undo
19 19
 class LanguageService implements SingletonInterface
20 20
 {
21 21
 
22
-    /**
23
-     * @var array
24
-     */
25
-    protected $languages;
26
-
27
-    /**
28
-     * @var array
29
-     */
30
-    protected $defaultIcon;
31
-
32
-    /**
33
-     * Store the localized records to boost up performance.
34
-     *
35
-     * @var array
36
-     */
37
-    protected $localizedRecordStorage;
38
-
39
-    /**
40
-     * Returns available language records.
41
-     * The method stores the records in the property to speed up the process as the method can be often called.
42
-     *
43
-     * @return array
44
-     */
45
-    public function getLanguages()
46
-    {
47
-        if (is_null($this->languages)) {
48
-
49
-            $tableName = 'sys_language';
50
-
51
-            $clause = '1 = 1';
52
-            $clause .= BackendUtility::deleteClause($tableName);
53
-            $clause .= BackendUtility::BEenableFields($tableName);
54
-            $this->languages = $this->getDatabaseConnection()->exec_SELECTgetRows('*', $tableName, $clause);
55
-        }
56
-        return $this->languages;
57
-    }
58
-
59
-    /**
60
-     * Returns a localized record according to a Content object and a language identifier.
61
-     * Notice! This method does not overlay anything but simply returns the raw localized record.
62
-     *
63
-     * @param Content $object
64
-     * @param int $language
65
-     * @return Content
66
-     */
67
-    public function getLocalizedContent(Content $object, $language)
68
-    {
69
-
70
-        // We want to cache data per Content object. Retrieve the Object hash.
71
-        $objectHash = spl_object_hash($object);
72
-
73
-        // Initialize the storage
74
-        if (empty($this->localizedRecordStorage[$objectHash])) {
75
-            $this->localizedRecordStorage[$objectHash] = [];
76
-        }
77
-
78
-        if (empty($this->localizedRecordStorage[$objectHash][$language])) {
79
-
80
-            $clause = sprintf('%s = %s AND %s = %s',
81
-                Tca::table($object)->getLanguageParentField(), // e.g. l10n_parent
82
-                $object->getUid(),
83
-                Tca::table($object)->getLanguageField(), // e.g. sys_language_uid
84
-                $language
85
-            );
86
-
87
-            $clause .= BackendUtility::deleteClause($object->getDataType());
88
-            $localizedRecord = $this->getDatabaseConnection()->exec_SELECTgetSingleRow('*', $object->getDataType(), $clause);
89
-
90
-            if ($localizedRecord) {
91
-                $localizedContent = GeneralUtility::makeInstance('Fab\Vidi\Domain\Model\Content', $object->getDataType(), $localizedRecord);
92
-                $this->localizedRecordStorage[$objectHash][$language] = $localizedContent;
93
-            } else {
94
-                $this->localizedRecordStorage[$objectHash][$language] = []; // We want an array at least, even if empty.
95
-            }
96
-        }
97
-
98
-        return $this->localizedRecordStorage[$objectHash][$language];
99
-    }
100
-
101
-    /**
102
-     * Tell whether the given Content object has a localization.
103
-     *
104
-     * @param Content $object
105
-     * @param int $language
106
-     * @return string
107
-     */
108
-    public function hasLocalization(Content $object, $language)
109
-    {
110
-        $localizedRecord = $this->getLocalizedContent($object, $language);
111
-        return !empty($localizedRecord);
112
-    }
113
-
114
-    /**
115
-     * Returns a localized field according to a Content object and a language identifier.
116
-     * Notice! If there is not translation, simply returns an empty string.
117
-     *
118
-     * @param Content $object
119
-     * @param int $language
120
-     * @param string $fieldName
121
-     * @return string
122
-     */
123
-    public function getLocalizedFieldName(Content $object, $language, $fieldName)
124
-    {
125
-        $localizedRecord = $this->getLocalizedContent($object, $language);
126
-        return empty($localizedRecord) ? '' : $localizedRecord[$fieldName];
127
-    }
128
-
129
-    /**
130
-     * Returns the default language configured by TSConfig.
131
-     *
132
-     * @return array
133
-     */
134
-    public function getDefaultFlag()
135
-    {
136
-
137
-        if (is_null($this->defaultIcon)) {
138
-
139
-            $defaultFlag = ''; // default value
140
-
141
-            $tsConfig = BackendUtility::getModTSconfig(0, 'mod.SHARED');
142
-
143
-            // Fallback non sprite-configuration
144
-            if (($pos = strrpos($tsConfig['properties']['defaultLanguageFlag'], '.')) !== false) {
145
-                $defaultFlag = substr($tsConfig['properties']['defaultLanguageFlag'], 0, $pos);
146
-            }
147
-
148
-            $this->defaultIcon = $defaultFlag;
149
-        }
150
-
151
-        return $this->defaultIcon;
152
-    }
153
-
154
-    /**
155
-     * Returns whether the system includes language records.
156
-     *
157
-     * @return bool
158
-     */
159
-    public function hasLanguages()
160
-    {
161
-        $languages = $this->getLanguages();
162
-        return !empty($languages);
163
-    }
164
-
165
-    /**
166
-     * Tell whether the given language exists.
167
-     *
168
-     * @param int $language
169
-     * @return bool
170
-     */
171
-    public function languageExists($language)
172
-    {
173
-        $languages = $this->getLanguages();
174
-
175
-        $LanguageExists = false;
176
-        foreach ($languages as $_language) {
177
-            if ((int)$_language['uid'] === (int)$language) {
178
-                $LanguageExists = true;
179
-                break;
180
-            }
181
-        }
182
-
183
-        return $LanguageExists;
184
-    }
185
-
186
-    /**
187
-     * Returns a pointer to the database.
188
-     *
189
-     * @return \TYPO3\CMS\Core\Database\DatabaseConnection
190
-     */
191
-    protected function getDatabaseConnection()
192
-    {
193
-        return $GLOBALS['TYPO3_DB'];
194
-    }
22
+	/**
23
+	 * @var array
24
+	 */
25
+	protected $languages;
26
+
27
+	/**
28
+	 * @var array
29
+	 */
30
+	protected $defaultIcon;
31
+
32
+	/**
33
+	 * Store the localized records to boost up performance.
34
+	 *
35
+	 * @var array
36
+	 */
37
+	protected $localizedRecordStorage;
38
+
39
+	/**
40
+	 * Returns available language records.
41
+	 * The method stores the records in the property to speed up the process as the method can be often called.
42
+	 *
43
+	 * @return array
44
+	 */
45
+	public function getLanguages()
46
+	{
47
+		if (is_null($this->languages)) {
48
+
49
+			$tableName = 'sys_language';
50
+
51
+			$clause = '1 = 1';
52
+			$clause .= BackendUtility::deleteClause($tableName);
53
+			$clause .= BackendUtility::BEenableFields($tableName);
54
+			$this->languages = $this->getDatabaseConnection()->exec_SELECTgetRows('*', $tableName, $clause);
55
+		}
56
+		return $this->languages;
57
+	}
58
+
59
+	/**
60
+	 * Returns a localized record according to a Content object and a language identifier.
61
+	 * Notice! This method does not overlay anything but simply returns the raw localized record.
62
+	 *
63
+	 * @param Content $object
64
+	 * @param int $language
65
+	 * @return Content
66
+	 */
67
+	public function getLocalizedContent(Content $object, $language)
68
+	{
69
+
70
+		// We want to cache data per Content object. Retrieve the Object hash.
71
+		$objectHash = spl_object_hash($object);
72
+
73
+		// Initialize the storage
74
+		if (empty($this->localizedRecordStorage[$objectHash])) {
75
+			$this->localizedRecordStorage[$objectHash] = [];
76
+		}
77
+
78
+		if (empty($this->localizedRecordStorage[$objectHash][$language])) {
79
+
80
+			$clause = sprintf('%s = %s AND %s = %s',
81
+				Tca::table($object)->getLanguageParentField(), // e.g. l10n_parent
82
+				$object->getUid(),
83
+				Tca::table($object)->getLanguageField(), // e.g. sys_language_uid
84
+				$language
85
+			);
86
+
87
+			$clause .= BackendUtility::deleteClause($object->getDataType());
88
+			$localizedRecord = $this->getDatabaseConnection()->exec_SELECTgetSingleRow('*', $object->getDataType(), $clause);
89
+
90
+			if ($localizedRecord) {
91
+				$localizedContent = GeneralUtility::makeInstance('Fab\Vidi\Domain\Model\Content', $object->getDataType(), $localizedRecord);
92
+				$this->localizedRecordStorage[$objectHash][$language] = $localizedContent;
93
+			} else {
94
+				$this->localizedRecordStorage[$objectHash][$language] = []; // We want an array at least, even if empty.
95
+			}
96
+		}
97
+
98
+		return $this->localizedRecordStorage[$objectHash][$language];
99
+	}
100
+
101
+	/**
102
+	 * Tell whether the given Content object has a localization.
103
+	 *
104
+	 * @param Content $object
105
+	 * @param int $language
106
+	 * @return string
107
+	 */
108
+	public function hasLocalization(Content $object, $language)
109
+	{
110
+		$localizedRecord = $this->getLocalizedContent($object, $language);
111
+		return !empty($localizedRecord);
112
+	}
113
+
114
+	/**
115
+	 * Returns a localized field according to a Content object and a language identifier.
116
+	 * Notice! If there is not translation, simply returns an empty string.
117
+	 *
118
+	 * @param Content $object
119
+	 * @param int $language
120
+	 * @param string $fieldName
121
+	 * @return string
122
+	 */
123
+	public function getLocalizedFieldName(Content $object, $language, $fieldName)
124
+	{
125
+		$localizedRecord = $this->getLocalizedContent($object, $language);
126
+		return empty($localizedRecord) ? '' : $localizedRecord[$fieldName];
127
+	}
128
+
129
+	/**
130
+	 * Returns the default language configured by TSConfig.
131
+	 *
132
+	 * @return array
133
+	 */
134
+	public function getDefaultFlag()
135
+	{
136
+
137
+		if (is_null($this->defaultIcon)) {
138
+
139
+			$defaultFlag = ''; // default value
140
+
141
+			$tsConfig = BackendUtility::getModTSconfig(0, 'mod.SHARED');
142
+
143
+			// Fallback non sprite-configuration
144
+			if (($pos = strrpos($tsConfig['properties']['defaultLanguageFlag'], '.')) !== false) {
145
+				$defaultFlag = substr($tsConfig['properties']['defaultLanguageFlag'], 0, $pos);
146
+			}
147
+
148
+			$this->defaultIcon = $defaultFlag;
149
+		}
150
+
151
+		return $this->defaultIcon;
152
+	}
153
+
154
+	/**
155
+	 * Returns whether the system includes language records.
156
+	 *
157
+	 * @return bool
158
+	 */
159
+	public function hasLanguages()
160
+	{
161
+		$languages = $this->getLanguages();
162
+		return !empty($languages);
163
+	}
164
+
165
+	/**
166
+	 * Tell whether the given language exists.
167
+	 *
168
+	 * @param int $language
169
+	 * @return bool
170
+	 */
171
+	public function languageExists($language)
172
+	{
173
+		$languages = $this->getLanguages();
174
+
175
+		$LanguageExists = false;
176
+		foreach ($languages as $_language) {
177
+			if ((int)$_language['uid'] === (int)$language) {
178
+				$LanguageExists = true;
179
+				break;
180
+			}
181
+		}
182
+
183
+		return $LanguageExists;
184
+	}
185
+
186
+	/**
187
+	 * Returns a pointer to the database.
188
+	 *
189
+	 * @return \TYPO3\CMS\Core\Database\DatabaseConnection
190
+	 */
191
+	protected function getDatabaseConnection()
192
+	{
193
+		return $GLOBALS['TYPO3_DB'];
194
+	}
195 195
 
196 196
 }
Please login to merge, or discard this patch.
Classes/Persistence/Matcher.php 3 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -192,7 +192,7 @@
 block discarded – undo
192 192
     }
193 193
 
194 194
     /**
195
-     * @return array
195
+     * @return string
196 196
      */
197 197
     public function getDefaultLogicalSeparator()
198 198
     {
Please login to merge, or discard this patch.
Indentation   +466 added lines, -466 removed lines patch added patch discarded remove patch
@@ -13,470 +13,470 @@
 block discarded – undo
13 13
  */
14 14
 class Matcher
15 15
 {
16
-    /**
17
-     * The logical OR
18
-     */
19
-    const LOGICAL_OR = 'logicalOr';
20
-
21
-    /**
22
-     * The logical AND
23
-     */
24
-    const LOGICAL_AND = 'logicalAnd';
25
-
26
-    /**
27
-     * @var string
28
-     */
29
-    protected $dataType = '';
30
-
31
-    /**
32
-     * @var string
33
-     */
34
-    protected $searchTerm = '';
35
-
36
-    /**
37
-     * @var array
38
-     */
39
-    protected $supportedOperators = [
40
-        '=' => 'equals',
41
-        'in' => 'in',
42
-        'like' => 'like',
43
-        '>' => 'greaterThan',
44
-        '>=' => 'greaterThanOrEqual',
45
-        '<' => 'lessThan',
46
-        '<=' => 'lessThanOrEqual'
47
-    ];
48
-
49
-    /**
50
-     * @var array
51
-     */
52
-    protected $equals = [];
53
-
54
-    /**
55
-     * @var array
56
-     */
57
-    protected $greaterThan = [];
58
-
59
-    /**
60
-     * @var array
61
-     */
62
-    protected $greaterThanOrEqual = [];
63
-
64
-    /**
65
-     * @var array
66
-     */
67
-    protected $lessThan = [];
68
-
69
-    /**
70
-     * @var array
71
-     */
72
-    protected $lessThanOrEqual = [];
73
-
74
-    /**
75
-     * @var array
76
-     */
77
-    protected $in = [];
78
-
79
-    /**
80
-     * @var array
81
-     */
82
-    protected $like = [];
83
-
84
-    /**
85
-     * @var string
86
-     */
87
-    protected $defaultLogicalSeparator = self::LOGICAL_AND;
88
-
89
-    /**
90
-     * @var string
91
-     */
92
-    protected $logicalSeparatorForEquals = self::LOGICAL_AND;
93
-
94
-    /**
95
-     * @var string
96
-     */
97
-    protected $logicalSeparatorForGreaterThan = self::LOGICAL_AND;
98
-
99
-    /**
100
-     * @var string
101
-     */
102
-    protected $logicalSeparatorForGreaterThanOrEqual = self::LOGICAL_AND;
103
-
104
-    /**
105
-     * @var string
106
-     */
107
-    protected $logicalSeparatorForLessThan = self::LOGICAL_AND;
108
-
109
-    /**
110
-     * @var string
111
-     */
112
-    protected $logicalSeparatorForLessThanOrEqual = self::LOGICAL_AND;
113
-
114
-    /**
115
-     * @var string
116
-     */
117
-    protected $logicalSeparatorForIn = self::LOGICAL_AND;
118
-
119
-    /**
120
-     * @var string
121
-     */
122
-    protected $logicalSeparatorForLike = self::LOGICAL_AND;
123
-
124
-    /**
125
-     * @var string
126
-     */
127
-    protected $logicalSeparatorForSearchTerm = self::LOGICAL_OR;
128
-
129
-    /**
130
-     * Constructs a new Matcher
131
-     *
132
-     * @param array $matches associative [$field => $value]
133
-     * @param string $dataType which corresponds to an entry of the TCA (table name).
134
-     * @return \Fab\Vidi\Persistence\Matcher
135
-     */
136
-    public function __construct($matches = [], $dataType = '')
137
-    {
138
-        $this->dataType = $dataType;
139
-        $this->matches = $matches;
140
-    }
141
-
142
-    /**
143
-     * @param string $searchTerm
144
-     * @return \Fab\Vidi\Persistence\Matcher
145
-     */
146
-    public function setSearchTerm($searchTerm)
147
-    {
148
-        $this->searchTerm = $searchTerm;
149
-        return $this;
150
-    }
151
-
152
-    /**
153
-     * @return string
154
-     */
155
-    public function getSearchTerm()
156
-    {
157
-        return $this->searchTerm;
158
-    }
159
-
160
-    /**
161
-     * @return array
162
-     */
163
-    public function getEquals()
164
-    {
165
-        return $this->equals;
166
-    }
167
-
168
-    /**
169
-     * @param $fieldNameAndPath
170
-     * @param $operand
171
-     * @return $this
172
-     */
173
-    public function equals($fieldNameAndPath, $operand)
174
-    {
175
-        $this->equals[] = ['fieldNameAndPath' => $fieldNameAndPath, 'operand' => $operand];
176
-        return $this;
177
-    }
178
-
179
-    /**
180
-     * @return array
181
-     */
182
-    public function getGreaterThan()
183
-    {
184
-        return $this->greaterThan;
185
-    }
186
-
187
-    /**
188
-     * @param $fieldNameAndPath
189
-     * @param $operand
190
-     * @return $this
191
-     */
192
-    public function greaterThan($fieldNameAndPath, $operand)
193
-    {
194
-        $this->greaterThan[] = ['fieldNameAndPath' => $fieldNameAndPath, 'operand' => $operand];
195
-        return $this;
196
-    }
197
-
198
-    /**
199
-     * @return array
200
-     */
201
-    public function getGreaterThanOrEqual()
202
-    {
203
-        return $this->greaterThanOrEqual;
204
-    }
205
-
206
-    /**
207
-     * @param $fieldNameAndPath
208
-     * @param $operand
209
-     * @return $this
210
-     */
211
-    public function greaterThanOrEqual($fieldNameAndPath, $operand)
212
-    {
213
-        $this->greaterThanOrEqual[] = ['fieldNameAndPath' => $fieldNameAndPath, 'operand' => $operand];
214
-        return $this;
215
-    }
216
-
217
-    /**
218
-     * @return array
219
-     */
220
-    public function getLessThan()
221
-    {
222
-        return $this->lessThan;
223
-    }
224
-
225
-    /**
226
-     * @param $fieldNameAndPath
227
-     * @param $operand
228
-     * @return $this
229
-     */
230
-    public function lessThan($fieldNameAndPath, $operand)
231
-    {
232
-        $this->lessThan[] = ['fieldNameAndPath' => $fieldNameAndPath, 'operand' => $operand];
233
-        return $this;
234
-    }
235
-
236
-    /**
237
-     * @return array
238
-     */
239
-    public function getLessThanOrEqual()
240
-    {
241
-        return $this->lessThanOrEqual;
242
-    }
243
-
244
-    /**
245
-     * @param $fieldNameAndPath
246
-     * @param $operand
247
-     * @return $this
248
-     */
249
-    public function lessThanOrEqual($fieldNameAndPath, $operand)
250
-    {
251
-        $this->lessThanOrEqual[] = ['fieldNameAndPath' => $fieldNameAndPath, 'operand' => $operand];
252
-        return $this;
253
-    }
254
-
255
-    /**
256
-     * @return array
257
-     */
258
-    public function getLike()
259
-    {
260
-        return $this->like;
261
-    }
262
-
263
-    /**
264
-     * @param $fieldNameAndPath
265
-     * @param $operand
266
-     * @return $this
267
-     */
268
-    public function in($fieldNameAndPath, $operand)
269
-    {
270
-        $this->in[] = ['fieldNameAndPath' => $fieldNameAndPath, 'operand' => $operand];
271
-        return $this;
272
-    }
273
-
274
-    /**
275
-     * @return array
276
-     */
277
-    public function getIn()
278
-    {
279
-        return $this->in;
280
-    }
281
-
282
-    /**
283
-     * @param $fieldNameAndPath
284
-     * @param $operand
285
-     * @param bool $addWildCard
286
-     * @return $this
287
-     */
288
-    public function like($fieldNameAndPath, $operand, $addWildCard = true)
289
-    {
290
-        $wildCardSymbol = $addWildCard ? '%' : '';
291
-        $this->like[] = ['fieldNameAndPath' => $fieldNameAndPath, 'operand' => $wildCardSymbol . $operand . $wildCardSymbol];
292
-        return $this;
293
-    }
294
-
295
-    /**
296
-     * @return array
297
-     */
298
-    public function getDefaultLogicalSeparator()
299
-    {
300
-        return $this->defaultLogicalSeparator;
301
-    }
302
-
303
-    /**
304
-     * @param string $defaultLogicalSeparator
305
-     * @return $this
306
-     */
307
-    public function setDefaultLogicalSeparator($defaultLogicalSeparator)
308
-    {
309
-        $this->defaultLogicalSeparator = $defaultLogicalSeparator;
310
-        return $this;
311
-    }
312
-
313
-    /**
314
-     * @return string
315
-     */
316
-    public function getLogicalSeparatorForEquals()
317
-    {
318
-        return $this->logicalSeparatorForEquals;
319
-    }
320
-
321
-    /**
322
-     * @param string $logicalSeparatorForEquals
323
-     * @return $this
324
-     */
325
-    public function setLogicalSeparatorForEquals($logicalSeparatorForEquals)
326
-    {
327
-        $this->logicalSeparatorForEquals = $logicalSeparatorForEquals;
328
-        return $this;
329
-    }
330
-
331
-    /**
332
-     * @return string
333
-     */
334
-    public function getLogicalSeparatorForGreaterThan()
335
-    {
336
-        return $this->logicalSeparatorForGreaterThan;
337
-    }
338
-
339
-    /**
340
-     * @param string $logicalSeparatorForGreaterThan
341
-     * @return $this
342
-     */
343
-    public function setLogicalSeparatorForGreaterThan($logicalSeparatorForGreaterThan)
344
-    {
345
-        $this->logicalSeparatorForGreaterThan = $logicalSeparatorForGreaterThan;
346
-        return $this;
347
-    }
348
-
349
-    /**
350
-     * @return string
351
-     */
352
-    public function getLogicalSeparatorForGreaterThanOrEqual()
353
-    {
354
-        return $this->logicalSeparatorForGreaterThanOrEqual;
355
-    }
356
-
357
-    /**
358
-     * @param string $logicalSeparatorForGreaterThanOrEqual
359
-     * @return $this
360
-     */
361
-    public function setLogicalSeparatorForGreaterThanOrEqual($logicalSeparatorForGreaterThanOrEqual)
362
-    {
363
-        $this->logicalSeparatorForGreaterThanOrEqual = $logicalSeparatorForGreaterThanOrEqual;
364
-        return $this;
365
-    }
366
-
367
-    /**
368
-     * @return string
369
-     */
370
-    public function getLogicalSeparatorForLessThan()
371
-    {
372
-        return $this->logicalSeparatorForLessThan;
373
-    }
374
-
375
-    /**
376
-     * @param string $logicalSeparatorForLessThan
377
-     * @return $this
378
-     */
379
-    public function setLogicalSeparatorForLessThan($logicalSeparatorForLessThan)
380
-    {
381
-        $this->logicalSeparatorForLessThan = $logicalSeparatorForLessThan;
382
-        return $this;
383
-    }
384
-
385
-    /**
386
-     * @return string
387
-     */
388
-    public function getLogicalSeparatorForLessThanOrEqual()
389
-    {
390
-        return $this->logicalSeparatorForLessThanOrEqual;
391
-    }
392
-
393
-    /**
394
-     * @param string $logicalSeparatorForLessThanOrEqual
395
-     * @return $this
396
-     */
397
-    public function setLogicalSeparatorForLessThanOrEqual($logicalSeparatorForLessThanOrEqual)
398
-    {
399
-        $this->logicalSeparatorForLessThanOrEqual = $logicalSeparatorForLessThanOrEqual;
400
-        return $this;
401
-    }
402
-
403
-    /**
404
-     * @return string
405
-     */
406
-    public function getLogicalSeparatorForIn()
407
-    {
408
-        return $this->logicalSeparatorForIn;
409
-    }
410
-
411
-    /**
412
-     * @param string $logicalSeparatorForIn
413
-     * @return $this
414
-     */
415
-    public function setLogicalSeparatorForIn($logicalSeparatorForIn)
416
-    {
417
-        $this->logicalSeparatorForIn = $logicalSeparatorForIn;
418
-        return $this;
419
-    }
420
-
421
-    /**
422
-     * @return string
423
-     */
424
-    public function getLogicalSeparatorForLike()
425
-    {
426
-        return $this->logicalSeparatorForLike;
427
-    }
428
-
429
-    /**
430
-     * @param string $logicalSeparatorForLike
431
-     * @return $this
432
-     */
433
-    public function setLogicalSeparatorForLike($logicalSeparatorForLike)
434
-    {
435
-        $this->logicalSeparatorForLike = $logicalSeparatorForLike;
436
-        return $this;
437
-    }
438
-
439
-    /**
440
-     * @return string
441
-     */
442
-    public function getLogicalSeparatorForSearchTerm()
443
-    {
444
-        return $this->logicalSeparatorForSearchTerm;
445
-    }
446
-
447
-    /**
448
-     * @param string $logicalSeparatorForSearchTerm
449
-     * @return $this
450
-     */
451
-    public function setLogicalSeparatorForSearchTerm($logicalSeparatorForSearchTerm)
452
-    {
453
-        $this->logicalSeparatorForSearchTerm = $logicalSeparatorForSearchTerm;
454
-        return $this;
455
-    }
456
-
457
-    /**
458
-     * @return array
459
-     */
460
-    public function getSupportedOperators()
461
-    {
462
-        return $this->supportedOperators;
463
-    }
464
-
465
-    /**
466
-     * @return string
467
-     */
468
-    public function getDataType()
469
-    {
470
-        return $this->dataType;
471
-    }
472
-
473
-    /**
474
-     * @param string $dataType
475
-     * @return $this
476
-     */
477
-    public function setDataType($dataType)
478
-    {
479
-        $this->dataType = $dataType;
480
-        return $this;
481
-    }
16
+	/**
17
+	 * The logical OR
18
+	 */
19
+	const LOGICAL_OR = 'logicalOr';
20
+
21
+	/**
22
+	 * The logical AND
23
+	 */
24
+	const LOGICAL_AND = 'logicalAnd';
25
+
26
+	/**
27
+	 * @var string
28
+	 */
29
+	protected $dataType = '';
30
+
31
+	/**
32
+	 * @var string
33
+	 */
34
+	protected $searchTerm = '';
35
+
36
+	/**
37
+	 * @var array
38
+	 */
39
+	protected $supportedOperators = [
40
+		'=' => 'equals',
41
+		'in' => 'in',
42
+		'like' => 'like',
43
+		'>' => 'greaterThan',
44
+		'>=' => 'greaterThanOrEqual',
45
+		'<' => 'lessThan',
46
+		'<=' => 'lessThanOrEqual'
47
+	];
48
+
49
+	/**
50
+	 * @var array
51
+	 */
52
+	protected $equals = [];
53
+
54
+	/**
55
+	 * @var array
56
+	 */
57
+	protected $greaterThan = [];
58
+
59
+	/**
60
+	 * @var array
61
+	 */
62
+	protected $greaterThanOrEqual = [];
63
+
64
+	/**
65
+	 * @var array
66
+	 */
67
+	protected $lessThan = [];
68
+
69
+	/**
70
+	 * @var array
71
+	 */
72
+	protected $lessThanOrEqual = [];
73
+
74
+	/**
75
+	 * @var array
76
+	 */
77
+	protected $in = [];
78
+
79
+	/**
80
+	 * @var array
81
+	 */
82
+	protected $like = [];
83
+
84
+	/**
85
+	 * @var string
86
+	 */
87
+	protected $defaultLogicalSeparator = self::LOGICAL_AND;
88
+
89
+	/**
90
+	 * @var string
91
+	 */
92
+	protected $logicalSeparatorForEquals = self::LOGICAL_AND;
93
+
94
+	/**
95
+	 * @var string
96
+	 */
97
+	protected $logicalSeparatorForGreaterThan = self::LOGICAL_AND;
98
+
99
+	/**
100
+	 * @var string
101
+	 */
102
+	protected $logicalSeparatorForGreaterThanOrEqual = self::LOGICAL_AND;
103
+
104
+	/**
105
+	 * @var string
106
+	 */
107
+	protected $logicalSeparatorForLessThan = self::LOGICAL_AND;
108
+
109
+	/**
110
+	 * @var string
111
+	 */
112
+	protected $logicalSeparatorForLessThanOrEqual = self::LOGICAL_AND;
113
+
114
+	/**
115
+	 * @var string
116
+	 */
117
+	protected $logicalSeparatorForIn = self::LOGICAL_AND;
118
+
119
+	/**
120
+	 * @var string
121
+	 */
122
+	protected $logicalSeparatorForLike = self::LOGICAL_AND;
123
+
124
+	/**
125
+	 * @var string
126
+	 */
127
+	protected $logicalSeparatorForSearchTerm = self::LOGICAL_OR;
128
+
129
+	/**
130
+	 * Constructs a new Matcher
131
+	 *
132
+	 * @param array $matches associative [$field => $value]
133
+	 * @param string $dataType which corresponds to an entry of the TCA (table name).
134
+	 * @return \Fab\Vidi\Persistence\Matcher
135
+	 */
136
+	public function __construct($matches = [], $dataType = '')
137
+	{
138
+		$this->dataType = $dataType;
139
+		$this->matches = $matches;
140
+	}
141
+
142
+	/**
143
+	 * @param string $searchTerm
144
+	 * @return \Fab\Vidi\Persistence\Matcher
145
+	 */
146
+	public function setSearchTerm($searchTerm)
147
+	{
148
+		$this->searchTerm = $searchTerm;
149
+		return $this;
150
+	}
151
+
152
+	/**
153
+	 * @return string
154
+	 */
155
+	public function getSearchTerm()
156
+	{
157
+		return $this->searchTerm;
158
+	}
159
+
160
+	/**
161
+	 * @return array
162
+	 */
163
+	public function getEquals()
164
+	{
165
+		return $this->equals;
166
+	}
167
+
168
+	/**
169
+	 * @param $fieldNameAndPath
170
+	 * @param $operand
171
+	 * @return $this
172
+	 */
173
+	public function equals($fieldNameAndPath, $operand)
174
+	{
175
+		$this->equals[] = ['fieldNameAndPath' => $fieldNameAndPath, 'operand' => $operand];
176
+		return $this;
177
+	}
178
+
179
+	/**
180
+	 * @return array
181
+	 */
182
+	public function getGreaterThan()
183
+	{
184
+		return $this->greaterThan;
185
+	}
186
+
187
+	/**
188
+	 * @param $fieldNameAndPath
189
+	 * @param $operand
190
+	 * @return $this
191
+	 */
192
+	public function greaterThan($fieldNameAndPath, $operand)
193
+	{
194
+		$this->greaterThan[] = ['fieldNameAndPath' => $fieldNameAndPath, 'operand' => $operand];
195
+		return $this;
196
+	}
197
+
198
+	/**
199
+	 * @return array
200
+	 */
201
+	public function getGreaterThanOrEqual()
202
+	{
203
+		return $this->greaterThanOrEqual;
204
+	}
205
+
206
+	/**
207
+	 * @param $fieldNameAndPath
208
+	 * @param $operand
209
+	 * @return $this
210
+	 */
211
+	public function greaterThanOrEqual($fieldNameAndPath, $operand)
212
+	{
213
+		$this->greaterThanOrEqual[] = ['fieldNameAndPath' => $fieldNameAndPath, 'operand' => $operand];
214
+		return $this;
215
+	}
216
+
217
+	/**
218
+	 * @return array
219
+	 */
220
+	public function getLessThan()
221
+	{
222
+		return $this->lessThan;
223
+	}
224
+
225
+	/**
226
+	 * @param $fieldNameAndPath
227
+	 * @param $operand
228
+	 * @return $this
229
+	 */
230
+	public function lessThan($fieldNameAndPath, $operand)
231
+	{
232
+		$this->lessThan[] = ['fieldNameAndPath' => $fieldNameAndPath, 'operand' => $operand];
233
+		return $this;
234
+	}
235
+
236
+	/**
237
+	 * @return array
238
+	 */
239
+	public function getLessThanOrEqual()
240
+	{
241
+		return $this->lessThanOrEqual;
242
+	}
243
+
244
+	/**
245
+	 * @param $fieldNameAndPath
246
+	 * @param $operand
247
+	 * @return $this
248
+	 */
249
+	public function lessThanOrEqual($fieldNameAndPath, $operand)
250
+	{
251
+		$this->lessThanOrEqual[] = ['fieldNameAndPath' => $fieldNameAndPath, 'operand' => $operand];
252
+		return $this;
253
+	}
254
+
255
+	/**
256
+	 * @return array
257
+	 */
258
+	public function getLike()
259
+	{
260
+		return $this->like;
261
+	}
262
+
263
+	/**
264
+	 * @param $fieldNameAndPath
265
+	 * @param $operand
266
+	 * @return $this
267
+	 */
268
+	public function in($fieldNameAndPath, $operand)
269
+	{
270
+		$this->in[] = ['fieldNameAndPath' => $fieldNameAndPath, 'operand' => $operand];
271
+		return $this;
272
+	}
273
+
274
+	/**
275
+	 * @return array
276
+	 */
277
+	public function getIn()
278
+	{
279
+		return $this->in;
280
+	}
281
+
282
+	/**
283
+	 * @param $fieldNameAndPath
284
+	 * @param $operand
285
+	 * @param bool $addWildCard
286
+	 * @return $this
287
+	 */
288
+	public function like($fieldNameAndPath, $operand, $addWildCard = true)
289
+	{
290
+		$wildCardSymbol = $addWildCard ? '%' : '';
291
+		$this->like[] = ['fieldNameAndPath' => $fieldNameAndPath, 'operand' => $wildCardSymbol . $operand . $wildCardSymbol];
292
+		return $this;
293
+	}
294
+
295
+	/**
296
+	 * @return array
297
+	 */
298
+	public function getDefaultLogicalSeparator()
299
+	{
300
+		return $this->defaultLogicalSeparator;
301
+	}
302
+
303
+	/**
304
+	 * @param string $defaultLogicalSeparator
305
+	 * @return $this
306
+	 */
307
+	public function setDefaultLogicalSeparator($defaultLogicalSeparator)
308
+	{
309
+		$this->defaultLogicalSeparator = $defaultLogicalSeparator;
310
+		return $this;
311
+	}
312
+
313
+	/**
314
+	 * @return string
315
+	 */
316
+	public function getLogicalSeparatorForEquals()
317
+	{
318
+		return $this->logicalSeparatorForEquals;
319
+	}
320
+
321
+	/**
322
+	 * @param string $logicalSeparatorForEquals
323
+	 * @return $this
324
+	 */
325
+	public function setLogicalSeparatorForEquals($logicalSeparatorForEquals)
326
+	{
327
+		$this->logicalSeparatorForEquals = $logicalSeparatorForEquals;
328
+		return $this;
329
+	}
330
+
331
+	/**
332
+	 * @return string
333
+	 */
334
+	public function getLogicalSeparatorForGreaterThan()
335
+	{
336
+		return $this->logicalSeparatorForGreaterThan;
337
+	}
338
+
339
+	/**
340
+	 * @param string $logicalSeparatorForGreaterThan
341
+	 * @return $this
342
+	 */
343
+	public function setLogicalSeparatorForGreaterThan($logicalSeparatorForGreaterThan)
344
+	{
345
+		$this->logicalSeparatorForGreaterThan = $logicalSeparatorForGreaterThan;
346
+		return $this;
347
+	}
348
+
349
+	/**
350
+	 * @return string
351
+	 */
352
+	public function getLogicalSeparatorForGreaterThanOrEqual()
353
+	{
354
+		return $this->logicalSeparatorForGreaterThanOrEqual;
355
+	}
356
+
357
+	/**
358
+	 * @param string $logicalSeparatorForGreaterThanOrEqual
359
+	 * @return $this
360
+	 */
361
+	public function setLogicalSeparatorForGreaterThanOrEqual($logicalSeparatorForGreaterThanOrEqual)
362
+	{
363
+		$this->logicalSeparatorForGreaterThanOrEqual = $logicalSeparatorForGreaterThanOrEqual;
364
+		return $this;
365
+	}
366
+
367
+	/**
368
+	 * @return string
369
+	 */
370
+	public function getLogicalSeparatorForLessThan()
371
+	{
372
+		return $this->logicalSeparatorForLessThan;
373
+	}
374
+
375
+	/**
376
+	 * @param string $logicalSeparatorForLessThan
377
+	 * @return $this
378
+	 */
379
+	public function setLogicalSeparatorForLessThan($logicalSeparatorForLessThan)
380
+	{
381
+		$this->logicalSeparatorForLessThan = $logicalSeparatorForLessThan;
382
+		return $this;
383
+	}
384
+
385
+	/**
386
+	 * @return string
387
+	 */
388
+	public function getLogicalSeparatorForLessThanOrEqual()
389
+	{
390
+		return $this->logicalSeparatorForLessThanOrEqual;
391
+	}
392
+
393
+	/**
394
+	 * @param string $logicalSeparatorForLessThanOrEqual
395
+	 * @return $this
396
+	 */
397
+	public function setLogicalSeparatorForLessThanOrEqual($logicalSeparatorForLessThanOrEqual)
398
+	{
399
+		$this->logicalSeparatorForLessThanOrEqual = $logicalSeparatorForLessThanOrEqual;
400
+		return $this;
401
+	}
402
+
403
+	/**
404
+	 * @return string
405
+	 */
406
+	public function getLogicalSeparatorForIn()
407
+	{
408
+		return $this->logicalSeparatorForIn;
409
+	}
410
+
411
+	/**
412
+	 * @param string $logicalSeparatorForIn
413
+	 * @return $this
414
+	 */
415
+	public function setLogicalSeparatorForIn($logicalSeparatorForIn)
416
+	{
417
+		$this->logicalSeparatorForIn = $logicalSeparatorForIn;
418
+		return $this;
419
+	}
420
+
421
+	/**
422
+	 * @return string
423
+	 */
424
+	public function getLogicalSeparatorForLike()
425
+	{
426
+		return $this->logicalSeparatorForLike;
427
+	}
428
+
429
+	/**
430
+	 * @param string $logicalSeparatorForLike
431
+	 * @return $this
432
+	 */
433
+	public function setLogicalSeparatorForLike($logicalSeparatorForLike)
434
+	{
435
+		$this->logicalSeparatorForLike = $logicalSeparatorForLike;
436
+		return $this;
437
+	}
438
+
439
+	/**
440
+	 * @return string
441
+	 */
442
+	public function getLogicalSeparatorForSearchTerm()
443
+	{
444
+		return $this->logicalSeparatorForSearchTerm;
445
+	}
446
+
447
+	/**
448
+	 * @param string $logicalSeparatorForSearchTerm
449
+	 * @return $this
450
+	 */
451
+	public function setLogicalSeparatorForSearchTerm($logicalSeparatorForSearchTerm)
452
+	{
453
+		$this->logicalSeparatorForSearchTerm = $logicalSeparatorForSearchTerm;
454
+		return $this;
455
+	}
456
+
457
+	/**
458
+	 * @return array
459
+	 */
460
+	public function getSupportedOperators()
461
+	{
462
+		return $this->supportedOperators;
463
+	}
464
+
465
+	/**
466
+	 * @return string
467
+	 */
468
+	public function getDataType()
469
+	{
470
+		return $this->dataType;
471
+	}
472
+
473
+	/**
474
+	 * @param string $dataType
475
+	 * @return $this
476
+	 */
477
+	public function setDataType($dataType)
478
+	{
479
+		$this->dataType = $dataType;
480
+		return $this;
481
+	}
482 482
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -288,7 +288,7 @@
 block discarded – undo
288 288
     public function like($fieldNameAndPath, $operand, $addWildCard = true)
289 289
     {
290 290
         $wildCardSymbol = $addWildCard ? '%' : '';
291
-        $this->like[] = ['fieldNameAndPath' => $fieldNameAndPath, 'operand' => $wildCardSymbol . $operand . $wildCardSymbol];
291
+        $this->like[] = ['fieldNameAndPath' => $fieldNameAndPath, 'operand' => $wildCardSymbol.$operand.$wildCardSymbol];
292 292
         return $this;
293 293
     }
294 294
 
Please login to merge, or discard this patch.
Classes/Persistence/Query.php 3 patches
Doc Comments   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -290,7 +290,7 @@  discard block
 block discarded – undo
290 290
      * 'bar' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_DESCENDING
291 291
      * )
292 292
      *
293
-     * @return array
293
+     * @return integer
294 294
      * @api
295 295
      */
296 296
     public function getOrderings()
@@ -483,7 +483,7 @@  discard block
 block discarded – undo
483 483
      * Returns a like criterion used for matching objects against a query
484 484
      *
485 485
      * @param string $propertyName The name of the property to compare against
486
-     * @param mixed $operand The value to compare with
486
+     * @param string $operand The value to compare with
487 487
      * @param boolean $caseSensitive Whether the matching should be done case-sensitive
488 488
      * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
489 489
      * @api
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -193,8 +193,8 @@
 block discarded – undo
193 193
             $configuration = $backendConfigurationManager->getTypoScriptSetup();
194 194
             $querySettings = array('respectSysLanguage');
195 195
             foreach ($querySettings as $setting) {
196
-                if (isset($configuration['config.']['tx_vidi.']['persistence.']['backend.'][$this->type . '.'][$setting])) {
197
-                    $value = (bool)$configuration['config.']['tx_vidi.']['persistence.']['backend.'][$this->type . '.'][$setting];
196
+                if (isset($configuration['config.']['tx_vidi.']['persistence.']['backend.'][$this->type.'.'][$setting])) {
197
+                    $value = (bool)$configuration['config.']['tx_vidi.']['persistence.']['backend.'][$this->type.'.'][$setting];
198 198
                     ObjectAccess::setProperty($this->querySettings, $setting, $value);
199 199
                 }
200 200
             }
Please login to merge, or discard this patch.
Indentation   +644 added lines, -644 removed lines patch added patch discarded remove patch
@@ -23,649 +23,649 @@
 block discarded – undo
23 23
 class Query implements QueryInterface
24 24
 {
25 25
 
26
-    /**
27
-     * An inner join.
28
-     */
29
-    const JCR_JOIN_TYPE_INNER = '{http://www.jcp.org/jcr/1.0}joinTypeInner';
30
-
31
-    /**
32
-     * A left-outer join.
33
-     */
34
-    const JCR_JOIN_TYPE_LEFT_OUTER = '{http://www.jcp.org/jcr/1.0}joinTypeLeftOuter';
35
-
36
-    /**
37
-     * A right-outer join.
38
-     */
39
-    const JCR_JOIN_TYPE_RIGHT_OUTER = '{http://www.jcp.org/jcr/1.0}joinTypeRightOuter';
40
-
41
-    /**
42
-     * Charset of strings in QOM
43
-     */
44
-    const CHARSET = 'utf-8';
45
-
46
-    /**
47
-     * @var string
48
-     */
49
-    protected $sourceFieldName;
50
-
51
-    /**
52
-     * @var string
53
-     */
54
-    protected $type;
55
-
56
-    /**
57
-     * @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
58
-     */
59
-    protected $objectManager;
60
-
61
-    /**
62
-     * @var \TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface
63
-     */
64
-    protected $persistenceManager;
65
-
66
-    /**
67
-     * @var \TYPO3\CMS\Extbase\Persistence\Generic\Qom\QueryObjectModelFactory
68
-     */
69
-    protected $qomFactory;
70
-
71
-    /**
72
-     * @var \TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInterface
73
-     */
74
-    protected $source;
75
-
76
-    /**
77
-     * @var ConstraintInterface
78
-     */
79
-    protected $constraint;
80
-
81
-    /**
82
-     * @var \TYPO3\CMS\Extbase\Persistence\Generic\Qom\Statement
83
-     */
84
-    protected $statement;
85
-
86
-    /**
87
-     * @var int
88
-     */
89
-    protected $orderings = [];
90
-
91
-    /**
92
-     * @var int
93
-     */
94
-    protected $limit;
95
-
96
-    /**
97
-     * @var int
98
-     */
99
-    protected $offset;
100
-
101
-    /**
102
-     * Apply DISTINCT upon property.
103
-     *
104
-     * @var string
105
-     */
106
-    protected $distinct;
107
-
108
-    /**
109
-     * The query settings.
110
-     *
111
-     * @var \Fab\Vidi\Persistence\QuerySettings
112
-     * @inject
113
-     */
114
-    protected $querySettings;
115
-
116
-    /**
117
-     * Constructs a query object working on the given class name
118
-     *
119
-     * @param string $type
120
-     */
121
-    public function __construct($type)
122
-    {
123
-        $this->type = $type;
124
-    }
125
-
126
-    /**
127
-     * @param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager
128
-     * @return void
129
-     */
130
-    public function injectObjectManager(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager)
131
-    {
132
-        $this->objectManager = $objectManager;
133
-    }
134
-
135
-    /**
136
-     * Injects the persistence manager, used to fetch the CR session
137
-     *
138
-     * @param \TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface $persistenceManager
139
-     * @return void
140
-     */
141
-    public function injectPersistenceManager(\TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface $persistenceManager)
142
-    {
143
-        $this->persistenceManager = $persistenceManager;
144
-    }
145
-
146
-    /**
147
-     * Injects the Query Object Model Factory
148
-     *
149
-     * @param \TYPO3\CMS\Extbase\Persistence\Generic\Qom\QueryObjectModelFactory $qomFactory
150
-     * @return void
151
-     */
152
-    public function injectQomFactory(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\QueryObjectModelFactory $qomFactory)
153
-    {
154
-        $this->qomFactory = $qomFactory;
155
-    }
156
-
157
-    /**
158
-     * Sets the Query Settings. These Query settings must match the settings expected by
159
-     * the specific Storage Backend.
160
-     *
161
-     * @param \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface $querySettings The Query Settings
162
-     * @return void
163
-     * @api This method is not part of FLOW3 API
164
-     */
165
-    public function setQuerySettings(\TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface $querySettings)
166
-    {
167
-        $this->querySettings = $querySettings;
168
-    }
169
-
170
-    /**
171
-     * Returns the Query Settings.
172
-     *
173
-     * @throws \Exception
174
-     * @return \Fab\Vidi\Persistence\QuerySettings $querySettings The Query Settings
175
-     * @api This method is not part of FLOW3 API
176
-     */
177
-    public function getQuerySettings()
178
-    {
179
-        if (!$this->querySettings instanceof \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface) {
180
-            throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception('Tried to get the query settings without setting them before.', 1248689115);
181
-        }
182
-
183
-        // Apply possible settings to the query.
184
-        if ($this->isBackendMode()) {
185
-            /** @var \TYPO3\CMS\Extbase\Configuration\BackendConfigurationManager $backendConfigurationManager */
186
-            $backendConfigurationManager = $this->objectManager->get('TYPO3\CMS\Extbase\Configuration\BackendConfigurationManager');
187
-            $configuration = $backendConfigurationManager->getTypoScriptSetup();
188
-            $querySettings = array('respectSysLanguage');
189
-            foreach ($querySettings as $setting) {
190
-                if (isset($configuration['config.']['tx_vidi.']['persistence.']['backend.'][$this->type . '.'][$setting])) {
191
-                    $value = (bool)$configuration['config.']['tx_vidi.']['persistence.']['backend.'][$this->type . '.'][$setting];
192
-                    ObjectAccess::setProperty($this->querySettings, $setting, $value);
193
-                }
194
-            }
195
-        }
196
-
197
-        return $this->querySettings;
198
-    }
199
-
200
-    /**
201
-     * Returns the type this query cares for.
202
-     *
203
-     * @return string
204
-     * @api
205
-     */
206
-    public function getType()
207
-    {
208
-        return $this->type;
209
-    }
210
-
211
-    /**
212
-     * Sets the source to fetch the result from
213
-     *
214
-     * @param \TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInterface $source
215
-     */
216
-    public function setSource(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInterface $source)
217
-    {
218
-        $this->source = $source;
219
-    }
220
-
221
-    /**
222
-     * Returns the selectorn name or an empty string, if the source is not a selector
223
-     * TODO This has to be checked at another place
224
-     *
225
-     * @return string The selector name
226
-     */
227
-    protected function getSelectorName()
228
-    {
229
-        if ($this->getSource() instanceof \TYPO3\CMS\Extbase\Persistence\Generic\Qom\SelectorInterface) {
230
-            return $this->source->getSelectorName();
231
-        } else {
232
-            return '';
233
-        }
234
-    }
235
-
236
-    /**
237
-     * Gets the node-tuple source for this query.
238
-     *
239
-     * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInterface the node-tuple source; non-null
240
-     */
241
-    public function getSource()
242
-    {
243
-        if ($this->source === null) {
244
-            $this->source = $this->qomFactory->selector($this->getType());
245
-        }
246
-        return $this->source;
247
-    }
248
-
249
-    /**
250
-     * Executes the query against the database and returns the result
251
-     *
252
-     * @return \TYPO3\CMS\Extbase\Persistence\QueryResultInterface|array The query result object or an array if $this->getQuerySettings()->getReturnRawQueryResult() is true
253
-     * @api
254
-     */
255
-    public function execute($returnRawQueryResult = false)
256
-    {
257
-        /** @var \Fab\Vidi\Persistence\Storage\VidiDbBackend $backend */
258
-        $backend = $this->objectManager->get('Fab\Vidi\Persistence\Storage\VidiDbBackend', $this);
259
-        return $backend->fetchResult();
260
-    }
261
-
262
-    /**
263
-     * Sets the property names to order the result by. Expected like this:
264
-     * array(
265
-     * 'foo' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_ASCENDING,
266
-     * 'bar' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_DESCENDING
267
-     * )
268
-     * where 'foo' and 'bar' are property names.
269
-     *
270
-     * @param array $orderings The property names to order by
271
-     * @return QueryInterface
272
-     * @api
273
-     */
274
-    public function setOrderings(array $orderings)
275
-    {
276
-        $this->orderings = $orderings;
277
-        return $this;
278
-    }
279
-
280
-    /**
281
-     * Returns the property names to order the result by. Like this:
282
-     * array(
283
-     * 'foo' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_ASCENDING,
284
-     * 'bar' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_DESCENDING
285
-     * )
286
-     *
287
-     * @return array
288
-     * @api
289
-     */
290
-    public function getOrderings()
291
-    {
292
-        return $this->orderings;
293
-    }
294
-
295
-    /**
296
-     * Sets the maximum size of the result set to limit. Returns $this to allow
297
-     * for chaining (fluid interface)
298
-     *
299
-     * @param integer $limit
300
-     * @throws \InvalidArgumentException
301
-     * @return QueryInterface
302
-     * @api
303
-     */
304
-    public function setLimit($limit)
305
-    {
306
-        if (!is_int($limit) || $limit < 1) {
307
-            throw new \InvalidArgumentException('The limit must be an integer >= 1', 1245071870);
308
-        }
309
-        $this->limit = $limit;
310
-        return $this;
311
-    }
312
-
313
-    /**
314
-     * Resets a previously set maximum size of the result set. Returns $this to allow
315
-     * for chaining (fluid interface)
316
-     *
317
-     * @return QueryInterface
318
-     * @api
319
-     */
320
-    public function unsetLimit()
321
-    {
322
-        unset($this->limit);
323
-        return $this;
324
-    }
325
-
326
-    /**
327
-     * Returns the maximum size of the result set to limit.
328
-     *
329
-     * @return integer
330
-     * @api
331
-     */
332
-    public function getLimit()
333
-    {
334
-        return $this->limit;
335
-    }
336
-
337
-    /**
338
-     * Sets the start offset of the result set to offset. Returns $this to
339
-     * allow for chaining (fluid interface)
340
-     *
341
-     * @param integer $offset
342
-     * @throws \InvalidArgumentException
343
-     * @return QueryInterface
344
-     * @api
345
-     */
346
-    public function setOffset($offset)
347
-    {
348
-        if (!is_int($offset) || $offset < 0) {
349
-            throw new \InvalidArgumentException('The offset must be a positive integer', 1245071872);
350
-        }
351
-        $this->offset = $offset;
352
-        return $this;
353
-    }
354
-
355
-    /**
356
-     * Returns the start offset of the result set.
357
-     *
358
-     * @return integer
359
-     * @api
360
-     */
361
-    public function getOffset()
362
-    {
363
-        return $this->offset;
364
-    }
365
-
366
-    /**
367
-     * The constraint used to limit the result set. Returns $this to allow
368
-     * for chaining (fluid interface)
369
-     *
370
-     * @param ConstraintInterface $constraint
371
-     * @return QueryInterface
372
-     * @api
373
-     */
374
-    public function matching($constraint)
375
-    {
376
-        $this->constraint = $constraint;
377
-        return $this;
378
-    }
379
-
380
-    /**
381
-     * Gets the constraint for this query.
382
-     *
383
-     * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\Constraint the constraint, or null if none
384
-     * @api
385
-     */
386
-    public function getConstraint()
387
-    {
388
-        return $this->constraint;
389
-    }
390
-
391
-    /**
392
-     * Performs a logical conjunction of the given constraints. The method takes one or more contraints and concatenates them with a boolean AND.
393
-     * It also scepts a single array of constraints to be concatenated.
394
-     *
395
-     * @param mixed $constraint1 The first of multiple constraints or an array of constraints.
396
-     * @throws InvalidNumberOfConstraintsException
397
-     * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\AndInterface
398
-     * @api
399
-     */
400
-    public function logicalAnd($constraint1)
401
-    {
402
-        if (is_array($constraint1)) {
403
-            $resultingConstraint = array_shift($constraint1);
404
-            $constraints = $constraint1;
405
-        } else {
406
-            $constraints = func_get_args();
407
-            $resultingConstraint = array_shift($constraints);
408
-        }
409
-        if ($resultingConstraint === null) {
410
-            throw new InvalidNumberOfConstraintsException('There must be at least one constraint or a non-empty array of constraints given.', 1401289500);
411
-        }
412
-        foreach ($constraints as $constraint) {
413
-            $resultingConstraint = $this->qomFactory->_and($resultingConstraint, $constraint);
414
-        }
415
-        return $resultingConstraint;
416
-    }
417
-
418
-    /**
419
-     * Performs a logical disjunction of the two given constraints
420
-     *
421
-     * @param mixed $constraint1 The first of multiple constraints or an array of constraints.
422
-     * @throws InvalidNumberOfConstraintsException
423
-     * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\OrInterface
424
-     * @api
425
-     */
426
-    public function logicalOr($constraint1)
427
-    {
428
-        if (is_array($constraint1)) {
429
-            $resultingConstraint = array_shift($constraint1);
430
-            $constraints = $constraint1;
431
-        } else {
432
-            $constraints = func_get_args();
433
-            $resultingConstraint = array_shift($constraints);
434
-        }
435
-        if ($resultingConstraint === null) {
436
-            throw new InvalidNumberOfConstraintsException('There must be at least one constraint or a non-empty array of constraints given.', 1401289501);
437
-        }
438
-        foreach ($constraints as $constraint) {
439
-            $resultingConstraint = $this->qomFactory->_or($resultingConstraint, $constraint);
440
-        }
441
-        return $resultingConstraint;
442
-    }
443
-
444
-    /**
445
-     * Performs a logical negation of the given constraint
446
-     *
447
-     * @param ConstraintInterface $constraint Constraint to negate
448
-     * @throws \RuntimeException
449
-     * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\NotInterface
450
-     * @api
451
-     */
452
-    public function logicalNot(ConstraintInterface $constraint)
453
-    {
454
-        return $this->qomFactory->not($constraint);
455
-    }
456
-
457
-    /**
458
-     * Returns an equals criterion used for matching objects against a query
459
-     *
460
-     * @param string $propertyName The name of the property to compare against
461
-     * @param mixed $operand The value to compare with
462
-     * @param boolean $caseSensitive Whether the equality test should be done case-sensitive
463
-     * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
464
-     * @api
465
-     */
466
-    public function equals($propertyName, $operand, $caseSensitive = true)
467
-    {
468
-        if (is_object($operand) || $caseSensitive) {
469
-            $comparison = $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_EQUAL_TO, $operand);
470
-        } else {
471
-            $comparison = $this->qomFactory->comparison($this->qomFactory->lowerCase($this->qomFactory->propertyValue($propertyName, $this->getSelectorName())), QueryInterface::OPERATOR_EQUAL_TO, \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Charset\\CharsetConverter')->conv_case(\TYPO3\CMS\Extbase\Persistence\Generic\Query::CHARSET, $operand, 'toLower'));
472
-        }
473
-        return $comparison;
474
-    }
475
-
476
-    /**
477
-     * Returns a like criterion used for matching objects against a query
478
-     *
479
-     * @param string $propertyName The name of the property to compare against
480
-     * @param mixed $operand The value to compare with
481
-     * @param boolean $caseSensitive Whether the matching should be done case-sensitive
482
-     * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
483
-     * @api
484
-     */
485
-    public function like($propertyName, $operand, $caseSensitive = true)
486
-    {
487
-        return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_LIKE, $operand);
488
-    }
489
-
490
-    /**
491
-     * Returns a "contains" criterion used for matching objects against a query.
492
-     * It matches if the multivalued property contains the given operand.
493
-     *
494
-     * @param string $propertyName The name of the (multivalued) property to compare against
495
-     * @param mixed $operand The value to compare with
496
-     * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
497
-     * @api
498
-     */
499
-    public function contains($propertyName, $operand)
500
-    {
501
-        return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_CONTAINS, $operand);
502
-    }
503
-
504
-    /**
505
-     * Returns an "in" criterion used for matching objects against a query. It
506
-     * matches if the property's value is contained in the multivalued operand.
507
-     *
508
-     * @param string $propertyName The name of the property to compare against
509
-     * @param mixed $operand The value to compare with, multivalued
510
-     * @throws UnexpectedTypeException
511
-     * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
512
-     * @api
513
-     */
514
-    public function in($propertyName, $operand)
515
-    {
516
-        if (!is_array($operand) && !$operand instanceof \ArrayAccess && !$operand instanceof \Traversable) {
517
-            throw new UnexpectedTypeException('The "in" operator must be given a mutlivalued operand (array, ArrayAccess, Traversable).', 1264678095);
518
-        }
519
-        return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_IN, $operand);
520
-    }
521
-
522
-    /**
523
-     * Returns a less than criterion used for matching objects against a query
524
-     *
525
-     * @param string $propertyName The name of the property to compare against
526
-     * @param mixed $operand The value to compare with
527
-     * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
528
-     * @api
529
-     */
530
-    public function lessThan($propertyName, $operand)
531
-    {
532
-        return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_LESS_THAN, $operand);
533
-    }
534
-
535
-    /**
536
-     * Returns a less or equal than criterion used for matching objects against a query
537
-     *
538
-     * @param string $propertyName The name of the property to compare against
539
-     * @param mixed $operand The value to compare with
540
-     * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
541
-     * @api
542
-     */
543
-    public function lessThanOrEqual($propertyName, $operand)
544
-    {
545
-        return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_LESS_THAN_OR_EQUAL_TO, $operand);
546
-    }
547
-
548
-    /**
549
-     * Returns a greater than criterion used for matching objects against a query
550
-     *
551
-     * @param string $propertyName The name of the property to compare against
552
-     * @param mixed $operand The value to compare with
553
-     * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
554
-     * @api
555
-     */
556
-    public function greaterThan($propertyName, $operand)
557
-    {
558
-        return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_GREATER_THAN, $operand);
559
-    }
560
-
561
-    /**
562
-     * Returns a greater than or equal criterion used for matching objects against a query
563
-     *
564
-     * @param string $propertyName The name of the property to compare against
565
-     * @param mixed $operand The value to compare with
566
-     * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
567
-     * @api
568
-     */
569
-    public function greaterThanOrEqual($propertyName, $operand)
570
-    {
571
-        return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_GREATER_THAN_OR_EQUAL_TO, $operand);
572
-    }
573
-
574
-    /**
575
-     * Returns the query result count.
576
-     *
577
-     * @return integer The query result count
578
-     * @api
579
-     */
580
-    public function count()
581
-    {
582
-        /** @var \Fab\Vidi\Persistence\Storage\VidiDbBackend $backend */
583
-        $backend = $this->objectManager->get('Fab\Vidi\Persistence\Storage\VidiDbBackend', $this);
584
-        return $backend->countResult();
585
-    }
586
-
587
-    /**
588
-     * Returns an "isEmpty" criterion used for matching objects against a query.
589
-     * It matches if the multivalued property contains no values or is null.
590
-     *
591
-     * @param string $propertyName The name of the multivalued property to compare against
592
-     * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\NotImplementedException
593
-     * @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException if used on a single-valued property
594
-     * @api
595
-     */
596
-    public function isEmpty($propertyName)
597
-    {
598
-        throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\NotImplementedException(__METHOD__);
599
-    }
600
-
601
-    /**
602
-     * @return string
603
-     */
604
-    public function getDistinct()
605
-    {
606
-        return $this->distinct;
607
-    }
608
-
609
-    /**
610
-     * @param string $distinct
611
-     * @return $this
612
-     */
613
-    public function setDistinct($distinct)
614
-    {
615
-        $this->distinct = $distinct;
616
-        return $this;
617
-    }
618
-
619
-    /**
620
-     * Sets the statement of this query. If you use this, you will lose the abstraction from a concrete storage
621
-     * backend (database).
622
-     *
623
-     * @param string|\TYPO3\CMS\Core\Database\PreparedStatement $statement The statement
624
-     * @param array $parameters An array of parameters. These will be bound to placeholders '?' in the $statement.
625
-     * @return QueryInterface
626
-     */
627
-    public function statement($statement, array $parameters = array())
628
-    {
629
-        $this->statement = $this->qomFactory->statement($statement, $parameters);
630
-        return $this;
631
-    }
632
-
633
-    /**
634
-     * Returns the statement of this query.
635
-     *
636
-     * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\Statement
637
-     */
638
-    public function getStatement()
639
-    {
640
-        return $this->statement;
641
-    }
642
-
643
-    /**
644
-     * Returns whether the current mode is Backend.
645
-     *
646
-     * @return bool
647
-     */
648
-    protected function isBackendMode()
649
-    {
650
-        return TYPO3_MODE == 'BE';
651
-    }
652
-
653
-    /**
654
-     * @return string
655
-     */
656
-    public function getSourceFieldName()
657
-    {
658
-        return $this->sourceFieldName;
659
-    }
660
-
661
-    /**
662
-     * @param string $sourceFieldName
663
-     * @return $this
664
-     */
665
-    public function setSourceFieldName($sourceFieldName)
666
-    {
667
-        $this->sourceFieldName = $sourceFieldName;
668
-        return $this;
669
-    }
26
+	/**
27
+	 * An inner join.
28
+	 */
29
+	const JCR_JOIN_TYPE_INNER = '{http://www.jcp.org/jcr/1.0}joinTypeInner';
30
+
31
+	/**
32
+	 * A left-outer join.
33
+	 */
34
+	const JCR_JOIN_TYPE_LEFT_OUTER = '{http://www.jcp.org/jcr/1.0}joinTypeLeftOuter';
35
+
36
+	/**
37
+	 * A right-outer join.
38
+	 */
39
+	const JCR_JOIN_TYPE_RIGHT_OUTER = '{http://www.jcp.org/jcr/1.0}joinTypeRightOuter';
40
+
41
+	/**
42
+	 * Charset of strings in QOM
43
+	 */
44
+	const CHARSET = 'utf-8';
45
+
46
+	/**
47
+	 * @var string
48
+	 */
49
+	protected $sourceFieldName;
50
+
51
+	/**
52
+	 * @var string
53
+	 */
54
+	protected $type;
55
+
56
+	/**
57
+	 * @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
58
+	 */
59
+	protected $objectManager;
60
+
61
+	/**
62
+	 * @var \TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface
63
+	 */
64
+	protected $persistenceManager;
65
+
66
+	/**
67
+	 * @var \TYPO3\CMS\Extbase\Persistence\Generic\Qom\QueryObjectModelFactory
68
+	 */
69
+	protected $qomFactory;
70
+
71
+	/**
72
+	 * @var \TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInterface
73
+	 */
74
+	protected $source;
75
+
76
+	/**
77
+	 * @var ConstraintInterface
78
+	 */
79
+	protected $constraint;
80
+
81
+	/**
82
+	 * @var \TYPO3\CMS\Extbase\Persistence\Generic\Qom\Statement
83
+	 */
84
+	protected $statement;
85
+
86
+	/**
87
+	 * @var int
88
+	 */
89
+	protected $orderings = [];
90
+
91
+	/**
92
+	 * @var int
93
+	 */
94
+	protected $limit;
95
+
96
+	/**
97
+	 * @var int
98
+	 */
99
+	protected $offset;
100
+
101
+	/**
102
+	 * Apply DISTINCT upon property.
103
+	 *
104
+	 * @var string
105
+	 */
106
+	protected $distinct;
107
+
108
+	/**
109
+	 * The query settings.
110
+	 *
111
+	 * @var \Fab\Vidi\Persistence\QuerySettings
112
+	 * @inject
113
+	 */
114
+	protected $querySettings;
115
+
116
+	/**
117
+	 * Constructs a query object working on the given class name
118
+	 *
119
+	 * @param string $type
120
+	 */
121
+	public function __construct($type)
122
+	{
123
+		$this->type = $type;
124
+	}
125
+
126
+	/**
127
+	 * @param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager
128
+	 * @return void
129
+	 */
130
+	public function injectObjectManager(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager)
131
+	{
132
+		$this->objectManager = $objectManager;
133
+	}
134
+
135
+	/**
136
+	 * Injects the persistence manager, used to fetch the CR session
137
+	 *
138
+	 * @param \TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface $persistenceManager
139
+	 * @return void
140
+	 */
141
+	public function injectPersistenceManager(\TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface $persistenceManager)
142
+	{
143
+		$this->persistenceManager = $persistenceManager;
144
+	}
145
+
146
+	/**
147
+	 * Injects the Query Object Model Factory
148
+	 *
149
+	 * @param \TYPO3\CMS\Extbase\Persistence\Generic\Qom\QueryObjectModelFactory $qomFactory
150
+	 * @return void
151
+	 */
152
+	public function injectQomFactory(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\QueryObjectModelFactory $qomFactory)
153
+	{
154
+		$this->qomFactory = $qomFactory;
155
+	}
156
+
157
+	/**
158
+	 * Sets the Query Settings. These Query settings must match the settings expected by
159
+	 * the specific Storage Backend.
160
+	 *
161
+	 * @param \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface $querySettings The Query Settings
162
+	 * @return void
163
+	 * @api This method is not part of FLOW3 API
164
+	 */
165
+	public function setQuerySettings(\TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface $querySettings)
166
+	{
167
+		$this->querySettings = $querySettings;
168
+	}
169
+
170
+	/**
171
+	 * Returns the Query Settings.
172
+	 *
173
+	 * @throws \Exception
174
+	 * @return \Fab\Vidi\Persistence\QuerySettings $querySettings The Query Settings
175
+	 * @api This method is not part of FLOW3 API
176
+	 */
177
+	public function getQuerySettings()
178
+	{
179
+		if (!$this->querySettings instanceof \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface) {
180
+			throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception('Tried to get the query settings without setting them before.', 1248689115);
181
+		}
182
+
183
+		// Apply possible settings to the query.
184
+		if ($this->isBackendMode()) {
185
+			/** @var \TYPO3\CMS\Extbase\Configuration\BackendConfigurationManager $backendConfigurationManager */
186
+			$backendConfigurationManager = $this->objectManager->get('TYPO3\CMS\Extbase\Configuration\BackendConfigurationManager');
187
+			$configuration = $backendConfigurationManager->getTypoScriptSetup();
188
+			$querySettings = array('respectSysLanguage');
189
+			foreach ($querySettings as $setting) {
190
+				if (isset($configuration['config.']['tx_vidi.']['persistence.']['backend.'][$this->type . '.'][$setting])) {
191
+					$value = (bool)$configuration['config.']['tx_vidi.']['persistence.']['backend.'][$this->type . '.'][$setting];
192
+					ObjectAccess::setProperty($this->querySettings, $setting, $value);
193
+				}
194
+			}
195
+		}
196
+
197
+		return $this->querySettings;
198
+	}
199
+
200
+	/**
201
+	 * Returns the type this query cares for.
202
+	 *
203
+	 * @return string
204
+	 * @api
205
+	 */
206
+	public function getType()
207
+	{
208
+		return $this->type;
209
+	}
210
+
211
+	/**
212
+	 * Sets the source to fetch the result from
213
+	 *
214
+	 * @param \TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInterface $source
215
+	 */
216
+	public function setSource(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInterface $source)
217
+	{
218
+		$this->source = $source;
219
+	}
220
+
221
+	/**
222
+	 * Returns the selectorn name or an empty string, if the source is not a selector
223
+	 * TODO This has to be checked at another place
224
+	 *
225
+	 * @return string The selector name
226
+	 */
227
+	protected function getSelectorName()
228
+	{
229
+		if ($this->getSource() instanceof \TYPO3\CMS\Extbase\Persistence\Generic\Qom\SelectorInterface) {
230
+			return $this->source->getSelectorName();
231
+		} else {
232
+			return '';
233
+		}
234
+	}
235
+
236
+	/**
237
+	 * Gets the node-tuple source for this query.
238
+	 *
239
+	 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInterface the node-tuple source; non-null
240
+	 */
241
+	public function getSource()
242
+	{
243
+		if ($this->source === null) {
244
+			$this->source = $this->qomFactory->selector($this->getType());
245
+		}
246
+		return $this->source;
247
+	}
248
+
249
+	/**
250
+	 * Executes the query against the database and returns the result
251
+	 *
252
+	 * @return \TYPO3\CMS\Extbase\Persistence\QueryResultInterface|array The query result object or an array if $this->getQuerySettings()->getReturnRawQueryResult() is true
253
+	 * @api
254
+	 */
255
+	public function execute($returnRawQueryResult = false)
256
+	{
257
+		/** @var \Fab\Vidi\Persistence\Storage\VidiDbBackend $backend */
258
+		$backend = $this->objectManager->get('Fab\Vidi\Persistence\Storage\VidiDbBackend', $this);
259
+		return $backend->fetchResult();
260
+	}
261
+
262
+	/**
263
+	 * Sets the property names to order the result by. Expected like this:
264
+	 * array(
265
+	 * 'foo' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_ASCENDING,
266
+	 * 'bar' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_DESCENDING
267
+	 * )
268
+	 * where 'foo' and 'bar' are property names.
269
+	 *
270
+	 * @param array $orderings The property names to order by
271
+	 * @return QueryInterface
272
+	 * @api
273
+	 */
274
+	public function setOrderings(array $orderings)
275
+	{
276
+		$this->orderings = $orderings;
277
+		return $this;
278
+	}
279
+
280
+	/**
281
+	 * Returns the property names to order the result by. Like this:
282
+	 * array(
283
+	 * 'foo' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_ASCENDING,
284
+	 * 'bar' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_DESCENDING
285
+	 * )
286
+	 *
287
+	 * @return array
288
+	 * @api
289
+	 */
290
+	public function getOrderings()
291
+	{
292
+		return $this->orderings;
293
+	}
294
+
295
+	/**
296
+	 * Sets the maximum size of the result set to limit. Returns $this to allow
297
+	 * for chaining (fluid interface)
298
+	 *
299
+	 * @param integer $limit
300
+	 * @throws \InvalidArgumentException
301
+	 * @return QueryInterface
302
+	 * @api
303
+	 */
304
+	public function setLimit($limit)
305
+	{
306
+		if (!is_int($limit) || $limit < 1) {
307
+			throw new \InvalidArgumentException('The limit must be an integer >= 1', 1245071870);
308
+		}
309
+		$this->limit = $limit;
310
+		return $this;
311
+	}
312
+
313
+	/**
314
+	 * Resets a previously set maximum size of the result set. Returns $this to allow
315
+	 * for chaining (fluid interface)
316
+	 *
317
+	 * @return QueryInterface
318
+	 * @api
319
+	 */
320
+	public function unsetLimit()
321
+	{
322
+		unset($this->limit);
323
+		return $this;
324
+	}
325
+
326
+	/**
327
+	 * Returns the maximum size of the result set to limit.
328
+	 *
329
+	 * @return integer
330
+	 * @api
331
+	 */
332
+	public function getLimit()
333
+	{
334
+		return $this->limit;
335
+	}
336
+
337
+	/**
338
+	 * Sets the start offset of the result set to offset. Returns $this to
339
+	 * allow for chaining (fluid interface)
340
+	 *
341
+	 * @param integer $offset
342
+	 * @throws \InvalidArgumentException
343
+	 * @return QueryInterface
344
+	 * @api
345
+	 */
346
+	public function setOffset($offset)
347
+	{
348
+		if (!is_int($offset) || $offset < 0) {
349
+			throw new \InvalidArgumentException('The offset must be a positive integer', 1245071872);
350
+		}
351
+		$this->offset = $offset;
352
+		return $this;
353
+	}
354
+
355
+	/**
356
+	 * Returns the start offset of the result set.
357
+	 *
358
+	 * @return integer
359
+	 * @api
360
+	 */
361
+	public function getOffset()
362
+	{
363
+		return $this->offset;
364
+	}
365
+
366
+	/**
367
+	 * The constraint used to limit the result set. Returns $this to allow
368
+	 * for chaining (fluid interface)
369
+	 *
370
+	 * @param ConstraintInterface $constraint
371
+	 * @return QueryInterface
372
+	 * @api
373
+	 */
374
+	public function matching($constraint)
375
+	{
376
+		$this->constraint = $constraint;
377
+		return $this;
378
+	}
379
+
380
+	/**
381
+	 * Gets the constraint for this query.
382
+	 *
383
+	 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\Constraint the constraint, or null if none
384
+	 * @api
385
+	 */
386
+	public function getConstraint()
387
+	{
388
+		return $this->constraint;
389
+	}
390
+
391
+	/**
392
+	 * Performs a logical conjunction of the given constraints. The method takes one or more contraints and concatenates them with a boolean AND.
393
+	 * It also scepts a single array of constraints to be concatenated.
394
+	 *
395
+	 * @param mixed $constraint1 The first of multiple constraints or an array of constraints.
396
+	 * @throws InvalidNumberOfConstraintsException
397
+	 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\AndInterface
398
+	 * @api
399
+	 */
400
+	public function logicalAnd($constraint1)
401
+	{
402
+		if (is_array($constraint1)) {
403
+			$resultingConstraint = array_shift($constraint1);
404
+			$constraints = $constraint1;
405
+		} else {
406
+			$constraints = func_get_args();
407
+			$resultingConstraint = array_shift($constraints);
408
+		}
409
+		if ($resultingConstraint === null) {
410
+			throw new InvalidNumberOfConstraintsException('There must be at least one constraint or a non-empty array of constraints given.', 1401289500);
411
+		}
412
+		foreach ($constraints as $constraint) {
413
+			$resultingConstraint = $this->qomFactory->_and($resultingConstraint, $constraint);
414
+		}
415
+		return $resultingConstraint;
416
+	}
417
+
418
+	/**
419
+	 * Performs a logical disjunction of the two given constraints
420
+	 *
421
+	 * @param mixed $constraint1 The first of multiple constraints or an array of constraints.
422
+	 * @throws InvalidNumberOfConstraintsException
423
+	 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\OrInterface
424
+	 * @api
425
+	 */
426
+	public function logicalOr($constraint1)
427
+	{
428
+		if (is_array($constraint1)) {
429
+			$resultingConstraint = array_shift($constraint1);
430
+			$constraints = $constraint1;
431
+		} else {
432
+			$constraints = func_get_args();
433
+			$resultingConstraint = array_shift($constraints);
434
+		}
435
+		if ($resultingConstraint === null) {
436
+			throw new InvalidNumberOfConstraintsException('There must be at least one constraint or a non-empty array of constraints given.', 1401289501);
437
+		}
438
+		foreach ($constraints as $constraint) {
439
+			$resultingConstraint = $this->qomFactory->_or($resultingConstraint, $constraint);
440
+		}
441
+		return $resultingConstraint;
442
+	}
443
+
444
+	/**
445
+	 * Performs a logical negation of the given constraint
446
+	 *
447
+	 * @param ConstraintInterface $constraint Constraint to negate
448
+	 * @throws \RuntimeException
449
+	 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\NotInterface
450
+	 * @api
451
+	 */
452
+	public function logicalNot(ConstraintInterface $constraint)
453
+	{
454
+		return $this->qomFactory->not($constraint);
455
+	}
456
+
457
+	/**
458
+	 * Returns an equals criterion used for matching objects against a query
459
+	 *
460
+	 * @param string $propertyName The name of the property to compare against
461
+	 * @param mixed $operand The value to compare with
462
+	 * @param boolean $caseSensitive Whether the equality test should be done case-sensitive
463
+	 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
464
+	 * @api
465
+	 */
466
+	public function equals($propertyName, $operand, $caseSensitive = true)
467
+	{
468
+		if (is_object($operand) || $caseSensitive) {
469
+			$comparison = $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_EQUAL_TO, $operand);
470
+		} else {
471
+			$comparison = $this->qomFactory->comparison($this->qomFactory->lowerCase($this->qomFactory->propertyValue($propertyName, $this->getSelectorName())), QueryInterface::OPERATOR_EQUAL_TO, \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Charset\\CharsetConverter')->conv_case(\TYPO3\CMS\Extbase\Persistence\Generic\Query::CHARSET, $operand, 'toLower'));
472
+		}
473
+		return $comparison;
474
+	}
475
+
476
+	/**
477
+	 * Returns a like criterion used for matching objects against a query
478
+	 *
479
+	 * @param string $propertyName The name of the property to compare against
480
+	 * @param mixed $operand The value to compare with
481
+	 * @param boolean $caseSensitive Whether the matching should be done case-sensitive
482
+	 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
483
+	 * @api
484
+	 */
485
+	public function like($propertyName, $operand, $caseSensitive = true)
486
+	{
487
+		return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_LIKE, $operand);
488
+	}
489
+
490
+	/**
491
+	 * Returns a "contains" criterion used for matching objects against a query.
492
+	 * It matches if the multivalued property contains the given operand.
493
+	 *
494
+	 * @param string $propertyName The name of the (multivalued) property to compare against
495
+	 * @param mixed $operand The value to compare with
496
+	 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
497
+	 * @api
498
+	 */
499
+	public function contains($propertyName, $operand)
500
+	{
501
+		return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_CONTAINS, $operand);
502
+	}
503
+
504
+	/**
505
+	 * Returns an "in" criterion used for matching objects against a query. It
506
+	 * matches if the property's value is contained in the multivalued operand.
507
+	 *
508
+	 * @param string $propertyName The name of the property to compare against
509
+	 * @param mixed $operand The value to compare with, multivalued
510
+	 * @throws UnexpectedTypeException
511
+	 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
512
+	 * @api
513
+	 */
514
+	public function in($propertyName, $operand)
515
+	{
516
+		if (!is_array($operand) && !$operand instanceof \ArrayAccess && !$operand instanceof \Traversable) {
517
+			throw new UnexpectedTypeException('The "in" operator must be given a mutlivalued operand (array, ArrayAccess, Traversable).', 1264678095);
518
+		}
519
+		return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_IN, $operand);
520
+	}
521
+
522
+	/**
523
+	 * Returns a less than criterion used for matching objects against a query
524
+	 *
525
+	 * @param string $propertyName The name of the property to compare against
526
+	 * @param mixed $operand The value to compare with
527
+	 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
528
+	 * @api
529
+	 */
530
+	public function lessThan($propertyName, $operand)
531
+	{
532
+		return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_LESS_THAN, $operand);
533
+	}
534
+
535
+	/**
536
+	 * Returns a less or equal than criterion used for matching objects against a query
537
+	 *
538
+	 * @param string $propertyName The name of the property to compare against
539
+	 * @param mixed $operand The value to compare with
540
+	 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
541
+	 * @api
542
+	 */
543
+	public function lessThanOrEqual($propertyName, $operand)
544
+	{
545
+		return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_LESS_THAN_OR_EQUAL_TO, $operand);
546
+	}
547
+
548
+	/**
549
+	 * Returns a greater than criterion used for matching objects against a query
550
+	 *
551
+	 * @param string $propertyName The name of the property to compare against
552
+	 * @param mixed $operand The value to compare with
553
+	 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
554
+	 * @api
555
+	 */
556
+	public function greaterThan($propertyName, $operand)
557
+	{
558
+		return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_GREATER_THAN, $operand);
559
+	}
560
+
561
+	/**
562
+	 * Returns a greater than or equal criterion used for matching objects against a query
563
+	 *
564
+	 * @param string $propertyName The name of the property to compare against
565
+	 * @param mixed $operand The value to compare with
566
+	 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
567
+	 * @api
568
+	 */
569
+	public function greaterThanOrEqual($propertyName, $operand)
570
+	{
571
+		return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_GREATER_THAN_OR_EQUAL_TO, $operand);
572
+	}
573
+
574
+	/**
575
+	 * Returns the query result count.
576
+	 *
577
+	 * @return integer The query result count
578
+	 * @api
579
+	 */
580
+	public function count()
581
+	{
582
+		/** @var \Fab\Vidi\Persistence\Storage\VidiDbBackend $backend */
583
+		$backend = $this->objectManager->get('Fab\Vidi\Persistence\Storage\VidiDbBackend', $this);
584
+		return $backend->countResult();
585
+	}
586
+
587
+	/**
588
+	 * Returns an "isEmpty" criterion used for matching objects against a query.
589
+	 * It matches if the multivalued property contains no values or is null.
590
+	 *
591
+	 * @param string $propertyName The name of the multivalued property to compare against
592
+	 * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\NotImplementedException
593
+	 * @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException if used on a single-valued property
594
+	 * @api
595
+	 */
596
+	public function isEmpty($propertyName)
597
+	{
598
+		throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\NotImplementedException(__METHOD__);
599
+	}
600
+
601
+	/**
602
+	 * @return string
603
+	 */
604
+	public function getDistinct()
605
+	{
606
+		return $this->distinct;
607
+	}
608
+
609
+	/**
610
+	 * @param string $distinct
611
+	 * @return $this
612
+	 */
613
+	public function setDistinct($distinct)
614
+	{
615
+		$this->distinct = $distinct;
616
+		return $this;
617
+	}
618
+
619
+	/**
620
+	 * Sets the statement of this query. If you use this, you will lose the abstraction from a concrete storage
621
+	 * backend (database).
622
+	 *
623
+	 * @param string|\TYPO3\CMS\Core\Database\PreparedStatement $statement The statement
624
+	 * @param array $parameters An array of parameters. These will be bound to placeholders '?' in the $statement.
625
+	 * @return QueryInterface
626
+	 */
627
+	public function statement($statement, array $parameters = array())
628
+	{
629
+		$this->statement = $this->qomFactory->statement($statement, $parameters);
630
+		return $this;
631
+	}
632
+
633
+	/**
634
+	 * Returns the statement of this query.
635
+	 *
636
+	 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\Statement
637
+	 */
638
+	public function getStatement()
639
+	{
640
+		return $this->statement;
641
+	}
642
+
643
+	/**
644
+	 * Returns whether the current mode is Backend.
645
+	 *
646
+	 * @return bool
647
+	 */
648
+	protected function isBackendMode()
649
+	{
650
+		return TYPO3_MODE == 'BE';
651
+	}
652
+
653
+	/**
654
+	 * @return string
655
+	 */
656
+	public function getSourceFieldName()
657
+	{
658
+		return $this->sourceFieldName;
659
+	}
660
+
661
+	/**
662
+	 * @param string $sourceFieldName
663
+	 * @return $this
664
+	 */
665
+	public function setSourceFieldName($sourceFieldName)
666
+	{
667
+		$this->sourceFieldName = $sourceFieldName;
668
+		return $this;
669
+	}
670 670
 
671 671
 }
Please login to merge, or discard this patch.
Classes/Persistence/Storage/VidiDbBackend.php 4 patches
Doc Comments   +3 added lines, -2 removed lines patch added patch discarded remove patch
@@ -231,7 +231,7 @@  discard block
 block discarded – undo
231 231
     /**
232 232
      * Parses the query and returns the SQL statement parts.
233 233
      *
234
-     * @param QueryInterface $query The query
234
+     * @param \Fab\Vidi\Persistence\Query $query The query
235 235
      * @param array &$parameters
236 236
      * @return array The SQL statement parts
237 237
      */
@@ -774,6 +774,7 @@  discard block
 block discarded – undo
774 774
      * @param string &$sqlString The query part with placeholders
775 775
      * @param array $parameters The parameters
776 776
      * @param string $tableName
777
+     * @param string $sqlString
777 778
      *
778 779
      * @throws Exception
779 780
      */
@@ -1071,7 +1072,7 @@  discard block
 block discarded – undo
1071 1072
      *
1072 1073
      * @param SourceInterface $source The source (selector od join)
1073 1074
      * @param array $row
1074
-     * @param QuerySettingsInterface $querySettings The TYPO3 CMS specific query settings
1075
+     * @param \Fab\Vidi\Persistence\QuerySettings $querySettings The TYPO3 CMS specific query settings
1075 1076
      * @return array
1076 1077
      */
1077 1078
     protected function doLanguageAndWorkspaceOverlay(SourceInterface $source, array $row, $querySettings)
Please login to merge, or discard this patch.
Unused Use Statements   -1 removed lines patch added patch discarded remove patch
@@ -18,7 +18,6 @@
 block discarded – undo
18 18
 use TYPO3\CMS\Core\Utility\GeneralUtility;
19 19
 use TYPO3\CMS\Core\Versioning\VersionState;
20 20
 use TYPO3\CMS\Extbase\Persistence\Generic\Exception;
21
-use TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap;
22 21
 use TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface;
23 22
 use TYPO3\CMS\Extbase\Persistence\Generic\Qom\DynamicOperandInterface;
24 23
 use TYPO3\CMS\Extbase\Persistence\Generic\Qom\JoinInterface;
Please login to merge, or discard this patch.
Spacing   +44 added lines, -44 removed lines patch added patch discarded remove patch
@@ -127,7 +127,7 @@  discard block
 block discarded – undo
127 127
         $fieldNames = array_keys($identifier);
128 128
         $suffixedFieldNames = [];
129 129
         foreach ($fieldNames as $fieldName) {
130
-            $suffixedFieldNames[] = $fieldName . '=?';
130
+            $suffixedFieldNames[] = $fieldName.'=?';
131 131
         }
132 132
         return implode(' AND ', $suffixedFieldNames);
133 133
     }
@@ -188,7 +188,7 @@  discard block
 block discarded – undo
188 188
             if (isset($statementParts['keywords']['distinct'])) {
189 189
                 unset($statementParts['keywords']['distinct']);
190 190
                 $distinctField = $this->query->getDistinct() ? $this->query->getDistinct() : 'uid';
191
-                $statementParts['fields'] = array('COUNT(DISTINCT ' . reset($statementParts['tables']) . '.' . $distinctField . ')');
191
+                $statementParts['fields'] = array('COUNT(DISTINCT '.reset($statementParts['tables']).'.'.$distinctField.')');
192 192
             }
193 193
 
194 194
             $statement = $this->buildQuery($statementParts);
@@ -258,14 +258,14 @@  discard block
 block discarded – undo
258 258
             // tx_domain_model_foo0 (the alias) <--> tx_domain_model_foo (the origin table name)
259 259
             $values = [];
260 260
             foreach ($statementParts['fields'] as $key => $value) {
261
-                $values[$key] = str_replace($tableName, $tableName . '0', $value);
261
+                $values[$key] = str_replace($tableName, $tableName.'0', $value);
262 262
             }
263 263
             $statementParts['fields'] = $values;
264 264
 
265 265
             // Same comment as above.
266 266
             $values = [];
267 267
             foreach ($statementParts['where'] as $key => $value) {
268
-                $values[$key] = str_replace($tableName . '0', $tableName, $value);
268
+                $values[$key] = str_replace($tableName.'0', $tableName, $value);
269 269
             }
270 270
             $statementParts['where'] = $values;
271 271
 
@@ -304,25 +304,25 @@  discard block
 block discarded – undo
304 304
         if (!empty($statementParts['unions'])) {
305 305
             foreach ($statementParts['unions'] as $tableName => $unionPart) {
306 306
                 if (!empty($statementParts['additionalWhereClause'][$tableName])) {
307
-                    $statementParts['unions'][$tableName] .= ' AND ' . implode(' AND ', $statementParts['additionalWhereClause'][$tableName]);
307
+                    $statementParts['unions'][$tableName] .= ' AND '.implode(' AND ', $statementParts['additionalWhereClause'][$tableName]);
308 308
                 }
309 309
             }
310 310
         }
311 311
 
312
-        $statement = 'SELECT ' . implode(' ', $statementParts['keywords']) . ' ' . implode(',', $statementParts['fields']) . ' FROM ' . implode(' ', $statementParts['tables']) . ' ' . implode(' ', $statementParts['unions']);
312
+        $statement = 'SELECT '.implode(' ', $statementParts['keywords']).' '.implode(',', $statementParts['fields']).' FROM '.implode(' ', $statementParts['tables']).' '.implode(' ', $statementParts['unions']);
313 313
         if (!empty($statementParts['where'])) {
314
-            $statement .= ' WHERE ' . implode('', $statementParts['where']);
314
+            $statement .= ' WHERE '.implode('', $statementParts['where']);
315 315
             if (!empty($statementParts['additionalWhereClause'][$this->query->getType()])) {
316
-                $statement .= ' AND ' . implode(' AND ', $statementParts['additionalWhereClause'][$this->query->getType()]);
316
+                $statement .= ' AND '.implode(' AND ', $statementParts['additionalWhereClause'][$this->query->getType()]);
317 317
             }
318 318
         } elseif (!empty($statementParts['additionalWhereClause'])) {
319
-            $statement .= ' WHERE ' . implode(' AND ', $statementParts['additionalWhereClause'][$this->query->getType()]);
319
+            $statement .= ' WHERE '.implode(' AND ', $statementParts['additionalWhereClause'][$this->query->getType()]);
320 320
         }
321 321
         if (!empty($statementParts['orderings'])) {
322
-            $statement .= ' ORDER BY ' . implode(', ', $statementParts['orderings']);
322
+            $statement .= ' ORDER BY '.implode(', ', $statementParts['orderings']);
323 323
         }
324 324
         if (!empty($statementParts['limit'])) {
325
-            $statement .= ' LIMIT ' . $statementParts['limit'];
325
+            $statement .= ' LIMIT '.$statementParts['limit'];
326 326
         }
327 327
 
328 328
         return $statement;
@@ -339,10 +339,10 @@  discard block
 block discarded – undo
339 339
     {
340 340
         if ($source instanceof SelectorInterface) {
341 341
             $tableName = $source->getNodeTypeName();
342
-            $sql['fields'][$tableName] = $tableName . '.*';
342
+            $sql['fields'][$tableName] = $tableName.'.*';
343 343
             $sql['tables'][$tableName] = $tableName;
344 344
             if ($this->query->getDistinct()) {
345
-                $sql['fields'][$tableName] = $tableName . '.' . $this->query->getDistinct();
345
+                $sql['fields'][$tableName] = $tableName.'.'.$this->query->getDistinct();
346 346
                 $sql['keywords']['distinct'] = 'DISTINCT';
347 347
             }
348 348
         } elseif ($source instanceof JoinInterface) {
@@ -367,15 +367,15 @@  discard block
 block discarded – undo
367 367
             $rightTableName = $rightSource->getLeft()->getSelectorName();
368 368
         } else {
369 369
             $rightTableName = $rightSource->getSelectorName();
370
-            $sql['fields'][$leftTableName] = $rightTableName . '.*';
370
+            $sql['fields'][$leftTableName] = $rightTableName.'.*';
371 371
         }
372 372
         $sql['tables'][$leftTableName] = $leftTableName;
373
-        $sql['unions'][$rightTableName] = 'LEFT JOIN ' . $rightTableName;
373
+        $sql['unions'][$rightTableName] = 'LEFT JOIN '.$rightTableName;
374 374
         $joinCondition = $join->getJoinCondition();
375 375
         if ($joinCondition instanceof \TYPO3\CMS\Extbase\Persistence\Generic\Qom\EquiJoinCondition) {
376 376
             $column1Name = $joinCondition->getProperty1Name();
377 377
             $column2Name = $joinCondition->getProperty2Name();
378
-            $sql['unions'][$rightTableName] .= ' ON ' . $joinCondition->getSelector1Name() . '.' . $column1Name . ' = ' . $joinCondition->getSelector2Name() . '.' . $column2Name;
378
+            $sql['unions'][$rightTableName] .= ' ON '.$joinCondition->getSelector1Name().'.'.$column1Name.' = '.$joinCondition->getSelector2Name().'.'.$column2Name;
379 379
         }
380 380
         if ($rightSource instanceof JoinInterface) {
381 381
             $this->parseJoin($rightSource, $sql);
@@ -513,7 +513,7 @@  discard block
 block discarded – undo
513 513
             if ($realInput instanceof \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface) {
514 514
                 return $realInput->getUid();
515 515
             } else {
516
-                throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\UnexpectedTypeException('An object of class "' . get_class($realInput) . '" could not be converted to a plain value.', 1274799934);
516
+                throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\UnexpectedTypeException('An object of class "'.get_class($realInput).'" could not be converted to a plain value.', 1274799934);
517 517
             }
518 518
         } elseif (is_bool($input)) {
519 519
             return $input === true ? 1 : 0;
@@ -558,9 +558,9 @@  discard block
 block discarded – undo
558 558
             $operator = $this->resolveOperator($operator);
559 559
             $constraintSQL = '';
560 560
             if ($valueFunction === null) {
561
-                $constraintSQL .= (!empty($tableName) ? $tableName . '.' : '') . $columnName . ' ' . $operator . ' ?';
561
+                $constraintSQL .= (!empty($tableName) ? $tableName.'.' : '').$columnName.' '.$operator.' ?';
562 562
             } else {
563
-                $constraintSQL .= $valueFunction . '(' . (!empty($tableName) ? $tableName . '.' : '') . $columnName . ') ' . $operator . ' ?';
563
+                $constraintSQL .= $valueFunction.'('.(!empty($tableName) ? $tableName.'.' : '').$columnName.') '.$operator.' ?';
564 564
             }
565 565
 
566 566
             if (isset($tableName) && !empty($this->currentChildTableNameAlias)) {
@@ -590,7 +590,7 @@  discard block
 block discarded – undo
590 590
         // to determine the relation type. Example for sys_category, property path will look like "items.sys_file"
591 591
         if ($table->field($fieldName)->isGroup()) {
592 592
             $parts = explode('.', $propertyPath, 3);
593
-            $explodedPropertyPath[0] = $parts[0] . '.' . $parts[1];
593
+            $explodedPropertyPath[0] = $parts[0].'.'.$parts[1];
594 594
             $explodedPropertyPath[1] = $parts[2];
595 595
             $fieldName = $explodedPropertyPath[0];
596 596
         }
@@ -599,16 +599,16 @@  discard block
 block discarded – undo
599 599
         $childTableName = $table->field($fieldName)->getForeignTable();
600 600
 
601 601
         if ($childTableName === null) {
602
-            throw new Exception\InvalidRelationConfigurationException('The relation information for property "' . $fieldName . '" of class "' . $tableName . '" is missing.', 1353170925);
602
+            throw new Exception\InvalidRelationConfigurationException('The relation information for property "'.$fieldName.'" of class "'.$tableName.'" is missing.', 1353170925);
603 603
         }
604 604
 
605 605
         if ($table->field($fieldName)->hasOne()) { // includes relation "one-to-one" and "many-to-one"
606 606
             // sometimes the opposite relation is not defined. We don't want to force this config for backward compatibility reasons.
607 607
             // $parentKeyFieldName === null does the trick somehow. Before condition was if (isset($parentKeyFieldName))
608 608
             if ($table->field($fieldName)->hasRelationManyToOne() || $parentKeyFieldName === null) {
609
-                $sql['unions'][$childTableName] = 'LEFT JOIN ' . $childTableName . ' ON ' . $tableName . '.' . $fieldName . '=' . $childTableName . '.uid';
609
+                $sql['unions'][$childTableName] = 'LEFT JOIN '.$childTableName.' ON '.$tableName.'.'.$fieldName.'='.$childTableName.'.uid';
610 610
             } else {
611
-                $sql['unions'][$childTableName] = 'LEFT JOIN ' . $childTableName . ' ON ' . $tableName . '.uid=' . $childTableName . '.' . $parentKeyFieldName;
611
+                $sql['unions'][$childTableName] = 'LEFT JOIN '.$childTableName.' ON '.$tableName.'.uid='.$childTableName.'.'.$parentKeyFieldName;
612 612
             }
613 613
         } elseif ($table->field($fieldName)->hasRelationManyToMany()) {
614 614
             $relationTableName = $table->field($fieldName)->getManyToManyTable();
@@ -773,11 +773,11 @@  discard block
 block discarded – undo
773 773
                     foreach ($parameter as $item) {
774 774
                         $items[] = $this->databaseHandle->fullQuoteStr($item, $tableName);
775 775
                     }
776
-                    $parameter = '(' . implode(',', $items) . ')';
776
+                    $parameter = '('.implode(',', $items).')';
777 777
                 } else {
778 778
                     $parameter = $this->databaseHandle->fullQuoteStr($parameter, $tableName);
779 779
                 }
780
-                $sqlString = substr($sqlString, 0, $markPosition) . $parameter . substr($sqlString, ($markPosition + 1));
780
+                $sqlString = substr($sqlString, 0, $markPosition).$parameter.substr($sqlString, ($markPosition + 1));
781 781
             }
782 782
             $offset = $markPosition + strlen($parameter);
783 783
         }
@@ -878,18 +878,18 @@  discard block
 block discarded – undo
878 878
         // If the table is found to have "workspace" support, add the corresponding fields in the statement.
879 879
         if (Tca::table($tableName)->hasWorkspaceSupport()) {
880 880
             if ($this->getBackendUser()->workspace === 0) {
881
-                $statement .= ' AND ' . $tableName . '.t3ver_state<=' . new VersionState(VersionState::DEFAULT_STATE);
881
+                $statement .= ' AND '.$tableName.'.t3ver_state<='.new VersionState(VersionState::DEFAULT_STATE);
882 882
             } else {
883 883
                 // Show only records of live and of the current workspace
884 884
                 // In case we are in a Versioning preview
885
-                $statement .= ' AND (' .
886
-                    $tableName . '.t3ver_wsid=0 OR ' .
887
-                    $tableName . '.t3ver_wsid=' . (int)$this->getBackendUser()->workspace .
885
+                $statement .= ' AND ('.
886
+                    $tableName.'.t3ver_wsid=0 OR '.
887
+                    $tableName.'.t3ver_wsid='.(int)$this->getBackendUser()->workspace.
888 888
                     ')';
889 889
             }
890 890
 
891 891
             // Check if this segment make sense here or whether it should be in the "if" part when we have workspace = 0
892
-            $statement .= ' AND ' . $tableName . '.pid<>-1';
892
+            $statement .= ' AND '.$tableName.'.pid<>-1';
893 893
         }
894 894
 
895 895
         if (!$includeDeleted) {
@@ -915,25 +915,25 @@  discard block
 block discarded – undo
915 915
         if (is_array($GLOBALS['TCA'][$tableName]['ctrl'])) {
916 916
             if (!empty($GLOBALS['TCA'][$tableName]['ctrl']['languageField'])) {
917 917
                 // Select all entries for the current language
918
-                $additionalWhereClause = $tableNameOrAlias . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] . ' IN (' . intval($querySettings->getLanguageUid()) . ',-1)';
918
+                $additionalWhereClause = $tableNameOrAlias.'.'.$GLOBALS['TCA'][$tableName]['ctrl']['languageField'].' IN ('.intval($querySettings->getLanguageUid()).',-1)';
919 919
                 // If any language is set -> get those entries which are not translated yet
920 920
                 // They will be removed by t3lib_page::getRecordOverlay if not matching overlay mode
921 921
                 if (isset($GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'])
922 922
                     && $querySettings->getLanguageUid() > 0
923 923
                 ) {
924
-                    $additionalWhereClause .= ' OR (' . $tableNameOrAlias . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] . '=0' .
925
-                        ' AND ' . $tableNameOrAlias . '.uid NOT IN (SELECT ' . $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'] .
926
-                        ' FROM ' . $tableName .
927
-                        ' WHERE ' . $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'] . '>0' .
928
-                        ' AND ' . $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] . '>0';
924
+                    $additionalWhereClause .= ' OR ('.$tableNameOrAlias.'.'.$GLOBALS['TCA'][$tableName]['ctrl']['languageField'].'=0'.
925
+                        ' AND '.$tableNameOrAlias.'.uid NOT IN (SELECT '.$tableName.'.'.$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'].
926
+                        ' FROM '.$tableName.
927
+                        ' WHERE '.$tableName.'.'.$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'].'>0'.
928
+                        ' AND '.$tableName.'.'.$GLOBALS['TCA'][$tableName]['ctrl']['languageField'].'>0';
929 929
 
930 930
                     // Add delete clause to ensure all entries are loaded
931 931
                     if (isset($GLOBALS['TCA'][$tableName]['ctrl']['delete'])) {
932
-                        $additionalWhereClause .= ' AND ' . $tableNameOrAlias . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['delete'] . '=0';
932
+                        $additionalWhereClause .= ' AND '.$tableNameOrAlias.'.'.$GLOBALS['TCA'][$tableName]['ctrl']['delete'].'=0';
933 933
                     }
934 934
                     $additionalWhereClause .= '))';
935 935
                 }
936
-                $statementParts['additionalWhereClause'][$tableNameOrAlias][] = '(' . $additionalWhereClause . ')';
936
+                $statementParts['additionalWhereClause'][$tableNameOrAlias][] = '('.$additionalWhereClause.')';
937 937
             }
938 938
         }
939 939
     }
@@ -978,7 +978,7 @@  discard block
 block discarded – undo
978 978
     protected function parseLimitAndOffset($limit, $offset, array &$sql)
979 979
     {
980 980
         if ($limit !== null && $offset !== null) {
981
-            $sql['limit'] = intval($offset) . ', ' . intval($limit);
981
+            $sql['limit'] = intval($offset).', '.intval($limit);
982 982
         } elseif ($limit !== null) {
983 983
             $sql['limit'] = intval($limit);
984 984
         }
@@ -1045,10 +1045,10 @@  discard block
 block discarded – undo
1045 1045
                 && $row[$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']] > 0
1046 1046
             ) {
1047 1047
                 $row = $this->databaseHandle->exec_SELECTgetSingleRow(
1048
-                    $tableName . '.*',
1048
+                    $tableName.'.*',
1049 1049
                     $tableName,
1050
-                    $tableName . '.uid=' . (int)$row[$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']] .
1051
-                    ' AND ' . $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] . '=0'
1050
+                    $tableName.'.uid='.(int)$row[$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']].
1051
+                    ' AND '.$tableName.'.'.$GLOBALS['TCA'][$tableName]['ctrl']['languageField'].'=0'
1052 1052
                 );
1053 1053
             }
1054 1054
         }
@@ -1103,7 +1103,7 @@  discard block
 block discarded – undo
1103 1103
         }
1104 1104
 
1105 1105
         $numberOfAliases = $this->tableNameAliases['aliasIncrement'][$tableName];
1106
-        $tableNameAlias = $tableName . $numberOfAliases;
1106
+        $tableNameAlias = $tableName.$numberOfAliases;
1107 1107
 
1108 1108
         $this->tableNameAliases['aliasIncrement'][$tableName]++;
1109 1109
         $this->tableNameAliases['aliases'][$tableNameAlias] = $tableName;
@@ -1182,7 +1182,7 @@  discard block
 block discarded – undo
1182 1182
     {
1183 1183
         $error = $this->databaseHandle->sql_error();
1184 1184
         if ($error !== '') {
1185
-            $error .= $sql ? ': ' . $sql : '';
1185
+            $error .= $sql ? ': '.$sql : '';
1186 1186
             throw new \TYPO3\CMS\Extbase\Persistence\Generic\Storage\Exception\SqlErrorException($error, 1247602160);
1187 1187
         }
1188 1188
     }
Please login to merge, or discard this patch.
Indentation   +1158 added lines, -1158 removed lines patch added patch discarded remove patch
@@ -32,1162 +32,1162 @@
 block discarded – undo
32 32
 class VidiDbBackend
33 33
 {
34 34
 
35
-    const OPERATOR_EQUAL_TO_NULL = 'operatorEqualToNull';
36
-    const OPERATOR_NOT_EQUAL_TO_NULL = 'operatorNotEqualToNull';
37
-
38
-    /**
39
-     * The TYPO3 database object
40
-     *
41
-     * @var \TYPO3\CMS\Core\Database\DatabaseConnection
42
-     */
43
-    protected $databaseHandle;
44
-
45
-    /**
46
-     * The TYPO3 page repository. Used for language and workspace overlay
47
-     *
48
-     * @var PageRepository
49
-     */
50
-    protected $pageRepository;
51
-
52
-    /**
53
-     * A first-level TypoScript configuration cache
54
-     *
55
-     * @var array
56
-     */
57
-    protected $pageTSConfigCache = [];
58
-
59
-    /**
60
-     * @var \TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface
61
-     * @inject
62
-     */
63
-    protected $configurationManager;
64
-
65
-    /**
66
-     * @var \TYPO3\CMS\Extbase\Service\CacheService
67
-     * @inject
68
-     */
69
-    protected $cacheService;
70
-
71
-    /**
72
-     * @var \TYPO3\CMS\Core\Cache\CacheManager
73
-     * @inject
74
-     */
75
-    protected $cacheManager;
76
-
77
-    /**
78
-     * @var \TYPO3\CMS\Extbase\Service\EnvironmentService
79
-     * @inject
80
-     */
81
-    protected $environmentService;
82
-
83
-    /**
84
-     * @var \Fab\Vidi\Persistence\Query
85
-     */
86
-    protected $query;
87
-
88
-    /**
89
-     * Store some info related to table name and its aliases.
90
-     *
91
-     * @var array
92
-     */
93
-    protected $tableNameAliases = array(
94
-        'aliases' => [],
95
-        'aliasIncrement' => [],
96
-    );
97
-
98
-    /**
99
-     * Use to store the current foreign table name alias.
100
-     *
101
-     * @var string
102
-     */
103
-    protected $currentChildTableNameAlias = '';
104
-
105
-    /**
106
-     * The default object type being returned.
107
-     *
108
-     * @var string
109
-     */
110
-    protected $objectType = 'Fab\Vidi\Domain\Model\Content';
111
-
112
-    /**
113
-     * Constructor. takes the database handle from $GLOBALS['TYPO3_DB']
114
-     */
115
-    public function __construct(QueryInterface $query)
116
-    {
117
-        $this->query = $query;
118
-        $this->databaseHandle = $GLOBALS['TYPO3_DB'];
119
-    }
120
-
121
-    /**
122
-     * @param array $identifier
123
-     * @return string
124
-     */
125
-    protected function parseIdentifier(array $identifier)
126
-    {
127
-        $fieldNames = array_keys($identifier);
128
-        $suffixedFieldNames = [];
129
-        foreach ($fieldNames as $fieldName) {
130
-            $suffixedFieldNames[] = $fieldName . '=?';
131
-        }
132
-        return implode(' AND ', $suffixedFieldNames);
133
-    }
134
-
135
-    /**
136
-     * Returns the result of the query
137
-     */
138
-    public function fetchResult()
139
-    {
140
-
141
-        $parameters = [];
142
-        $statementParts = $this->parseQuery($this->query, $parameters);
143
-        $statementParts = $this->processStatementStructureForRecursiveMMRelation($statementParts); // Mmm... check if that is the right way of doing that.
144
-
145
-        $sql = $this->buildQuery($statementParts);
146
-        $tableName = '';
147
-        if (is_array($statementParts) && !empty(reset($statementParts['tables']))) {
148
-            $tableName = reset($statementParts['tables']);
149
-        }
150
-        $this->replacePlaceholders($sql, $parameters, $tableName);
151
-        #print $sql; exit(); // @debug
152
-
153
-        $result = $this->databaseHandle->sql_query($sql);
154
-        $this->checkSqlErrors($sql);
155
-        $rows = $this->getRowsFromResult($result);
156
-        $this->databaseHandle->sql_free_result($result);
157
-
158
-        return $rows;
159
-    }
160
-
161
-    /**
162
-     * Returns the number of tuples matching the query.
163
-     *
164
-     * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Storage\Exception\BadConstraintException
165
-     * @return int The number of matching tuples
166
-     */
167
-    public function countResult()
168
-    {
169
-
170
-        $parameters = [];
171
-        $statementParts = $this->parseQuery($this->query, $parameters);
172
-        $statementParts = $this->processStatementStructureForRecursiveMMRelation($statementParts); // Mmm... check if that is the right way of doing that.
173
-        // Reset $statementParts for valid table return
174
-        reset($statementParts);
175
-
176
-        // if limit is set, we need to count the rows "manually" as COUNT(*) ignores LIMIT constraints
177
-        if (!empty($statementParts['limit'])) {
178
-            $statement = $this->buildQuery($statementParts);
179
-            $this->replacePlaceholders($statement, $parameters, current($statementParts['tables']));
180
-            #print $statement; exit(); // @debug
181
-            $result = $this->databaseHandle->sql_query($statement);
182
-            $this->checkSqlErrors($statement);
183
-            $count = $this->databaseHandle->sql_num_rows($result);
184
-        } else {
185
-            $statementParts['fields'] = array('COUNT(*)');
186
-            // having orderings without grouping is not compatible with non-MySQL DBMS
187
-            $statementParts['orderings'] = [];
188
-            if (isset($statementParts['keywords']['distinct'])) {
189
-                unset($statementParts['keywords']['distinct']);
190
-                $distinctField = $this->query->getDistinct() ? $this->query->getDistinct() : 'uid';
191
-                $statementParts['fields'] = array('COUNT(DISTINCT ' . reset($statementParts['tables']) . '.' . $distinctField . ')');
192
-            }
193
-
194
-            $statement = $this->buildQuery($statementParts);
195
-            $this->replacePlaceholders($statement, $parameters, current($statementParts['tables']));
196
-
197
-            #print $statement; exit(); // @debug
198
-            $result = $this->databaseHandle->sql_query($statement);
199
-            $this->checkSqlErrors($statement);
200
-            $count = 0;
201
-            if ($result) {
202
-                $row = $this->databaseHandle->sql_fetch_assoc($result);
203
-                $count = current($row);
204
-            }
205
-        }
206
-        $this->databaseHandle->sql_free_result($result);
207
-        return (int)$count;
208
-    }
209
-
210
-    /**
211
-     * Parses the query and returns the SQL statement parts.
212
-     *
213
-     * @param QueryInterface $query The query
214
-     * @param array &$parameters
215
-     * @return array The SQL statement parts
216
-     */
217
-    public function parseQuery(QueryInterface $query, array &$parameters)
218
-    {
219
-        $statementParts = [];
220
-        $statementParts['keywords'] = [];
221
-        $statementParts['tables'] = [];
222
-        $statementParts['unions'] = [];
223
-        $statementParts['fields'] = [];
224
-        $statementParts['where'] = [];
225
-        $statementParts['additionalWhereClause'] = [];
226
-        $statementParts['orderings'] = [];
227
-        $statementParts['limit'] = [];
228
-        $source = $query->getSource();
229
-        $this->parseSource($source, $statementParts);
230
-        $this->parseConstraint($query->getConstraint(), $source, $statementParts, $parameters);
231
-        $this->parseOrderings($query->getOrderings(), $source, $statementParts);
232
-        $this->parseLimitAndOffset($query->getLimit(), $query->getOffset(), $statementParts);
233
-        $tableNames = array_unique(array_keys($statementParts['tables'] + $statementParts['unions']));
234
-        foreach ($tableNames as $tableNameOrAlias) {
235
-            if (is_string($tableNameOrAlias) && strlen($tableNameOrAlias) > 0) {
236
-                $this->addAdditionalWhereClause($query->getQuerySettings(), $tableNameOrAlias, $statementParts);
237
-            }
238
-        }
239
-
240
-        return $statementParts;
241
-    }
242
-
243
-    /**
244
-     * Fiddle with the statement structure to handle recursive MM relations.
245
-     * For the recursive MM query to work, we must invert some values.
246
-     * Let see if that is the best way of doing that...
247
-     *
248
-     * @param array $statementParts
249
-     * @return array
250
-     */
251
-    public function processStatementStructureForRecursiveMMRelation(array $statementParts)
252
-    {
253
-
254
-        if ($this->hasRecursiveMMRelation()) {
255
-            $tableName = $this->query->getType();
256
-
257
-            // In order the MM query to work for a recursive MM query, we must invert some values.
258
-            // tx_domain_model_foo0 (the alias) <--> tx_domain_model_foo (the origin table name)
259
-            $values = [];
260
-            foreach ($statementParts['fields'] as $key => $value) {
261
-                $values[$key] = str_replace($tableName, $tableName . '0', $value);
262
-            }
263
-            $statementParts['fields'] = $values;
264
-
265
-            // Same comment as above.
266
-            $values = [];
267
-            foreach ($statementParts['where'] as $key => $value) {
268
-                $values[$key] = str_replace($tableName . '0', $tableName, $value);
269
-            }
270
-            $statementParts['where'] = $values;
271
-
272
-            // We must be more restrictive by transforming the "left" union by "inner"
273
-            $values = [];
274
-            foreach ($statementParts['unions'] as $key => $value) {
275
-                $values[$key] = str_replace('LEFT JOIN', 'INNER JOIN', $value);
276
-            }
277
-            $statementParts['unions'] = $values;
278
-        }
279
-
280
-        return $statementParts;
281
-    }
282
-
283
-    /**
284
-     * Tell whether there is a recursive MM relation.
285
-     *
286
-     * @return bool
287
-     */
288
-    public function hasRecursiveMMRelation()
289
-    {
290
-        return isset($this->tableNameAliases['aliasIncrement'][$this->query->getType()]);
291
-
292
-    }
293
-
294
-    /**
295
-     * Returns the statement, ready to be executed.
296
-     *
297
-     * @param array $statementParts The SQL statement parts
298
-     * @return string The SQL statement
299
-     */
300
-    public function buildQuery(array $statementParts)
301
-    {
302
-
303
-        // Add more statement to the UNION part.
304
-        if (!empty($statementParts['unions'])) {
305
-            foreach ($statementParts['unions'] as $tableName => $unionPart) {
306
-                if (!empty($statementParts['additionalWhereClause'][$tableName])) {
307
-                    $statementParts['unions'][$tableName] .= ' AND ' . implode(' AND ', $statementParts['additionalWhereClause'][$tableName]);
308
-                }
309
-            }
310
-        }
311
-
312
-        $statement = 'SELECT ' . implode(' ', $statementParts['keywords']) . ' ' . implode(',', $statementParts['fields']) . ' FROM ' . implode(' ', $statementParts['tables']) . ' ' . implode(' ', $statementParts['unions']);
313
-        if (!empty($statementParts['where'])) {
314
-            $statement .= ' WHERE ' . implode('', $statementParts['where']);
315
-            if (!empty($statementParts['additionalWhereClause'][$this->query->getType()])) {
316
-                $statement .= ' AND ' . implode(' AND ', $statementParts['additionalWhereClause'][$this->query->getType()]);
317
-            }
318
-        } elseif (!empty($statementParts['additionalWhereClause'])) {
319
-            $statement .= ' WHERE ' . implode(' AND ', $statementParts['additionalWhereClause'][$this->query->getType()]);
320
-        }
321
-        if (!empty($statementParts['orderings'])) {
322
-            $statement .= ' ORDER BY ' . implode(', ', $statementParts['orderings']);
323
-        }
324
-        if (!empty($statementParts['limit'])) {
325
-            $statement .= ' LIMIT ' . $statementParts['limit'];
326
-        }
327
-
328
-        return $statement;
329
-    }
330
-
331
-    /**
332
-     * Transforms a Query Source into SQL and parameter arrays
333
-     *
334
-     * @param SourceInterface $source The source
335
-     * @param array &$sql
336
-     * @return void
337
-     */
338
-    protected function parseSource(SourceInterface $source, array &$sql)
339
-    {
340
-        if ($source instanceof SelectorInterface) {
341
-            $tableName = $source->getNodeTypeName();
342
-            $sql['fields'][$tableName] = $tableName . '.*';
343
-            $sql['tables'][$tableName] = $tableName;
344
-            if ($this->query->getDistinct()) {
345
-                $sql['fields'][$tableName] = $tableName . '.' . $this->query->getDistinct();
346
-                $sql['keywords']['distinct'] = 'DISTINCT';
347
-            }
348
-        } elseif ($source instanceof JoinInterface) {
349
-            $this->parseJoin($source, $sql);
350
-        }
351
-    }
352
-
353
-    /**
354
-     * Transforms a Join into SQL and parameter arrays
355
-     *
356
-     * @param JoinInterface $join The join
357
-     * @param array &$sql The query parts
358
-     * @return void
359
-     */
360
-    protected function parseJoin(JoinInterface $join, array &$sql)
361
-    {
362
-        $leftSource = $join->getLeft();
363
-        $leftTableName = $leftSource->getSelectorName();
364
-        // $sql['fields'][$leftTableName] = $leftTableName . '.*';
365
-        $rightSource = $join->getRight();
366
-        if ($rightSource instanceof JoinInterface) {
367
-            $rightTableName = $rightSource->getLeft()->getSelectorName();
368
-        } else {
369
-            $rightTableName = $rightSource->getSelectorName();
370
-            $sql['fields'][$leftTableName] = $rightTableName . '.*';
371
-        }
372
-        $sql['tables'][$leftTableName] = $leftTableName;
373
-        $sql['unions'][$rightTableName] = 'LEFT JOIN ' . $rightTableName;
374
-        $joinCondition = $join->getJoinCondition();
375
-        if ($joinCondition instanceof \TYPO3\CMS\Extbase\Persistence\Generic\Qom\EquiJoinCondition) {
376
-            $column1Name = $joinCondition->getProperty1Name();
377
-            $column2Name = $joinCondition->getProperty2Name();
378
-            $sql['unions'][$rightTableName] .= ' ON ' . $joinCondition->getSelector1Name() . '.' . $column1Name . ' = ' . $joinCondition->getSelector2Name() . '.' . $column2Name;
379
-        }
380
-        if ($rightSource instanceof JoinInterface) {
381
-            $this->parseJoin($rightSource, $sql);
382
-        }
383
-    }
384
-
385
-    /**
386
-     * Transforms a constraint into SQL and parameter arrays
387
-     *
388
-     * @param \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ConstraintInterface $constraint The constraint
389
-     * @param SourceInterface $source The source
390
-     * @param array &$sql The query parts
391
-     * @param array &$parameters The parameters that will replace the markers
392
-     * @return void
393
-     */
394
-    protected function parseConstraint(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\ConstraintInterface $constraint = null, SourceInterface $source, array &$sql, array &$parameters)
395
-    {
396
-        if ($constraint instanceof \TYPO3\CMS\Extbase\Persistence\Generic\Qom\AndInterface) {
397
-            $sql['where'][] = '(';
398
-            $this->parseConstraint($constraint->getConstraint1(), $source, $sql, $parameters);
399
-            $sql['where'][] = ' AND ';
400
-            $this->parseConstraint($constraint->getConstraint2(), $source, $sql, $parameters);
401
-            $sql['where'][] = ')';
402
-        } elseif ($constraint instanceof \TYPO3\CMS\Extbase\Persistence\Generic\Qom\OrInterface) {
403
-            $sql['where'][] = '(';
404
-            $this->parseConstraint($constraint->getConstraint1(), $source, $sql, $parameters);
405
-            $sql['where'][] = ' OR ';
406
-            $this->parseConstraint($constraint->getConstraint2(), $source, $sql, $parameters);
407
-            $sql['where'][] = ')';
408
-        } elseif ($constraint instanceof \TYPO3\CMS\Extbase\Persistence\Generic\Qom\NotInterface) {
409
-            $sql['where'][] = 'NOT (';
410
-            $this->parseConstraint($constraint->getConstraint(), $source, $sql, $parameters);
411
-            $sql['where'][] = ')';
412
-        } elseif ($constraint instanceof ComparisonInterface) {
413
-            $this->parseComparison($constraint, $source, $sql, $parameters);
414
-        }
415
-    }
416
-
417
-    /**
418
-     * Parse a Comparison into SQL and parameter arrays.
419
-     *
420
-     * @param ComparisonInterface $comparison The comparison to parse
421
-     * @param SourceInterface $source The source
422
-     * @param array &$sql SQL query parts to add to
423
-     * @param array &$parameters Parameters to bind to the SQL
424
-     * @throws Exception\RepositoryException
425
-     * @return void
426
-     */
427
-    protected function parseComparison(ComparisonInterface $comparison, SourceInterface $source, array &$sql, array &$parameters)
428
-    {
429
-        $operand1 = $comparison->getOperand1();
430
-        $operator = $comparison->getOperator();
431
-        $operand2 = $comparison->getOperand2();
432
-        if ($operator === QueryInterface::OPERATOR_IN) {
433
-            $items = [];
434
-            $hasValue = false;
435
-            foreach ($operand2 as $value) {
436
-                $value = $this->getPlainValue($value);
437
-                if ($value !== null) {
438
-                    $items[] = $value;
439
-                    $hasValue = true;
440
-                }
441
-            }
442
-            if ($hasValue === false) {
443
-                $sql['where'][] = '1<>1';
444
-            } else {
445
-                $this->parseDynamicOperand($operand1, $operator, $source, $sql, $parameters, null);
446
-                $parameters[] = $items;
447
-            }
448
-        } elseif ($operator === QueryInterface::OPERATOR_CONTAINS) {
449
-            if ($operand2 === null) {
450
-                $sql['where'][] = '1<>1';
451
-            } else {
452
-                throw new \Exception('Not implemented! Contact extension author.', 1412931227);
453
-                # @todo re-implement me if necessary.
454
-                #$tableName = $this->query->getType();
455
-                #$propertyName = $operand1->getPropertyName();
456
-                #while (strpos($propertyName, '.') !== false) {
457
-                #	$this->addUnionStatement($tableName, $propertyName, $sql);
458
-                #}
459
-                #$columnName = $propertyName;
460
-                #$columnMap = $propertyName;
461
-                #$typeOfRelation = $columnMap instanceof ColumnMap ? $columnMap->getTypeOfRelation() : null;
462
-                #if ($typeOfRelation === ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY) {
463
-                #	$relationTableName = $columnMap->getRelationTableName();
464
-                #	$sql['where'][] = $tableName . '.uid IN (SELECT ' . $columnMap->getParentKeyFieldName() . ' FROM ' . $relationTableName . ' WHERE ' . $columnMap->getChildKeyFieldName() . '=?)';
465
-                #	$parameters[] = intval($this->getPlainValue($operand2));
466
-                #} elseif ($typeOfRelation === ColumnMap::RELATION_HAS_MANY) {
467
-                #	$parentKeyFieldName = $columnMap->getParentKeyFieldName();
468
-                #	if (isset($parentKeyFieldName)) {
469
-                #		$childTableName = $columnMap->getChildTableName();
470
-                #		$sql['where'][] = $tableName . '.uid=(SELECT ' . $childTableName . '.' . $parentKeyFieldName . ' FROM ' . $childTableName . ' WHERE ' . $childTableName . '.uid=?)';
471
-                #		$parameters[] = intval($this->getPlainValue($operand2));
472
-                #	} else {
473
-                #		$sql['where'][] = 'FIND_IN_SET(?,' . $tableName . '.' . $columnName . ')';
474
-                #		$parameters[] = intval($this->getPlainValue($operand2));
475
-                #	}
476
-                #} else {
477
-                #	throw new Exception\RepositoryException('Unsupported or non-existing property name "' . $propertyName . '" used in relation matching.', 1327065745);
478
-                #}
479
-            }
480
-        } else {
481
-            if ($operand2 === null) {
482
-                if ($operator === QueryInterface::OPERATOR_EQUAL_TO) {
483
-                    $operator = self::OPERATOR_EQUAL_TO_NULL;
484
-                } elseif ($operator === QueryInterface::OPERATOR_NOT_EQUAL_TO) {
485
-                    $operator = self::OPERATOR_NOT_EQUAL_TO_NULL;
486
-                }
487
-            }
488
-            $this->parseDynamicOperand($operand1, $operator, $source, $sql, $parameters);
489
-            $parameters[] = $this->getPlainValue($operand2);
490
-        }
491
-    }
492
-
493
-    /**
494
-     * Returns a plain value, i.e. objects are flattened out if possible.
495
-     *
496
-     * @param mixed $input
497
-     * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\UnexpectedTypeException
498
-     * @return mixed
499
-     */
500
-    protected function getPlainValue($input)
501
-    {
502
-        if (is_array($input)) {
503
-            throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\UnexpectedTypeException('An array could not be converted to a plain value.', 1274799932);
504
-        }
505
-        if ($input instanceof \DateTime) {
506
-            return $input->format('U');
507
-        } elseif (is_object($input)) {
508
-            if ($input instanceof \TYPO3\CMS\Extbase\Persistence\Generic\LazyLoadingProxy) {
509
-                $realInput = $input->_loadRealInstance();
510
-            } else {
511
-                $realInput = $input;
512
-            }
513
-            if ($realInput instanceof \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface) {
514
-                return $realInput->getUid();
515
-            } else {
516
-                throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\UnexpectedTypeException('An object of class "' . get_class($realInput) . '" could not be converted to a plain value.', 1274799934);
517
-            }
518
-        } elseif (is_bool($input)) {
519
-            return $input === true ? 1 : 0;
520
-        } else {
521
-            return $input;
522
-        }
523
-    }
524
-
525
-    /**
526
-     * Parse a DynamicOperand into SQL and parameter arrays.
527
-     *
528
-     * @param DynamicOperandInterface $operand
529
-     * @param string $operator One of the JCR_OPERATOR_* constants
530
-     * @param SourceInterface $source The source
531
-     * @param array &$sql The query parts
532
-     * @param array &$parameters The parameters that will replace the markers
533
-     * @param string $valueFunction an optional SQL function to apply to the operand value
534
-     * @return void
535
-     */
536
-    protected function parseDynamicOperand(DynamicOperandInterface $operand, $operator, SourceInterface $source, array &$sql, array &$parameters, $valueFunction = null)
537
-    {
538
-        if ($operand instanceof LowerCaseInterface) {
539
-            $this->parseDynamicOperand($operand->getOperand(), $operator, $source, $sql, $parameters, 'LOWER');
540
-        } elseif ($operand instanceof UpperCaseInterface) {
541
-            $this->parseDynamicOperand($operand->getOperand(), $operator, $source, $sql, $parameters, 'UPPER');
542
-        } elseif ($operand instanceof PropertyValueInterface) {
543
-            $propertyName = $operand->getPropertyName();
544
-
545
-            // Reset value.
546
-            $this->currentChildTableNameAlias = '';
547
-
548
-            if ($source instanceof SelectorInterface) {
549
-                $tableName = $this->query->getType();
550
-                while (strpos($propertyName, '.') !== false) {
551
-                    $this->addUnionStatement($tableName, $propertyName, $sql);
552
-                }
553
-            } elseif ($source instanceof JoinInterface) {
554
-                $tableName = $source->getJoinCondition()->getSelector1Name();
555
-            }
556
-
557
-            $columnName = $propertyName;
558
-            $operator = $this->resolveOperator($operator);
559
-            $constraintSQL = '';
560
-            if ($valueFunction === null) {
561
-                $constraintSQL .= (!empty($tableName) ? $tableName . '.' : '') . $columnName . ' ' . $operator . ' ?';
562
-            } else {
563
-                $constraintSQL .= $valueFunction . '(' . (!empty($tableName) ? $tableName . '.' : '') . $columnName . ') ' . $operator . ' ?';
564
-            }
565
-
566
-            if (isset($tableName) && !empty($this->currentChildTableNameAlias)) {
567
-                $constraintSQL = $this->replaceTableNameByAlias($tableName, $this->currentChildTableNameAlias, $constraintSQL);
568
-            }
569
-            $sql['where'][] = $constraintSQL;
570
-        }
571
-    }
572
-
573
-    /**
574
-     * @param string &$tableName
575
-     * @param array &$propertyPath
576
-     * @param array &$sql
577
-     * @throws Exception
578
-     * @throws Exception\InvalidRelationConfigurationException
579
-     * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\MissingColumnMapException
580
-     */
581
-    protected function addUnionStatement(&$tableName, &$propertyPath, array &$sql)
582
-    {
583
-
584
-        $table = Tca::table($tableName);
585
-
586
-        $explodedPropertyPath = explode('.', $propertyPath, 2);
587
-        $fieldName = $explodedPropertyPath[0];
588
-
589
-        // Field of type "group" are special because property path must contain the table name
590
-        // to determine the relation type. Example for sys_category, property path will look like "items.sys_file"
591
-        if ($table->field($fieldName)->isGroup()) {
592
-            $parts = explode('.', $propertyPath, 3);
593
-            $explodedPropertyPath[0] = $parts[0] . '.' . $parts[1];
594
-            $explodedPropertyPath[1] = $parts[2];
595
-            $fieldName = $explodedPropertyPath[0];
596
-        }
597
-
598
-        $parentKeyFieldName = $table->field($fieldName)->getForeignField();
599
-        $childTableName = $table->field($fieldName)->getForeignTable();
600
-
601
-        if ($childTableName === null) {
602
-            throw new Exception\InvalidRelationConfigurationException('The relation information for property "' . $fieldName . '" of class "' . $tableName . '" is missing.', 1353170925);
603
-        }
604
-
605
-        if ($table->field($fieldName)->hasOne()) { // includes relation "one-to-one" and "many-to-one"
606
-            // sometimes the opposite relation is not defined. We don't want to force this config for backward compatibility reasons.
607
-            // $parentKeyFieldName === null does the trick somehow. Before condition was if (isset($parentKeyFieldName))
608
-            if ($table->field($fieldName)->hasRelationManyToOne() || $parentKeyFieldName === null) {
609
-                $sql['unions'][$childTableName] = 'LEFT JOIN ' . $childTableName . ' ON ' . $tableName . '.' . $fieldName . '=' . $childTableName . '.uid';
610
-            } else {
611
-                $sql['unions'][$childTableName] = 'LEFT JOIN ' . $childTableName . ' ON ' . $tableName . '.uid=' . $childTableName . '.' . $parentKeyFieldName;
612
-            }
613
-        } elseif ($table->field($fieldName)->hasRelationManyToMany()) {
614
-            $relationTableName = $table->field($fieldName)->getManyToManyTable();
615
-
616
-            $parentKeyFieldName = $table->field($fieldName)->isOppositeRelation() ? 'uid_foreign' : 'uid_local';
617
-            $childKeyFieldName = !$table->field($fieldName)->isOppositeRelation() ? 'uid_foreign' : 'uid_local';
618
-
619
-            // MM table e.g sys_category_record_mm
620
-            $relationTableNameAlias = $this->generateAlias($relationTableName);
621
-            $join = sprintf(
622
-                'LEFT JOIN %s AS %s ON %s.uid=%s.%s', $relationTableName,
623
-                $relationTableNameAlias,
624
-                $tableName,
625
-                $relationTableNameAlias,
626
-                $parentKeyFieldName
627
-            );
628
-            $sql['unions'][$relationTableNameAlias] = $join;
629
-
630
-            // Foreign table e.g sys_category
631
-            $childTableNameAlias = $this->generateAlias($childTableName);
632
-            $this->currentChildTableNameAlias = $childTableNameAlias;
633
-            $join = sprintf(
634
-                'LEFT JOIN %s AS %s ON %s.%s=%s.uid',
635
-                $childTableName,
636
-                $childTableNameAlias,
637
-                $relationTableNameAlias,
638
-                $childKeyFieldName,
639
-                $childTableNameAlias
640
-            );
641
-            $sql['unions'][$childTableNameAlias] = $join;
642
-
643
-            // Find a possible table name for a MM condition.
644
-            $tableNameCondition = $table->field($fieldName)->getAdditionalTableNameCondition();
645
-            if ($tableNameCondition) {
646
-
647
-                // If we can find a source file name,  we can then retrieve more MM conditions from the TCA such as a field name.
648
-                $sourceFileName = $this->query->getSourceFieldName();
649
-                if (empty($sourceFileName)) {
650
-                    $additionalMMConditions = array(
651
-                        'tablenames' => $tableNameCondition,
652
-                    );
653
-                } else {
654
-                    $additionalMMConditions = Tca::table($tableNameCondition)->field($sourceFileName)->getAdditionalMMCondition();
655
-                }
656
-
657
-                foreach ($additionalMMConditions as $additionalFieldName => $additionalMMCondition) {
658
-                    $additionalJoin = sprintf(' AND %s.%s = "%s"', $relationTableNameAlias, $additionalFieldName, $additionalMMCondition);
659
-                    $sql['unions'][$relationTableNameAlias] .= $additionalJoin;
660
-
661
-                    $additionalJoin = sprintf(' AND %s.%s = "%s"', $relationTableNameAlias, $additionalFieldName, $additionalMMCondition);
662
-                    $sql['unions'][$childTableNameAlias] .= $additionalJoin;
663
-                }
664
-
665
-            }
666
-
667
-
668
-        } elseif ($table->field($fieldName)->hasMany()) { // includes relations "many-to-one" and "csv" relations
669
-            $childTableNameAlias = $this->generateAlias($childTableName);
670
-            $this->currentChildTableNameAlias = $childTableNameAlias;
671
-
672
-            if (isset($parentKeyFieldName)) {
673
-                $join = sprintf(
674
-                    'LEFT JOIN %s AS %s ON %s.uid=%s.%s',
675
-                    $childTableName,
676
-                    $childTableNameAlias,
677
-                    $tableName,
678
-                    $childTableNameAlias,
679
-                    $parentKeyFieldName
680
-                );
681
-                $sql['unions'][$childTableNameAlias] = $join;
682
-            } else {
683
-                $join = sprintf(
684
-                    'LEFT JOIN %s AS %s ON (FIND_IN_SET(%s.uid, %s.%s))',
685
-                    $childTableName,
686
-                    $childTableNameAlias,
687
-                    $childTableNameAlias,
688
-                    $tableName,
689
-                    $fieldName
690
-                );
691
-                $sql['unions'][$childTableNameAlias] = $join;
692
-            }
693
-        } else {
694
-            throw new Exception('Could not determine type of relation.', 1252502725);
695
-        }
696
-
697
-        // TODO check if there is another solution for this
698
-        $sql['keywords']['distinct'] = 'DISTINCT';
699
-        $propertyPath = $explodedPropertyPath[1];
700
-        $tableName = $childTableName;
701
-    }
702
-
703
-    /**
704
-     * Returns the SQL operator for the given JCR operator type.
705
-     *
706
-     * @param string $operator One of the JCR_OPERATOR_* constants
707
-     * @throws Exception
708
-     * @return string an SQL operator
709
-     */
710
-    protected function resolveOperator($operator)
711
-    {
712
-        switch ($operator) {
713
-            case self::OPERATOR_EQUAL_TO_NULL:
714
-                $operator = 'IS';
715
-                break;
716
-            case self::OPERATOR_NOT_EQUAL_TO_NULL:
717
-                $operator = 'IS NOT';
718
-                break;
719
-            case QueryInterface::OPERATOR_IN:
720
-                $operator = 'IN';
721
-                break;
722
-            case QueryInterface::OPERATOR_EQUAL_TO:
723
-                $operator = '=';
724
-                break;
725
-            case QueryInterface::OPERATOR_NOT_EQUAL_TO:
726
-                $operator = '!=';
727
-                break;
728
-            case QueryInterface::OPERATOR_LESS_THAN:
729
-                $operator = '<';
730
-                break;
731
-            case QueryInterface::OPERATOR_LESS_THAN_OR_EQUAL_TO:
732
-                $operator = '<=';
733
-                break;
734
-            case QueryInterface::OPERATOR_GREATER_THAN:
735
-                $operator = '>';
736
-                break;
737
-            case QueryInterface::OPERATOR_GREATER_THAN_OR_EQUAL_TO:
738
-                $operator = '>=';
739
-                break;
740
-            case QueryInterface::OPERATOR_LIKE:
741
-                $operator = 'LIKE';
742
-                break;
743
-            default:
744
-                throw new Exception('Unsupported operator encountered.', 1242816073);
745
-        }
746
-        return $operator;
747
-    }
748
-
749
-    /**
750
-     * Replace query placeholders in a query part by the given
751
-     * parameters.
752
-     *
753
-     * @param string &$sqlString The query part with placeholders
754
-     * @param array $parameters The parameters
755
-     * @param string $tableName
756
-     *
757
-     * @throws Exception
758
-     */
759
-    protected function replacePlaceholders(&$sqlString, array $parameters, $tableName = 'foo')
760
-    {
761
-        // TODO profile this method again
762
-        if (substr_count($sqlString, '?') !== count($parameters)) {
763
-            throw new Exception('The number of question marks to replace must be equal to the number of parameters.', 1242816074);
764
-        }
765
-        $offset = 0;
766
-        foreach ($parameters as $parameter) {
767
-            $markPosition = strpos($sqlString, '?', $offset);
768
-            if ($markPosition !== false) {
769
-                if ($parameter === null) {
770
-                    $parameter = 'null';
771
-                } elseif (is_array($parameter) || $parameter instanceof \ArrayAccess || $parameter instanceof \Traversable) {
772
-                    $items = [];
773
-                    foreach ($parameter as $item) {
774
-                        $items[] = $this->databaseHandle->fullQuoteStr($item, $tableName);
775
-                    }
776
-                    $parameter = '(' . implode(',', $items) . ')';
777
-                } else {
778
-                    $parameter = $this->databaseHandle->fullQuoteStr($parameter, $tableName);
779
-                }
780
-                $sqlString = substr($sqlString, 0, $markPosition) . $parameter . substr($sqlString, ($markPosition + 1));
781
-            }
782
-            $offset = $markPosition + strlen($parameter);
783
-        }
784
-    }
785
-
786
-    /**
787
-     * Adds additional WHERE statements according to the query settings.
788
-     *
789
-     * @param QuerySettingsInterface $querySettings The TYPO3 CMS specific query settings
790
-     * @param string $tableNameOrAlias The table name to add the additional where clause for
791
-     * @param array &$statementParts
792
-     * @return void
793
-     */
794
-    protected function addAdditionalWhereClause(QuerySettingsInterface $querySettings, $tableNameOrAlias, &$statementParts)
795
-    {
796
-        $this->addVisibilityConstraintStatement($querySettings, $tableNameOrAlias, $statementParts);
797
-        if ($querySettings->getRespectSysLanguage()) {
798
-            $this->addSysLanguageStatement($tableNameOrAlias, $statementParts, $querySettings);
799
-        }
800
-    }
801
-
802
-    /**
803
-     * Adds enableFields and deletedClause to the query if necessary
804
-     *
805
-     * @param QuerySettingsInterface $querySettings
806
-     * @param string $tableNameOrAlias The database table name
807
-     * @param array &$statementParts The query parts
808
-     * @return void
809
-     */
810
-    protected function addVisibilityConstraintStatement(QuerySettingsInterface $querySettings, $tableNameOrAlias, array &$statementParts)
811
-    {
812
-        $statement = '';
813
-        $tableName = $this->resolveTableNameAlias($tableNameOrAlias);
814
-        if (is_array($GLOBALS['TCA'][$tableName]['ctrl'])) {
815
-            $ignoreEnableFields = $querySettings->getIgnoreEnableFields();
816
-            $enableFieldsToBeIgnored = $querySettings->getEnableFieldsToBeIgnored();
817
-            $includeDeleted = $querySettings->getIncludeDeleted();
818
-            if ($this->environmentService->isEnvironmentInFrontendMode()) {
819
-                $statement .= $this->getFrontendConstraintStatement($tableNameOrAlias, $ignoreEnableFields, $enableFieldsToBeIgnored, $includeDeleted);
820
-            } else {
821
-                // TYPO3_MODE === 'BE'
822
-                $statement .= $this->getBackendConstraintStatement($tableNameOrAlias, $ignoreEnableFields, $includeDeleted);
823
-            }
824
-
825
-            // Remove the prefixing "AND" if any.
826
-            if (!empty($statement)) {
827
-                $statement = strtolower(substr($statement, 1, 3)) === 'and' ? substr($statement, 5) : $statement;
828
-                $statementParts['additionalWhereClause'][$tableNameOrAlias][] = $statement;
829
-            }
830
-        }
831
-    }
832
-
833
-    /**
834
-     * Returns constraint statement for frontend context
835
-     *
836
-     * @param string $tableNameOrAlias
837
-     * @param boolean $ignoreEnableFields A flag indicating whether the enable fields should be ignored
838
-     * @param array $enableFieldsToBeIgnored If $ignoreEnableFields is true, this array specifies enable fields to be ignored. If it is null or an empty array (default) all enable fields are ignored.
839
-     * @param boolean $includeDeleted A flag indicating whether deleted records should be included
840
-     * @return string
841
-     * @throws Exception\InconsistentQuerySettingsException
842
-     */
843
-    protected function getFrontendConstraintStatement($tableNameOrAlias, $ignoreEnableFields, $enableFieldsToBeIgnored = [], $includeDeleted)
844
-    {
845
-        $statement = '';
846
-        $tableName = $this->resolveTableNameAlias($tableNameOrAlias);
847
-        if ($ignoreEnableFields && !$includeDeleted) {
848
-            if (count($enableFieldsToBeIgnored)) {
849
-                // array_combine() is necessary because of the way \TYPO3\CMS\Frontend\Page\PageRepository::enableFields() is implemented
850
-                $statement .= $this->getPageRepository()->enableFields($tableName, -1, array_combine($enableFieldsToBeIgnored, $enableFieldsToBeIgnored));
851
-            } else {
852
-                $statement .= $this->getPageRepository()->deleteClause($tableName);
853
-            }
854
-        } elseif (!$ignoreEnableFields && !$includeDeleted) {
855
-            $statement .= $this->getPageRepository()->enableFields($tableName);
856
-        } elseif (!$ignoreEnableFields && $includeDeleted) {
857
-            throw new Exception\InconsistentQuerySettingsException('Query setting "ignoreEnableFields=false" can not be used together with "includeDeleted=true" in frontend context.', 1327678173);
858
-        }
859
-        return $this->replaceTableNameByAlias($tableName, $tableNameOrAlias, $statement);
860
-    }
861
-
862
-    /**
863
-     * Returns constraint statement for backend context
864
-     *
865
-     * @param string $tableNameOrAlias
866
-     * @param boolean $ignoreEnableFields A flag indicating whether the enable fields should be ignored
867
-     * @param boolean $includeDeleted A flag indicating whether deleted records should be included
868
-     * @return string
869
-     */
870
-    protected function getBackendConstraintStatement($tableNameOrAlias, $ignoreEnableFields, $includeDeleted)
871
-    {
872
-        $tableName = $this->resolveTableNameAlias($tableNameOrAlias);
873
-        $statement = '';
874
-        if (!$ignoreEnableFields) {
875
-            $statement .= BackendUtility::BEenableFields($tableName);
876
-        }
877
-
878
-        // If the table is found to have "workspace" support, add the corresponding fields in the statement.
879
-        if (Tca::table($tableName)->hasWorkspaceSupport()) {
880
-            if ($this->getBackendUser()->workspace === 0) {
881
-                $statement .= ' AND ' . $tableName . '.t3ver_state<=' . new VersionState(VersionState::DEFAULT_STATE);
882
-            } else {
883
-                // Show only records of live and of the current workspace
884
-                // In case we are in a Versioning preview
885
-                $statement .= ' AND (' .
886
-                    $tableName . '.t3ver_wsid=0 OR ' .
887
-                    $tableName . '.t3ver_wsid=' . (int)$this->getBackendUser()->workspace .
888
-                    ')';
889
-            }
890
-
891
-            // Check if this segment make sense here or whether it should be in the "if" part when we have workspace = 0
892
-            $statement .= ' AND ' . $tableName . '.pid<>-1';
893
-        }
894
-
895
-        if (!$includeDeleted) {
896
-            $statement .= BackendUtility::deleteClause($tableName);
897
-        }
898
-
899
-        return $this->replaceTableNameByAlias($tableName, $tableNameOrAlias, $statement);
900
-    }
901
-
902
-    /**
903
-     * Builds the language field statement
904
-     *
905
-     * @param string $tableNameOrAlias The database table name
906
-     * @param array &$statementParts The query parts
907
-     * @param QuerySettingsInterface $querySettings The TYPO3 CMS specific query settings
908
-     * @throws Exception
909
-     * @return void
910
-     */
911
-    protected function addSysLanguageStatement($tableNameOrAlias, array &$statementParts, $querySettings)
912
-    {
913
-
914
-        $tableName = $this->resolveTableNameAlias($tableNameOrAlias);
915
-        if (is_array($GLOBALS['TCA'][$tableName]['ctrl'])) {
916
-            if (!empty($GLOBALS['TCA'][$tableName]['ctrl']['languageField'])) {
917
-                // Select all entries for the current language
918
-                $additionalWhereClause = $tableNameOrAlias . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] . ' IN (' . intval($querySettings->getLanguageUid()) . ',-1)';
919
-                // If any language is set -> get those entries which are not translated yet
920
-                // They will be removed by t3lib_page::getRecordOverlay if not matching overlay mode
921
-                if (isset($GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'])
922
-                    && $querySettings->getLanguageUid() > 0
923
-                ) {
924
-                    $additionalWhereClause .= ' OR (' . $tableNameOrAlias . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] . '=0' .
925
-                        ' AND ' . $tableNameOrAlias . '.uid NOT IN (SELECT ' . $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'] .
926
-                        ' FROM ' . $tableName .
927
-                        ' WHERE ' . $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'] . '>0' .
928
-                        ' AND ' . $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] . '>0';
929
-
930
-                    // Add delete clause to ensure all entries are loaded
931
-                    if (isset($GLOBALS['TCA'][$tableName]['ctrl']['delete'])) {
932
-                        $additionalWhereClause .= ' AND ' . $tableNameOrAlias . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['delete'] . '=0';
933
-                    }
934
-                    $additionalWhereClause .= '))';
935
-                }
936
-                $statementParts['additionalWhereClause'][$tableNameOrAlias][] = '(' . $additionalWhereClause . ')';
937
-            }
938
-        }
939
-    }
940
-
941
-    /**
942
-     * Transforms orderings into SQL.
943
-     *
944
-     * @param array $orderings An array of orderings (Tx_Extbase_Persistence_QOM_Ordering)
945
-     * @param SourceInterface $source The source
946
-     * @param array &$sql The query parts
947
-     * @throws Exception\UnsupportedOrderException
948
-     * @return void
949
-     */
950
-    protected function parseOrderings(array $orderings, SourceInterface $source, array &$sql)
951
-    {
952
-        foreach ($orderings as $fieldNameAndPath => $order) {
953
-            switch ($order) {
954
-                case QueryInterface::ORDER_ASCENDING:
955
-                    $order = 'ASC';
956
-                    break;
957
-                case QueryInterface::ORDER_DESCENDING:
958
-                    $order = 'DESC';
959
-                    break;
960
-                default:
961
-                    throw new Exception\UnsupportedOrderException('Unsupported order encountered.', 1456845126);
962
-            }
963
-
964
-            $tableName = $this->getFieldPathResolver()->getDataType($fieldNameAndPath, $this->query->getType());
965
-            $fieldName = $this->getFieldPathResolver()->stripFieldPath($fieldNameAndPath, $tableName);
966
-            $sql['orderings'][] = sprintf('%s.%s %s', $tableName, $fieldName, $order);
967
-        }
968
-    }
969
-
970
-    /**
971
-     * Transforms limit and offset into SQL
972
-     *
973
-     * @param int $limit
974
-     * @param int $offset
975
-     * @param array &$sql
976
-     * @return void
977
-     */
978
-    protected function parseLimitAndOffset($limit, $offset, array &$sql)
979
-    {
980
-        if ($limit !== null && $offset !== null) {
981
-            $sql['limit'] = intval($offset) . ', ' . intval($limit);
982
-        } elseif ($limit !== null) {
983
-            $sql['limit'] = intval($limit);
984
-        }
985
-    }
986
-
987
-    /**
988
-     * Transforms a Resource from a database query to an array of rows.
989
-     *
990
-     * @param resource $result The result
991
-     * @return array The result as an array of rows (tuples)
992
-     */
993
-    protected function getRowsFromResult($result)
994
-    {
995
-        $rows = [];
996
-        while ($row = $this->databaseHandle->sql_fetch_assoc($result)) {
997
-            if (is_array($row)) {
998
-
999
-                // Get language uid from querySettings.
1000
-                // Ensure the backend handling is not broken (fallback to Get parameter 'L' if needed)
1001
-                $overlaidRow = $this->doLanguageAndWorkspaceOverlay($this->query->getSource(), $row, $this->query->getQuerySettings());
1002
-                $contentObject = GeneralUtility::makeInstance($this->objectType, $this->query->getType(), $overlaidRow);
1003
-                $rows[] = $contentObject;
1004
-            }
1005
-        }
1006
-
1007
-        return $rows;
1008
-    }
1009
-
1010
-    /**
1011
-     * Performs workspace and language overlay on the given row array. The language and workspace id is automatically
1012
-     * detected (depending on FE or BE context). You can also explicitly set the language/workspace id.
1013
-     *
1014
-     * @param SourceInterface $source The source (selector od join)
1015
-     * @param array $row
1016
-     * @param QuerySettingsInterface $querySettings The TYPO3 CMS specific query settings
1017
-     * @return array
1018
-     */
1019
-    protected function doLanguageAndWorkspaceOverlay(SourceInterface $source, array $row, $querySettings)
1020
-    {
1021
-
1022
-        /** @var SelectorInterface $source */
1023
-        $tableName = $source->getSelectorName();
1024
-
1025
-        $pageRepository = $this->getPageRepository();
1026
-        if (is_object($GLOBALS['TSFE'])) {
1027
-            $languageMode = $GLOBALS['TSFE']->sys_language_mode;
1028
-            if ($this->isBackendUserLogged() && $this->getBackendUser()->workspace !== 0) {
1029
-                $pageRepository->versioningWorkspaceId = $this->getBackendUser()->workspace;
1030
-            }
1031
-        } else {
1032
-            $languageMode = '';
1033
-            $workspaceUid = $this->getBackendUser()->workspace;
1034
-            $pageRepository->versioningWorkspaceId = $workspaceUid;
1035
-            if ($this->getBackendUser()->workspace !== 0) {
1036
-                $pageRepository->versioningPreview = 1;
1037
-            }
1038
-        }
1039
-
1040
-        // If current row is a translation select its parent
1041
-        if (isset($GLOBALS['TCA'][$tableName]['ctrl']['languageField'])
1042
-            && isset($GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'])
1043
-        ) {
1044
-            if (isset($row[$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']])
1045
-                && $row[$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']] > 0
1046
-            ) {
1047
-                $row = $this->databaseHandle->exec_SELECTgetSingleRow(
1048
-                    $tableName . '.*',
1049
-                    $tableName,
1050
-                    $tableName . '.uid=' . (int)$row[$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']] .
1051
-                    ' AND ' . $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] . '=0'
1052
-                );
1053
-            }
1054
-        }
1055
-
1056
-        // Retrieve the original uid; Used for Workspaces!
1057
-        if (TYPO3_MODE !== 'BE') {
1058
-            $pageRepository->versionOL($tableName, $row, true, true);
1059
-        } else {
1060
-            BackendUtility::workspaceOL($tableName, $row);
1061
-        }
1062
-        if ($pageRepository->versioningPreview && isset($row['_ORIG_uid'])) {
1063
-            $row['uid'] = $row['_ORIG_uid'];
1064
-        }
1065
-
1066
-        // Special case for table "pages"
1067
-        if ($tableName == 'pages') {
1068
-            $row = $pageRepository->getPageOverlay($row, $querySettings->getLanguageUid());
1069
-        } elseif (isset($GLOBALS['TCA'][$tableName]['ctrl']['languageField'])
1070
-            && $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] !== ''
1071
-        ) {
1072
-            if (in_array($row[$GLOBALS['TCA'][$tableName]['ctrl']['languageField']], array(-1, 0))) {
1073
-                $overlayMode = $languageMode === 'strict' ? 'hideNonTranslated' : '';
1074
-                $row = $pageRepository->getRecordOverlay($tableName, $row, $querySettings->getLanguageUid(), $overlayMode);
1075
-            }
1076
-        }
1077
-
1078
-        return $row;
1079
-    }
1080
-
1081
-    /**
1082
-     * Return a resolved table name given a possible table name alias.
1083
-     *
1084
-     * @param string $tableNameOrAlias
1085
-     * @return string
1086
-     */
1087
-    protected function resolveTableNameAlias($tableNameOrAlias)
1088
-    {
1089
-        $resolvedTableName = $tableNameOrAlias;
1090
-        if (!empty($this->tableNameAliases['aliases'][$tableNameOrAlias])) {
1091
-            $resolvedTableName = $this->tableNameAliases['aliases'][$tableNameOrAlias];
1092
-        }
1093
-        return $resolvedTableName;
1094
-    }
1095
-
1096
-    /**
1097
-     * Generate a unique table name alias for the given table name.
1098
-     *
1099
-     * @param string $tableName
1100
-     * @return string
1101
-     */
1102
-    protected function generateAlias($tableName)
1103
-    {
1104
-
1105
-        if (!isset($this->tableNameAliases['aliasIncrement'][$tableName])) {
1106
-            $this->tableNameAliases['aliasIncrement'][$tableName] = 0;
1107
-        }
1108
-
1109
-        $numberOfAliases = $this->tableNameAliases['aliasIncrement'][$tableName];
1110
-        $tableNameAlias = $tableName . $numberOfAliases;
1111
-
1112
-        $this->tableNameAliases['aliasIncrement'][$tableName]++;
1113
-        $this->tableNameAliases['aliases'][$tableNameAlias] = $tableName;
1114
-
1115
-        return $tableNameAlias;
1116
-    }
1117
-
1118
-    /**
1119
-     * Replace the table names by its table name alias within the given statement.
1120
-     *
1121
-     * @param string $tableName
1122
-     * @param string $tableNameAlias
1123
-     * @param string $statement
1124
-     * @return string
1125
-     */
1126
-    protected function replaceTableNameByAlias($tableName, $tableNameAlias, $statement)
1127
-    {
1128
-        if ($statement && $tableName !== $tableNameAlias) {
1129
-            $statement = str_replace($tableName, $tableNameAlias, $statement);
1130
-        }
1131
-        return $statement;
1132
-    }
1133
-
1134
-    /**
1135
-     * Returns an instance of the current Backend User.
1136
-     *
1137
-     * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
1138
-     */
1139
-    protected function getBackendUser()
1140
-    {
1141
-        return $GLOBALS['BE_USER'];
1142
-    }
1143
-
1144
-    /**
1145
-     * Tell whether a Backend User is logged in.
1146
-     *
1147
-     * @return bool
1148
-     */
1149
-    protected function isBackendUserLogged()
1150
-    {
1151
-        return is_object($GLOBALS['BE_USER']);
1152
-    }
1153
-
1154
-    /**
1155
-     * @return PageRepository
1156
-     */
1157
-    protected function getPageRepository()
1158
-    {
1159
-        if (!$this->pageRepository instanceof PageRepository) {
1160
-            if ($this->environmentService->isEnvironmentInFrontendMode() && is_object($GLOBALS['TSFE'])) {
1161
-                $this->pageRepository = $GLOBALS['TSFE']->sys_page;
1162
-            } else {
1163
-                $this->pageRepository = GeneralUtility::makeInstance('TYPO3\\CMS\\Frontend\\Page\\PageRepository');
1164
-            }
1165
-        }
1166
-
1167
-        return $this->pageRepository;
1168
-    }
1169
-
1170
-    /**
1171
-     * @return \Fab\Vidi\Resolver\FieldPathResolver
1172
-     */
1173
-    protected function getFieldPathResolver()
1174
-    {
1175
-        return GeneralUtility::makeInstance('Fab\Vidi\Resolver\FieldPathResolver');
1176
-    }
1177
-
1178
-    /**
1179
-     * Checks if there are SQL errors in the last query, and if yes, throw an exception.
1180
-     *
1181
-     * @return void
1182
-     * @param string $sql The SQL statement
1183
-     * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Storage\Exception\SqlErrorException
1184
-     */
1185
-    protected function checkSqlErrors($sql = '')
1186
-    {
1187
-        $error = $this->databaseHandle->sql_error();
1188
-        if ($error !== '') {
1189
-            $error .= $sql ? ': ' . $sql : '';
1190
-            throw new \TYPO3\CMS\Extbase\Persistence\Generic\Storage\Exception\SqlErrorException($error, 1247602160);
1191
-        }
1192
-    }
35
+	const OPERATOR_EQUAL_TO_NULL = 'operatorEqualToNull';
36
+	const OPERATOR_NOT_EQUAL_TO_NULL = 'operatorNotEqualToNull';
37
+
38
+	/**
39
+	 * The TYPO3 database object
40
+	 *
41
+	 * @var \TYPO3\CMS\Core\Database\DatabaseConnection
42
+	 */
43
+	protected $databaseHandle;
44
+
45
+	/**
46
+	 * The TYPO3 page repository. Used for language and workspace overlay
47
+	 *
48
+	 * @var PageRepository
49
+	 */
50
+	protected $pageRepository;
51
+
52
+	/**
53
+	 * A first-level TypoScript configuration cache
54
+	 *
55
+	 * @var array
56
+	 */
57
+	protected $pageTSConfigCache = [];
58
+
59
+	/**
60
+	 * @var \TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface
61
+	 * @inject
62
+	 */
63
+	protected $configurationManager;
64
+
65
+	/**
66
+	 * @var \TYPO3\CMS\Extbase\Service\CacheService
67
+	 * @inject
68
+	 */
69
+	protected $cacheService;
70
+
71
+	/**
72
+	 * @var \TYPO3\CMS\Core\Cache\CacheManager
73
+	 * @inject
74
+	 */
75
+	protected $cacheManager;
76
+
77
+	/**
78
+	 * @var \TYPO3\CMS\Extbase\Service\EnvironmentService
79
+	 * @inject
80
+	 */
81
+	protected $environmentService;
82
+
83
+	/**
84
+	 * @var \Fab\Vidi\Persistence\Query
85
+	 */
86
+	protected $query;
87
+
88
+	/**
89
+	 * Store some info related to table name and its aliases.
90
+	 *
91
+	 * @var array
92
+	 */
93
+	protected $tableNameAliases = array(
94
+		'aliases' => [],
95
+		'aliasIncrement' => [],
96
+	);
97
+
98
+	/**
99
+	 * Use to store the current foreign table name alias.
100
+	 *
101
+	 * @var string
102
+	 */
103
+	protected $currentChildTableNameAlias = '';
104
+
105
+	/**
106
+	 * The default object type being returned.
107
+	 *
108
+	 * @var string
109
+	 */
110
+	protected $objectType = 'Fab\Vidi\Domain\Model\Content';
111
+
112
+	/**
113
+	 * Constructor. takes the database handle from $GLOBALS['TYPO3_DB']
114
+	 */
115
+	public function __construct(QueryInterface $query)
116
+	{
117
+		$this->query = $query;
118
+		$this->databaseHandle = $GLOBALS['TYPO3_DB'];
119
+	}
120
+
121
+	/**
122
+	 * @param array $identifier
123
+	 * @return string
124
+	 */
125
+	protected function parseIdentifier(array $identifier)
126
+	{
127
+		$fieldNames = array_keys($identifier);
128
+		$suffixedFieldNames = [];
129
+		foreach ($fieldNames as $fieldName) {
130
+			$suffixedFieldNames[] = $fieldName . '=?';
131
+		}
132
+		return implode(' AND ', $suffixedFieldNames);
133
+	}
134
+
135
+	/**
136
+	 * Returns the result of the query
137
+	 */
138
+	public function fetchResult()
139
+	{
140
+
141
+		$parameters = [];
142
+		$statementParts = $this->parseQuery($this->query, $parameters);
143
+		$statementParts = $this->processStatementStructureForRecursiveMMRelation($statementParts); // Mmm... check if that is the right way of doing that.
144
+
145
+		$sql = $this->buildQuery($statementParts);
146
+		$tableName = '';
147
+		if (is_array($statementParts) && !empty(reset($statementParts['tables']))) {
148
+			$tableName = reset($statementParts['tables']);
149
+		}
150
+		$this->replacePlaceholders($sql, $parameters, $tableName);
151
+		#print $sql; exit(); // @debug
152
+
153
+		$result = $this->databaseHandle->sql_query($sql);
154
+		$this->checkSqlErrors($sql);
155
+		$rows = $this->getRowsFromResult($result);
156
+		$this->databaseHandle->sql_free_result($result);
157
+
158
+		return $rows;
159
+	}
160
+
161
+	/**
162
+	 * Returns the number of tuples matching the query.
163
+	 *
164
+	 * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Storage\Exception\BadConstraintException
165
+	 * @return int The number of matching tuples
166
+	 */
167
+	public function countResult()
168
+	{
169
+
170
+		$parameters = [];
171
+		$statementParts = $this->parseQuery($this->query, $parameters);
172
+		$statementParts = $this->processStatementStructureForRecursiveMMRelation($statementParts); // Mmm... check if that is the right way of doing that.
173
+		// Reset $statementParts for valid table return
174
+		reset($statementParts);
175
+
176
+		// if limit is set, we need to count the rows "manually" as COUNT(*) ignores LIMIT constraints
177
+		if (!empty($statementParts['limit'])) {
178
+			$statement = $this->buildQuery($statementParts);
179
+			$this->replacePlaceholders($statement, $parameters, current($statementParts['tables']));
180
+			#print $statement; exit(); // @debug
181
+			$result = $this->databaseHandle->sql_query($statement);
182
+			$this->checkSqlErrors($statement);
183
+			$count = $this->databaseHandle->sql_num_rows($result);
184
+		} else {
185
+			$statementParts['fields'] = array('COUNT(*)');
186
+			// having orderings without grouping is not compatible with non-MySQL DBMS
187
+			$statementParts['orderings'] = [];
188
+			if (isset($statementParts['keywords']['distinct'])) {
189
+				unset($statementParts['keywords']['distinct']);
190
+				$distinctField = $this->query->getDistinct() ? $this->query->getDistinct() : 'uid';
191
+				$statementParts['fields'] = array('COUNT(DISTINCT ' . reset($statementParts['tables']) . '.' . $distinctField . ')');
192
+			}
193
+
194
+			$statement = $this->buildQuery($statementParts);
195
+			$this->replacePlaceholders($statement, $parameters, current($statementParts['tables']));
196
+
197
+			#print $statement; exit(); // @debug
198
+			$result = $this->databaseHandle->sql_query($statement);
199
+			$this->checkSqlErrors($statement);
200
+			$count = 0;
201
+			if ($result) {
202
+				$row = $this->databaseHandle->sql_fetch_assoc($result);
203
+				$count = current($row);
204
+			}
205
+		}
206
+		$this->databaseHandle->sql_free_result($result);
207
+		return (int)$count;
208
+	}
209
+
210
+	/**
211
+	 * Parses the query and returns the SQL statement parts.
212
+	 *
213
+	 * @param QueryInterface $query The query
214
+	 * @param array &$parameters
215
+	 * @return array The SQL statement parts
216
+	 */
217
+	public function parseQuery(QueryInterface $query, array &$parameters)
218
+	{
219
+		$statementParts = [];
220
+		$statementParts['keywords'] = [];
221
+		$statementParts['tables'] = [];
222
+		$statementParts['unions'] = [];
223
+		$statementParts['fields'] = [];
224
+		$statementParts['where'] = [];
225
+		$statementParts['additionalWhereClause'] = [];
226
+		$statementParts['orderings'] = [];
227
+		$statementParts['limit'] = [];
228
+		$source = $query->getSource();
229
+		$this->parseSource($source, $statementParts);
230
+		$this->parseConstraint($query->getConstraint(), $source, $statementParts, $parameters);
231
+		$this->parseOrderings($query->getOrderings(), $source, $statementParts);
232
+		$this->parseLimitAndOffset($query->getLimit(), $query->getOffset(), $statementParts);
233
+		$tableNames = array_unique(array_keys($statementParts['tables'] + $statementParts['unions']));
234
+		foreach ($tableNames as $tableNameOrAlias) {
235
+			if (is_string($tableNameOrAlias) && strlen($tableNameOrAlias) > 0) {
236
+				$this->addAdditionalWhereClause($query->getQuerySettings(), $tableNameOrAlias, $statementParts);
237
+			}
238
+		}
239
+
240
+		return $statementParts;
241
+	}
242
+
243
+	/**
244
+	 * Fiddle with the statement structure to handle recursive MM relations.
245
+	 * For the recursive MM query to work, we must invert some values.
246
+	 * Let see if that is the best way of doing that...
247
+	 *
248
+	 * @param array $statementParts
249
+	 * @return array
250
+	 */
251
+	public function processStatementStructureForRecursiveMMRelation(array $statementParts)
252
+	{
253
+
254
+		if ($this->hasRecursiveMMRelation()) {
255
+			$tableName = $this->query->getType();
256
+
257
+			// In order the MM query to work for a recursive MM query, we must invert some values.
258
+			// tx_domain_model_foo0 (the alias) <--> tx_domain_model_foo (the origin table name)
259
+			$values = [];
260
+			foreach ($statementParts['fields'] as $key => $value) {
261
+				$values[$key] = str_replace($tableName, $tableName . '0', $value);
262
+			}
263
+			$statementParts['fields'] = $values;
264
+
265
+			// Same comment as above.
266
+			$values = [];
267
+			foreach ($statementParts['where'] as $key => $value) {
268
+				$values[$key] = str_replace($tableName . '0', $tableName, $value);
269
+			}
270
+			$statementParts['where'] = $values;
271
+
272
+			// We must be more restrictive by transforming the "left" union by "inner"
273
+			$values = [];
274
+			foreach ($statementParts['unions'] as $key => $value) {
275
+				$values[$key] = str_replace('LEFT JOIN', 'INNER JOIN', $value);
276
+			}
277
+			$statementParts['unions'] = $values;
278
+		}
279
+
280
+		return $statementParts;
281
+	}
282
+
283
+	/**
284
+	 * Tell whether there is a recursive MM relation.
285
+	 *
286
+	 * @return bool
287
+	 */
288
+	public function hasRecursiveMMRelation()
289
+	{
290
+		return isset($this->tableNameAliases['aliasIncrement'][$this->query->getType()]);
291
+
292
+	}
293
+
294
+	/**
295
+	 * Returns the statement, ready to be executed.
296
+	 *
297
+	 * @param array $statementParts The SQL statement parts
298
+	 * @return string The SQL statement
299
+	 */
300
+	public function buildQuery(array $statementParts)
301
+	{
302
+
303
+		// Add more statement to the UNION part.
304
+		if (!empty($statementParts['unions'])) {
305
+			foreach ($statementParts['unions'] as $tableName => $unionPart) {
306
+				if (!empty($statementParts['additionalWhereClause'][$tableName])) {
307
+					$statementParts['unions'][$tableName] .= ' AND ' . implode(' AND ', $statementParts['additionalWhereClause'][$tableName]);
308
+				}
309
+			}
310
+		}
311
+
312
+		$statement = 'SELECT ' . implode(' ', $statementParts['keywords']) . ' ' . implode(',', $statementParts['fields']) . ' FROM ' . implode(' ', $statementParts['tables']) . ' ' . implode(' ', $statementParts['unions']);
313
+		if (!empty($statementParts['where'])) {
314
+			$statement .= ' WHERE ' . implode('', $statementParts['where']);
315
+			if (!empty($statementParts['additionalWhereClause'][$this->query->getType()])) {
316
+				$statement .= ' AND ' . implode(' AND ', $statementParts['additionalWhereClause'][$this->query->getType()]);
317
+			}
318
+		} elseif (!empty($statementParts['additionalWhereClause'])) {
319
+			$statement .= ' WHERE ' . implode(' AND ', $statementParts['additionalWhereClause'][$this->query->getType()]);
320
+		}
321
+		if (!empty($statementParts['orderings'])) {
322
+			$statement .= ' ORDER BY ' . implode(', ', $statementParts['orderings']);
323
+		}
324
+		if (!empty($statementParts['limit'])) {
325
+			$statement .= ' LIMIT ' . $statementParts['limit'];
326
+		}
327
+
328
+		return $statement;
329
+	}
330
+
331
+	/**
332
+	 * Transforms a Query Source into SQL and parameter arrays
333
+	 *
334
+	 * @param SourceInterface $source The source
335
+	 * @param array &$sql
336
+	 * @return void
337
+	 */
338
+	protected function parseSource(SourceInterface $source, array &$sql)
339
+	{
340
+		if ($source instanceof SelectorInterface) {
341
+			$tableName = $source->getNodeTypeName();
342
+			$sql['fields'][$tableName] = $tableName . '.*';
343
+			$sql['tables'][$tableName] = $tableName;
344
+			if ($this->query->getDistinct()) {
345
+				$sql['fields'][$tableName] = $tableName . '.' . $this->query->getDistinct();
346
+				$sql['keywords']['distinct'] = 'DISTINCT';
347
+			}
348
+		} elseif ($source instanceof JoinInterface) {
349
+			$this->parseJoin($source, $sql);
350
+		}
351
+	}
352
+
353
+	/**
354
+	 * Transforms a Join into SQL and parameter arrays
355
+	 *
356
+	 * @param JoinInterface $join The join
357
+	 * @param array &$sql The query parts
358
+	 * @return void
359
+	 */
360
+	protected function parseJoin(JoinInterface $join, array &$sql)
361
+	{
362
+		$leftSource = $join->getLeft();
363
+		$leftTableName = $leftSource->getSelectorName();
364
+		// $sql['fields'][$leftTableName] = $leftTableName . '.*';
365
+		$rightSource = $join->getRight();
366
+		if ($rightSource instanceof JoinInterface) {
367
+			$rightTableName = $rightSource->getLeft()->getSelectorName();
368
+		} else {
369
+			$rightTableName = $rightSource->getSelectorName();
370
+			$sql['fields'][$leftTableName] = $rightTableName . '.*';
371
+		}
372
+		$sql['tables'][$leftTableName] = $leftTableName;
373
+		$sql['unions'][$rightTableName] = 'LEFT JOIN ' . $rightTableName;
374
+		$joinCondition = $join->getJoinCondition();
375
+		if ($joinCondition instanceof \TYPO3\CMS\Extbase\Persistence\Generic\Qom\EquiJoinCondition) {
376
+			$column1Name = $joinCondition->getProperty1Name();
377
+			$column2Name = $joinCondition->getProperty2Name();
378
+			$sql['unions'][$rightTableName] .= ' ON ' . $joinCondition->getSelector1Name() . '.' . $column1Name . ' = ' . $joinCondition->getSelector2Name() . '.' . $column2Name;
379
+		}
380
+		if ($rightSource instanceof JoinInterface) {
381
+			$this->parseJoin($rightSource, $sql);
382
+		}
383
+	}
384
+
385
+	/**
386
+	 * Transforms a constraint into SQL and parameter arrays
387
+	 *
388
+	 * @param \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ConstraintInterface $constraint The constraint
389
+	 * @param SourceInterface $source The source
390
+	 * @param array &$sql The query parts
391
+	 * @param array &$parameters The parameters that will replace the markers
392
+	 * @return void
393
+	 */
394
+	protected function parseConstraint(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\ConstraintInterface $constraint = null, SourceInterface $source, array &$sql, array &$parameters)
395
+	{
396
+		if ($constraint instanceof \TYPO3\CMS\Extbase\Persistence\Generic\Qom\AndInterface) {
397
+			$sql['where'][] = '(';
398
+			$this->parseConstraint($constraint->getConstraint1(), $source, $sql, $parameters);
399
+			$sql['where'][] = ' AND ';
400
+			$this->parseConstraint($constraint->getConstraint2(), $source, $sql, $parameters);
401
+			$sql['where'][] = ')';
402
+		} elseif ($constraint instanceof \TYPO3\CMS\Extbase\Persistence\Generic\Qom\OrInterface) {
403
+			$sql['where'][] = '(';
404
+			$this->parseConstraint($constraint->getConstraint1(), $source, $sql, $parameters);
405
+			$sql['where'][] = ' OR ';
406
+			$this->parseConstraint($constraint->getConstraint2(), $source, $sql, $parameters);
407
+			$sql['where'][] = ')';
408
+		} elseif ($constraint instanceof \TYPO3\CMS\Extbase\Persistence\Generic\Qom\NotInterface) {
409
+			$sql['where'][] = 'NOT (';
410
+			$this->parseConstraint($constraint->getConstraint(), $source, $sql, $parameters);
411
+			$sql['where'][] = ')';
412
+		} elseif ($constraint instanceof ComparisonInterface) {
413
+			$this->parseComparison($constraint, $source, $sql, $parameters);
414
+		}
415
+	}
416
+
417
+	/**
418
+	 * Parse a Comparison into SQL and parameter arrays.
419
+	 *
420
+	 * @param ComparisonInterface $comparison The comparison to parse
421
+	 * @param SourceInterface $source The source
422
+	 * @param array &$sql SQL query parts to add to
423
+	 * @param array &$parameters Parameters to bind to the SQL
424
+	 * @throws Exception\RepositoryException
425
+	 * @return void
426
+	 */
427
+	protected function parseComparison(ComparisonInterface $comparison, SourceInterface $source, array &$sql, array &$parameters)
428
+	{
429
+		$operand1 = $comparison->getOperand1();
430
+		$operator = $comparison->getOperator();
431
+		$operand2 = $comparison->getOperand2();
432
+		if ($operator === QueryInterface::OPERATOR_IN) {
433
+			$items = [];
434
+			$hasValue = false;
435
+			foreach ($operand2 as $value) {
436
+				$value = $this->getPlainValue($value);
437
+				if ($value !== null) {
438
+					$items[] = $value;
439
+					$hasValue = true;
440
+				}
441
+			}
442
+			if ($hasValue === false) {
443
+				$sql['where'][] = '1<>1';
444
+			} else {
445
+				$this->parseDynamicOperand($operand1, $operator, $source, $sql, $parameters, null);
446
+				$parameters[] = $items;
447
+			}
448
+		} elseif ($operator === QueryInterface::OPERATOR_CONTAINS) {
449
+			if ($operand2 === null) {
450
+				$sql['where'][] = '1<>1';
451
+			} else {
452
+				throw new \Exception('Not implemented! Contact extension author.', 1412931227);
453
+				# @todo re-implement me if necessary.
454
+				#$tableName = $this->query->getType();
455
+				#$propertyName = $operand1->getPropertyName();
456
+				#while (strpos($propertyName, '.') !== false) {
457
+				#	$this->addUnionStatement($tableName, $propertyName, $sql);
458
+				#}
459
+				#$columnName = $propertyName;
460
+				#$columnMap = $propertyName;
461
+				#$typeOfRelation = $columnMap instanceof ColumnMap ? $columnMap->getTypeOfRelation() : null;
462
+				#if ($typeOfRelation === ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY) {
463
+				#	$relationTableName = $columnMap->getRelationTableName();
464
+				#	$sql['where'][] = $tableName . '.uid IN (SELECT ' . $columnMap->getParentKeyFieldName() . ' FROM ' . $relationTableName . ' WHERE ' . $columnMap->getChildKeyFieldName() . '=?)';
465
+				#	$parameters[] = intval($this->getPlainValue($operand2));
466
+				#} elseif ($typeOfRelation === ColumnMap::RELATION_HAS_MANY) {
467
+				#	$parentKeyFieldName = $columnMap->getParentKeyFieldName();
468
+				#	if (isset($parentKeyFieldName)) {
469
+				#		$childTableName = $columnMap->getChildTableName();
470
+				#		$sql['where'][] = $tableName . '.uid=(SELECT ' . $childTableName . '.' . $parentKeyFieldName . ' FROM ' . $childTableName . ' WHERE ' . $childTableName . '.uid=?)';
471
+				#		$parameters[] = intval($this->getPlainValue($operand2));
472
+				#	} else {
473
+				#		$sql['where'][] = 'FIND_IN_SET(?,' . $tableName . '.' . $columnName . ')';
474
+				#		$parameters[] = intval($this->getPlainValue($operand2));
475
+				#	}
476
+				#} else {
477
+				#	throw new Exception\RepositoryException('Unsupported or non-existing property name "' . $propertyName . '" used in relation matching.', 1327065745);
478
+				#}
479
+			}
480
+		} else {
481
+			if ($operand2 === null) {
482
+				if ($operator === QueryInterface::OPERATOR_EQUAL_TO) {
483
+					$operator = self::OPERATOR_EQUAL_TO_NULL;
484
+				} elseif ($operator === QueryInterface::OPERATOR_NOT_EQUAL_TO) {
485
+					$operator = self::OPERATOR_NOT_EQUAL_TO_NULL;
486
+				}
487
+			}
488
+			$this->parseDynamicOperand($operand1, $operator, $source, $sql, $parameters);
489
+			$parameters[] = $this->getPlainValue($operand2);
490
+		}
491
+	}
492
+
493
+	/**
494
+	 * Returns a plain value, i.e. objects are flattened out if possible.
495
+	 *
496
+	 * @param mixed $input
497
+	 * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\UnexpectedTypeException
498
+	 * @return mixed
499
+	 */
500
+	protected function getPlainValue($input)
501
+	{
502
+		if (is_array($input)) {
503
+			throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\UnexpectedTypeException('An array could not be converted to a plain value.', 1274799932);
504
+		}
505
+		if ($input instanceof \DateTime) {
506
+			return $input->format('U');
507
+		} elseif (is_object($input)) {
508
+			if ($input instanceof \TYPO3\CMS\Extbase\Persistence\Generic\LazyLoadingProxy) {
509
+				$realInput = $input->_loadRealInstance();
510
+			} else {
511
+				$realInput = $input;
512
+			}
513
+			if ($realInput instanceof \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface) {
514
+				return $realInput->getUid();
515
+			} else {
516
+				throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\UnexpectedTypeException('An object of class "' . get_class($realInput) . '" could not be converted to a plain value.', 1274799934);
517
+			}
518
+		} elseif (is_bool($input)) {
519
+			return $input === true ? 1 : 0;
520
+		} else {
521
+			return $input;
522
+		}
523
+	}
524
+
525
+	/**
526
+	 * Parse a DynamicOperand into SQL and parameter arrays.
527
+	 *
528
+	 * @param DynamicOperandInterface $operand
529
+	 * @param string $operator One of the JCR_OPERATOR_* constants
530
+	 * @param SourceInterface $source The source
531
+	 * @param array &$sql The query parts
532
+	 * @param array &$parameters The parameters that will replace the markers
533
+	 * @param string $valueFunction an optional SQL function to apply to the operand value
534
+	 * @return void
535
+	 */
536
+	protected function parseDynamicOperand(DynamicOperandInterface $operand, $operator, SourceInterface $source, array &$sql, array &$parameters, $valueFunction = null)
537
+	{
538
+		if ($operand instanceof LowerCaseInterface) {
539
+			$this->parseDynamicOperand($operand->getOperand(), $operator, $source, $sql, $parameters, 'LOWER');
540
+		} elseif ($operand instanceof UpperCaseInterface) {
541
+			$this->parseDynamicOperand($operand->getOperand(), $operator, $source, $sql, $parameters, 'UPPER');
542
+		} elseif ($operand instanceof PropertyValueInterface) {
543
+			$propertyName = $operand->getPropertyName();
544
+
545
+			// Reset value.
546
+			$this->currentChildTableNameAlias = '';
547
+
548
+			if ($source instanceof SelectorInterface) {
549
+				$tableName = $this->query->getType();
550
+				while (strpos($propertyName, '.') !== false) {
551
+					$this->addUnionStatement($tableName, $propertyName, $sql);
552
+				}
553
+			} elseif ($source instanceof JoinInterface) {
554
+				$tableName = $source->getJoinCondition()->getSelector1Name();
555
+			}
556
+
557
+			$columnName = $propertyName;
558
+			$operator = $this->resolveOperator($operator);
559
+			$constraintSQL = '';
560
+			if ($valueFunction === null) {
561
+				$constraintSQL .= (!empty($tableName) ? $tableName . '.' : '') . $columnName . ' ' . $operator . ' ?';
562
+			} else {
563
+				$constraintSQL .= $valueFunction . '(' . (!empty($tableName) ? $tableName . '.' : '') . $columnName . ') ' . $operator . ' ?';
564
+			}
565
+
566
+			if (isset($tableName) && !empty($this->currentChildTableNameAlias)) {
567
+				$constraintSQL = $this->replaceTableNameByAlias($tableName, $this->currentChildTableNameAlias, $constraintSQL);
568
+			}
569
+			$sql['where'][] = $constraintSQL;
570
+		}
571
+	}
572
+
573
+	/**
574
+	 * @param string &$tableName
575
+	 * @param array &$propertyPath
576
+	 * @param array &$sql
577
+	 * @throws Exception
578
+	 * @throws Exception\InvalidRelationConfigurationException
579
+	 * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\MissingColumnMapException
580
+	 */
581
+	protected function addUnionStatement(&$tableName, &$propertyPath, array &$sql)
582
+	{
583
+
584
+		$table = Tca::table($tableName);
585
+
586
+		$explodedPropertyPath = explode('.', $propertyPath, 2);
587
+		$fieldName = $explodedPropertyPath[0];
588
+
589
+		// Field of type "group" are special because property path must contain the table name
590
+		// to determine the relation type. Example for sys_category, property path will look like "items.sys_file"
591
+		if ($table->field($fieldName)->isGroup()) {
592
+			$parts = explode('.', $propertyPath, 3);
593
+			$explodedPropertyPath[0] = $parts[0] . '.' . $parts[1];
594
+			$explodedPropertyPath[1] = $parts[2];
595
+			$fieldName = $explodedPropertyPath[0];
596
+		}
597
+
598
+		$parentKeyFieldName = $table->field($fieldName)->getForeignField();
599
+		$childTableName = $table->field($fieldName)->getForeignTable();
600
+
601
+		if ($childTableName === null) {
602
+			throw new Exception\InvalidRelationConfigurationException('The relation information for property "' . $fieldName . '" of class "' . $tableName . '" is missing.', 1353170925);
603
+		}
604
+
605
+		if ($table->field($fieldName)->hasOne()) { // includes relation "one-to-one" and "many-to-one"
606
+			// sometimes the opposite relation is not defined. We don't want to force this config for backward compatibility reasons.
607
+			// $parentKeyFieldName === null does the trick somehow. Before condition was if (isset($parentKeyFieldName))
608
+			if ($table->field($fieldName)->hasRelationManyToOne() || $parentKeyFieldName === null) {
609
+				$sql['unions'][$childTableName] = 'LEFT JOIN ' . $childTableName . ' ON ' . $tableName . '.' . $fieldName . '=' . $childTableName . '.uid';
610
+			} else {
611
+				$sql['unions'][$childTableName] = 'LEFT JOIN ' . $childTableName . ' ON ' . $tableName . '.uid=' . $childTableName . '.' . $parentKeyFieldName;
612
+			}
613
+		} elseif ($table->field($fieldName)->hasRelationManyToMany()) {
614
+			$relationTableName = $table->field($fieldName)->getManyToManyTable();
615
+
616
+			$parentKeyFieldName = $table->field($fieldName)->isOppositeRelation() ? 'uid_foreign' : 'uid_local';
617
+			$childKeyFieldName = !$table->field($fieldName)->isOppositeRelation() ? 'uid_foreign' : 'uid_local';
618
+
619
+			// MM table e.g sys_category_record_mm
620
+			$relationTableNameAlias = $this->generateAlias($relationTableName);
621
+			$join = sprintf(
622
+				'LEFT JOIN %s AS %s ON %s.uid=%s.%s', $relationTableName,
623
+				$relationTableNameAlias,
624
+				$tableName,
625
+				$relationTableNameAlias,
626
+				$parentKeyFieldName
627
+			);
628
+			$sql['unions'][$relationTableNameAlias] = $join;
629
+
630
+			// Foreign table e.g sys_category
631
+			$childTableNameAlias = $this->generateAlias($childTableName);
632
+			$this->currentChildTableNameAlias = $childTableNameAlias;
633
+			$join = sprintf(
634
+				'LEFT JOIN %s AS %s ON %s.%s=%s.uid',
635
+				$childTableName,
636
+				$childTableNameAlias,
637
+				$relationTableNameAlias,
638
+				$childKeyFieldName,
639
+				$childTableNameAlias
640
+			);
641
+			$sql['unions'][$childTableNameAlias] = $join;
642
+
643
+			// Find a possible table name for a MM condition.
644
+			$tableNameCondition = $table->field($fieldName)->getAdditionalTableNameCondition();
645
+			if ($tableNameCondition) {
646
+
647
+				// If we can find a source file name,  we can then retrieve more MM conditions from the TCA such as a field name.
648
+				$sourceFileName = $this->query->getSourceFieldName();
649
+				if (empty($sourceFileName)) {
650
+					$additionalMMConditions = array(
651
+						'tablenames' => $tableNameCondition,
652
+					);
653
+				} else {
654
+					$additionalMMConditions = Tca::table($tableNameCondition)->field($sourceFileName)->getAdditionalMMCondition();
655
+				}
656
+
657
+				foreach ($additionalMMConditions as $additionalFieldName => $additionalMMCondition) {
658
+					$additionalJoin = sprintf(' AND %s.%s = "%s"', $relationTableNameAlias, $additionalFieldName, $additionalMMCondition);
659
+					$sql['unions'][$relationTableNameAlias] .= $additionalJoin;
660
+
661
+					$additionalJoin = sprintf(' AND %s.%s = "%s"', $relationTableNameAlias, $additionalFieldName, $additionalMMCondition);
662
+					$sql['unions'][$childTableNameAlias] .= $additionalJoin;
663
+				}
664
+
665
+			}
666
+
667
+
668
+		} elseif ($table->field($fieldName)->hasMany()) { // includes relations "many-to-one" and "csv" relations
669
+			$childTableNameAlias = $this->generateAlias($childTableName);
670
+			$this->currentChildTableNameAlias = $childTableNameAlias;
671
+
672
+			if (isset($parentKeyFieldName)) {
673
+				$join = sprintf(
674
+					'LEFT JOIN %s AS %s ON %s.uid=%s.%s',
675
+					$childTableName,
676
+					$childTableNameAlias,
677
+					$tableName,
678
+					$childTableNameAlias,
679
+					$parentKeyFieldName
680
+				);
681
+				$sql['unions'][$childTableNameAlias] = $join;
682
+			} else {
683
+				$join = sprintf(
684
+					'LEFT JOIN %s AS %s ON (FIND_IN_SET(%s.uid, %s.%s))',
685
+					$childTableName,
686
+					$childTableNameAlias,
687
+					$childTableNameAlias,
688
+					$tableName,
689
+					$fieldName
690
+				);
691
+				$sql['unions'][$childTableNameAlias] = $join;
692
+			}
693
+		} else {
694
+			throw new Exception('Could not determine type of relation.', 1252502725);
695
+		}
696
+
697
+		// TODO check if there is another solution for this
698
+		$sql['keywords']['distinct'] = 'DISTINCT';
699
+		$propertyPath = $explodedPropertyPath[1];
700
+		$tableName = $childTableName;
701
+	}
702
+
703
+	/**
704
+	 * Returns the SQL operator for the given JCR operator type.
705
+	 *
706
+	 * @param string $operator One of the JCR_OPERATOR_* constants
707
+	 * @throws Exception
708
+	 * @return string an SQL operator
709
+	 */
710
+	protected function resolveOperator($operator)
711
+	{
712
+		switch ($operator) {
713
+			case self::OPERATOR_EQUAL_TO_NULL:
714
+				$operator = 'IS';
715
+				break;
716
+			case self::OPERATOR_NOT_EQUAL_TO_NULL:
717
+				$operator = 'IS NOT';
718
+				break;
719
+			case QueryInterface::OPERATOR_IN:
720
+				$operator = 'IN';
721
+				break;
722
+			case QueryInterface::OPERATOR_EQUAL_TO:
723
+				$operator = '=';
724
+				break;
725
+			case QueryInterface::OPERATOR_NOT_EQUAL_TO:
726
+				$operator = '!=';
727
+				break;
728
+			case QueryInterface::OPERATOR_LESS_THAN:
729
+				$operator = '<';
730
+				break;
731
+			case QueryInterface::OPERATOR_LESS_THAN_OR_EQUAL_TO:
732
+				$operator = '<=';
733
+				break;
734
+			case QueryInterface::OPERATOR_GREATER_THAN:
735
+				$operator = '>';
736
+				break;
737
+			case QueryInterface::OPERATOR_GREATER_THAN_OR_EQUAL_TO:
738
+				$operator = '>=';
739
+				break;
740
+			case QueryInterface::OPERATOR_LIKE:
741
+				$operator = 'LIKE';
742
+				break;
743
+			default:
744
+				throw new Exception('Unsupported operator encountered.', 1242816073);
745
+		}
746
+		return $operator;
747
+	}
748
+
749
+	/**
750
+	 * Replace query placeholders in a query part by the given
751
+	 * parameters.
752
+	 *
753
+	 * @param string &$sqlString The query part with placeholders
754
+	 * @param array $parameters The parameters
755
+	 * @param string $tableName
756
+	 *
757
+	 * @throws Exception
758
+	 */
759
+	protected function replacePlaceholders(&$sqlString, array $parameters, $tableName = 'foo')
760
+	{
761
+		// TODO profile this method again
762
+		if (substr_count($sqlString, '?') !== count($parameters)) {
763
+			throw new Exception('The number of question marks to replace must be equal to the number of parameters.', 1242816074);
764
+		}
765
+		$offset = 0;
766
+		foreach ($parameters as $parameter) {
767
+			$markPosition = strpos($sqlString, '?', $offset);
768
+			if ($markPosition !== false) {
769
+				if ($parameter === null) {
770
+					$parameter = 'null';
771
+				} elseif (is_array($parameter) || $parameter instanceof \ArrayAccess || $parameter instanceof \Traversable) {
772
+					$items = [];
773
+					foreach ($parameter as $item) {
774
+						$items[] = $this->databaseHandle->fullQuoteStr($item, $tableName);
775
+					}
776
+					$parameter = '(' . implode(',', $items) . ')';
777
+				} else {
778
+					$parameter = $this->databaseHandle->fullQuoteStr($parameter, $tableName);
779
+				}
780
+				$sqlString = substr($sqlString, 0, $markPosition) . $parameter . substr($sqlString, ($markPosition + 1));
781
+			}
782
+			$offset = $markPosition + strlen($parameter);
783
+		}
784
+	}
785
+
786
+	/**
787
+	 * Adds additional WHERE statements according to the query settings.
788
+	 *
789
+	 * @param QuerySettingsInterface $querySettings The TYPO3 CMS specific query settings
790
+	 * @param string $tableNameOrAlias The table name to add the additional where clause for
791
+	 * @param array &$statementParts
792
+	 * @return void
793
+	 */
794
+	protected function addAdditionalWhereClause(QuerySettingsInterface $querySettings, $tableNameOrAlias, &$statementParts)
795
+	{
796
+		$this->addVisibilityConstraintStatement($querySettings, $tableNameOrAlias, $statementParts);
797
+		if ($querySettings->getRespectSysLanguage()) {
798
+			$this->addSysLanguageStatement($tableNameOrAlias, $statementParts, $querySettings);
799
+		}
800
+	}
801
+
802
+	/**
803
+	 * Adds enableFields and deletedClause to the query if necessary
804
+	 *
805
+	 * @param QuerySettingsInterface $querySettings
806
+	 * @param string $tableNameOrAlias The database table name
807
+	 * @param array &$statementParts The query parts
808
+	 * @return void
809
+	 */
810
+	protected function addVisibilityConstraintStatement(QuerySettingsInterface $querySettings, $tableNameOrAlias, array &$statementParts)
811
+	{
812
+		$statement = '';
813
+		$tableName = $this->resolveTableNameAlias($tableNameOrAlias);
814
+		if (is_array($GLOBALS['TCA'][$tableName]['ctrl'])) {
815
+			$ignoreEnableFields = $querySettings->getIgnoreEnableFields();
816
+			$enableFieldsToBeIgnored = $querySettings->getEnableFieldsToBeIgnored();
817
+			$includeDeleted = $querySettings->getIncludeDeleted();
818
+			if ($this->environmentService->isEnvironmentInFrontendMode()) {
819
+				$statement .= $this->getFrontendConstraintStatement($tableNameOrAlias, $ignoreEnableFields, $enableFieldsToBeIgnored, $includeDeleted);
820
+			} else {
821
+				// TYPO3_MODE === 'BE'
822
+				$statement .= $this->getBackendConstraintStatement($tableNameOrAlias, $ignoreEnableFields, $includeDeleted);
823
+			}
824
+
825
+			// Remove the prefixing "AND" if any.
826
+			if (!empty($statement)) {
827
+				$statement = strtolower(substr($statement, 1, 3)) === 'and' ? substr($statement, 5) : $statement;
828
+				$statementParts['additionalWhereClause'][$tableNameOrAlias][] = $statement;
829
+			}
830
+		}
831
+	}
832
+
833
+	/**
834
+	 * Returns constraint statement for frontend context
835
+	 *
836
+	 * @param string $tableNameOrAlias
837
+	 * @param boolean $ignoreEnableFields A flag indicating whether the enable fields should be ignored
838
+	 * @param array $enableFieldsToBeIgnored If $ignoreEnableFields is true, this array specifies enable fields to be ignored. If it is null or an empty array (default) all enable fields are ignored.
839
+	 * @param boolean $includeDeleted A flag indicating whether deleted records should be included
840
+	 * @return string
841
+	 * @throws Exception\InconsistentQuerySettingsException
842
+	 */
843
+	protected function getFrontendConstraintStatement($tableNameOrAlias, $ignoreEnableFields, $enableFieldsToBeIgnored = [], $includeDeleted)
844
+	{
845
+		$statement = '';
846
+		$tableName = $this->resolveTableNameAlias($tableNameOrAlias);
847
+		if ($ignoreEnableFields && !$includeDeleted) {
848
+			if (count($enableFieldsToBeIgnored)) {
849
+				// array_combine() is necessary because of the way \TYPO3\CMS\Frontend\Page\PageRepository::enableFields() is implemented
850
+				$statement .= $this->getPageRepository()->enableFields($tableName, -1, array_combine($enableFieldsToBeIgnored, $enableFieldsToBeIgnored));
851
+			} else {
852
+				$statement .= $this->getPageRepository()->deleteClause($tableName);
853
+			}
854
+		} elseif (!$ignoreEnableFields && !$includeDeleted) {
855
+			$statement .= $this->getPageRepository()->enableFields($tableName);
856
+		} elseif (!$ignoreEnableFields && $includeDeleted) {
857
+			throw new Exception\InconsistentQuerySettingsException('Query setting "ignoreEnableFields=false" can not be used together with "includeDeleted=true" in frontend context.', 1327678173);
858
+		}
859
+		return $this->replaceTableNameByAlias($tableName, $tableNameOrAlias, $statement);
860
+	}
861
+
862
+	/**
863
+	 * Returns constraint statement for backend context
864
+	 *
865
+	 * @param string $tableNameOrAlias
866
+	 * @param boolean $ignoreEnableFields A flag indicating whether the enable fields should be ignored
867
+	 * @param boolean $includeDeleted A flag indicating whether deleted records should be included
868
+	 * @return string
869
+	 */
870
+	protected function getBackendConstraintStatement($tableNameOrAlias, $ignoreEnableFields, $includeDeleted)
871
+	{
872
+		$tableName = $this->resolveTableNameAlias($tableNameOrAlias);
873
+		$statement = '';
874
+		if (!$ignoreEnableFields) {
875
+			$statement .= BackendUtility::BEenableFields($tableName);
876
+		}
877
+
878
+		// If the table is found to have "workspace" support, add the corresponding fields in the statement.
879
+		if (Tca::table($tableName)->hasWorkspaceSupport()) {
880
+			if ($this->getBackendUser()->workspace === 0) {
881
+				$statement .= ' AND ' . $tableName . '.t3ver_state<=' . new VersionState(VersionState::DEFAULT_STATE);
882
+			} else {
883
+				// Show only records of live and of the current workspace
884
+				// In case we are in a Versioning preview
885
+				$statement .= ' AND (' .
886
+					$tableName . '.t3ver_wsid=0 OR ' .
887
+					$tableName . '.t3ver_wsid=' . (int)$this->getBackendUser()->workspace .
888
+					')';
889
+			}
890
+
891
+			// Check if this segment make sense here or whether it should be in the "if" part when we have workspace = 0
892
+			$statement .= ' AND ' . $tableName . '.pid<>-1';
893
+		}
894
+
895
+		if (!$includeDeleted) {
896
+			$statement .= BackendUtility::deleteClause($tableName);
897
+		}
898
+
899
+		return $this->replaceTableNameByAlias($tableName, $tableNameOrAlias, $statement);
900
+	}
901
+
902
+	/**
903
+	 * Builds the language field statement
904
+	 *
905
+	 * @param string $tableNameOrAlias The database table name
906
+	 * @param array &$statementParts The query parts
907
+	 * @param QuerySettingsInterface $querySettings The TYPO3 CMS specific query settings
908
+	 * @throws Exception
909
+	 * @return void
910
+	 */
911
+	protected function addSysLanguageStatement($tableNameOrAlias, array &$statementParts, $querySettings)
912
+	{
913
+
914
+		$tableName = $this->resolveTableNameAlias($tableNameOrAlias);
915
+		if (is_array($GLOBALS['TCA'][$tableName]['ctrl'])) {
916
+			if (!empty($GLOBALS['TCA'][$tableName]['ctrl']['languageField'])) {
917
+				// Select all entries for the current language
918
+				$additionalWhereClause = $tableNameOrAlias . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] . ' IN (' . intval($querySettings->getLanguageUid()) . ',-1)';
919
+				// If any language is set -> get those entries which are not translated yet
920
+				// They will be removed by t3lib_page::getRecordOverlay if not matching overlay mode
921
+				if (isset($GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'])
922
+					&& $querySettings->getLanguageUid() > 0
923
+				) {
924
+					$additionalWhereClause .= ' OR (' . $tableNameOrAlias . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] . '=0' .
925
+						' AND ' . $tableNameOrAlias . '.uid NOT IN (SELECT ' . $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'] .
926
+						' FROM ' . $tableName .
927
+						' WHERE ' . $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'] . '>0' .
928
+						' AND ' . $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] . '>0';
929
+
930
+					// Add delete clause to ensure all entries are loaded
931
+					if (isset($GLOBALS['TCA'][$tableName]['ctrl']['delete'])) {
932
+						$additionalWhereClause .= ' AND ' . $tableNameOrAlias . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['delete'] . '=0';
933
+					}
934
+					$additionalWhereClause .= '))';
935
+				}
936
+				$statementParts['additionalWhereClause'][$tableNameOrAlias][] = '(' . $additionalWhereClause . ')';
937
+			}
938
+		}
939
+	}
940
+
941
+	/**
942
+	 * Transforms orderings into SQL.
943
+	 *
944
+	 * @param array $orderings An array of orderings (Tx_Extbase_Persistence_QOM_Ordering)
945
+	 * @param SourceInterface $source The source
946
+	 * @param array &$sql The query parts
947
+	 * @throws Exception\UnsupportedOrderException
948
+	 * @return void
949
+	 */
950
+	protected function parseOrderings(array $orderings, SourceInterface $source, array &$sql)
951
+	{
952
+		foreach ($orderings as $fieldNameAndPath => $order) {
953
+			switch ($order) {
954
+				case QueryInterface::ORDER_ASCENDING:
955
+					$order = 'ASC';
956
+					break;
957
+				case QueryInterface::ORDER_DESCENDING:
958
+					$order = 'DESC';
959
+					break;
960
+				default:
961
+					throw new Exception\UnsupportedOrderException('Unsupported order encountered.', 1456845126);
962
+			}
963
+
964
+			$tableName = $this->getFieldPathResolver()->getDataType($fieldNameAndPath, $this->query->getType());
965
+			$fieldName = $this->getFieldPathResolver()->stripFieldPath($fieldNameAndPath, $tableName);
966
+			$sql['orderings'][] = sprintf('%s.%s %s', $tableName, $fieldName, $order);
967
+		}
968
+	}
969
+
970
+	/**
971
+	 * Transforms limit and offset into SQL
972
+	 *
973
+	 * @param int $limit
974
+	 * @param int $offset
975
+	 * @param array &$sql
976
+	 * @return void
977
+	 */
978
+	protected function parseLimitAndOffset($limit, $offset, array &$sql)
979
+	{
980
+		if ($limit !== null && $offset !== null) {
981
+			$sql['limit'] = intval($offset) . ', ' . intval($limit);
982
+		} elseif ($limit !== null) {
983
+			$sql['limit'] = intval($limit);
984
+		}
985
+	}
986
+
987
+	/**
988
+	 * Transforms a Resource from a database query to an array of rows.
989
+	 *
990
+	 * @param resource $result The result
991
+	 * @return array The result as an array of rows (tuples)
992
+	 */
993
+	protected function getRowsFromResult($result)
994
+	{
995
+		$rows = [];
996
+		while ($row = $this->databaseHandle->sql_fetch_assoc($result)) {
997
+			if (is_array($row)) {
998
+
999
+				// Get language uid from querySettings.
1000
+				// Ensure the backend handling is not broken (fallback to Get parameter 'L' if needed)
1001
+				$overlaidRow = $this->doLanguageAndWorkspaceOverlay($this->query->getSource(), $row, $this->query->getQuerySettings());
1002
+				$contentObject = GeneralUtility::makeInstance($this->objectType, $this->query->getType(), $overlaidRow);
1003
+				$rows[] = $contentObject;
1004
+			}
1005
+		}
1006
+
1007
+		return $rows;
1008
+	}
1009
+
1010
+	/**
1011
+	 * Performs workspace and language overlay on the given row array. The language and workspace id is automatically
1012
+	 * detected (depending on FE or BE context). You can also explicitly set the language/workspace id.
1013
+	 *
1014
+	 * @param SourceInterface $source The source (selector od join)
1015
+	 * @param array $row
1016
+	 * @param QuerySettingsInterface $querySettings The TYPO3 CMS specific query settings
1017
+	 * @return array
1018
+	 */
1019
+	protected function doLanguageAndWorkspaceOverlay(SourceInterface $source, array $row, $querySettings)
1020
+	{
1021
+
1022
+		/** @var SelectorInterface $source */
1023
+		$tableName = $source->getSelectorName();
1024
+
1025
+		$pageRepository = $this->getPageRepository();
1026
+		if (is_object($GLOBALS['TSFE'])) {
1027
+			$languageMode = $GLOBALS['TSFE']->sys_language_mode;
1028
+			if ($this->isBackendUserLogged() && $this->getBackendUser()->workspace !== 0) {
1029
+				$pageRepository->versioningWorkspaceId = $this->getBackendUser()->workspace;
1030
+			}
1031
+		} else {
1032
+			$languageMode = '';
1033
+			$workspaceUid = $this->getBackendUser()->workspace;
1034
+			$pageRepository->versioningWorkspaceId = $workspaceUid;
1035
+			if ($this->getBackendUser()->workspace !== 0) {
1036
+				$pageRepository->versioningPreview = 1;
1037
+			}
1038
+		}
1039
+
1040
+		// If current row is a translation select its parent
1041
+		if (isset($GLOBALS['TCA'][$tableName]['ctrl']['languageField'])
1042
+			&& isset($GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'])
1043
+		) {
1044
+			if (isset($row[$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']])
1045
+				&& $row[$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']] > 0
1046
+			) {
1047
+				$row = $this->databaseHandle->exec_SELECTgetSingleRow(
1048
+					$tableName . '.*',
1049
+					$tableName,
1050
+					$tableName . '.uid=' . (int)$row[$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']] .
1051
+					' AND ' . $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] . '=0'
1052
+				);
1053
+			}
1054
+		}
1055
+
1056
+		// Retrieve the original uid; Used for Workspaces!
1057
+		if (TYPO3_MODE !== 'BE') {
1058
+			$pageRepository->versionOL($tableName, $row, true, true);
1059
+		} else {
1060
+			BackendUtility::workspaceOL($tableName, $row);
1061
+		}
1062
+		if ($pageRepository->versioningPreview && isset($row['_ORIG_uid'])) {
1063
+			$row['uid'] = $row['_ORIG_uid'];
1064
+		}
1065
+
1066
+		// Special case for table "pages"
1067
+		if ($tableName == 'pages') {
1068
+			$row = $pageRepository->getPageOverlay($row, $querySettings->getLanguageUid());
1069
+		} elseif (isset($GLOBALS['TCA'][$tableName]['ctrl']['languageField'])
1070
+			&& $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] !== ''
1071
+		) {
1072
+			if (in_array($row[$GLOBALS['TCA'][$tableName]['ctrl']['languageField']], array(-1, 0))) {
1073
+				$overlayMode = $languageMode === 'strict' ? 'hideNonTranslated' : '';
1074
+				$row = $pageRepository->getRecordOverlay($tableName, $row, $querySettings->getLanguageUid(), $overlayMode);
1075
+			}
1076
+		}
1077
+
1078
+		return $row;
1079
+	}
1080
+
1081
+	/**
1082
+	 * Return a resolved table name given a possible table name alias.
1083
+	 *
1084
+	 * @param string $tableNameOrAlias
1085
+	 * @return string
1086
+	 */
1087
+	protected function resolveTableNameAlias($tableNameOrAlias)
1088
+	{
1089
+		$resolvedTableName = $tableNameOrAlias;
1090
+		if (!empty($this->tableNameAliases['aliases'][$tableNameOrAlias])) {
1091
+			$resolvedTableName = $this->tableNameAliases['aliases'][$tableNameOrAlias];
1092
+		}
1093
+		return $resolvedTableName;
1094
+	}
1095
+
1096
+	/**
1097
+	 * Generate a unique table name alias for the given table name.
1098
+	 *
1099
+	 * @param string $tableName
1100
+	 * @return string
1101
+	 */
1102
+	protected function generateAlias($tableName)
1103
+	{
1104
+
1105
+		if (!isset($this->tableNameAliases['aliasIncrement'][$tableName])) {
1106
+			$this->tableNameAliases['aliasIncrement'][$tableName] = 0;
1107
+		}
1108
+
1109
+		$numberOfAliases = $this->tableNameAliases['aliasIncrement'][$tableName];
1110
+		$tableNameAlias = $tableName . $numberOfAliases;
1111
+
1112
+		$this->tableNameAliases['aliasIncrement'][$tableName]++;
1113
+		$this->tableNameAliases['aliases'][$tableNameAlias] = $tableName;
1114
+
1115
+		return $tableNameAlias;
1116
+	}
1117
+
1118
+	/**
1119
+	 * Replace the table names by its table name alias within the given statement.
1120
+	 *
1121
+	 * @param string $tableName
1122
+	 * @param string $tableNameAlias
1123
+	 * @param string $statement
1124
+	 * @return string
1125
+	 */
1126
+	protected function replaceTableNameByAlias($tableName, $tableNameAlias, $statement)
1127
+	{
1128
+		if ($statement && $tableName !== $tableNameAlias) {
1129
+			$statement = str_replace($tableName, $tableNameAlias, $statement);
1130
+		}
1131
+		return $statement;
1132
+	}
1133
+
1134
+	/**
1135
+	 * Returns an instance of the current Backend User.
1136
+	 *
1137
+	 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
1138
+	 */
1139
+	protected function getBackendUser()
1140
+	{
1141
+		return $GLOBALS['BE_USER'];
1142
+	}
1143
+
1144
+	/**
1145
+	 * Tell whether a Backend User is logged in.
1146
+	 *
1147
+	 * @return bool
1148
+	 */
1149
+	protected function isBackendUserLogged()
1150
+	{
1151
+		return is_object($GLOBALS['BE_USER']);
1152
+	}
1153
+
1154
+	/**
1155
+	 * @return PageRepository
1156
+	 */
1157
+	protected function getPageRepository()
1158
+	{
1159
+		if (!$this->pageRepository instanceof PageRepository) {
1160
+			if ($this->environmentService->isEnvironmentInFrontendMode() && is_object($GLOBALS['TSFE'])) {
1161
+				$this->pageRepository = $GLOBALS['TSFE']->sys_page;
1162
+			} else {
1163
+				$this->pageRepository = GeneralUtility::makeInstance('TYPO3\\CMS\\Frontend\\Page\\PageRepository');
1164
+			}
1165
+		}
1166
+
1167
+		return $this->pageRepository;
1168
+	}
1169
+
1170
+	/**
1171
+	 * @return \Fab\Vidi\Resolver\FieldPathResolver
1172
+	 */
1173
+	protected function getFieldPathResolver()
1174
+	{
1175
+		return GeneralUtility::makeInstance('Fab\Vidi\Resolver\FieldPathResolver');
1176
+	}
1177
+
1178
+	/**
1179
+	 * Checks if there are SQL errors in the last query, and if yes, throw an exception.
1180
+	 *
1181
+	 * @return void
1182
+	 * @param string $sql The SQL statement
1183
+	 * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Storage\Exception\SqlErrorException
1184
+	 */
1185
+	protected function checkSqlErrors($sql = '')
1186
+	{
1187
+		$error = $this->databaseHandle->sql_error();
1188
+		if ($error !== '') {
1189
+			$error .= $sql ? ': ' . $sql : '';
1190
+			throw new \TYPO3\CMS\Extbase\Persistence\Generic\Storage\Exception\SqlErrorException($error, 1247602160);
1191
+		}
1192
+	}
1193 1193
 }
Please login to merge, or discard this patch.
Classes/Processor/ContentObjectProcessor.php 3 patches
Doc Comments   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -30,7 +30,7 @@  discard block
 block discarded – undo
30 30
 
31 31
     /**
32 32
      * @param ProcessContentDataSignalArguments $signalArguments
33
-     * @return array
33
+     * @return ProcessContentDataSignalArguments[]
34 34
      */
35 35
     public function processRelations(ProcessContentDataSignalArguments $signalArguments)
36 36
     {
@@ -50,7 +50,7 @@  discard block
 block discarded – undo
50 50
 
51 51
     /**
52 52
      * @param \Fab\Vidi\Domain\Model\Content $object
53
-     * @param $fieldNameAndPath
53
+     * @param string $fieldNameAndPath
54 54
      * @param array $contentData
55 55
      * @param string $savingBehavior
56 56
      * @return array
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -71,7 +71,7 @@
 block discarded – undo
71 71
                 $relatedValues = $this->getRelatedValues($object, $fieldNameAndPath, $fieldName);
72 72
 
73 73
                 foreach ($values as $value) {
74
-                    $appendOrRemove = $savingBehavior . 'Relations';
74
+                    $appendOrRemove = $savingBehavior.'Relations';
75 75
                     $relatedValues = $this->$appendOrRemove($value, $relatedValues);
76 76
                 }
77 77
 
Please login to merge, or discard this patch.
Indentation   +117 added lines, -117 removed lines patch added patch discarded remove patch
@@ -22,121 +22,121 @@
 block discarded – undo
22 22
 class ContentObjectProcessor implements SingletonInterface
23 23
 {
24 24
 
25
-    /**
26
-     * @param ProcessContentDataSignalArguments $signalArguments
27
-     * @return array
28
-     */
29
-    public function processRelations(ProcessContentDataSignalArguments $signalArguments)
30
-    {
31
-
32
-        $contentObject = $signalArguments->getContentObject();
33
-        $fieldNameAndPath = $signalArguments->getFieldNameAndPath();
34
-        $contentData = $signalArguments->getContentData();
35
-        $savingBehavior = $signalArguments->getSavingBehavior();
36
-
37
-        if ($savingBehavior !== SavingBehavior::REPLACE) {
38
-            $contentData = $this->appendOrRemoveRelations($contentObject, $fieldNameAndPath, $contentData, $savingBehavior);
39
-            $signalArguments->setContentData($contentData);
40
-        }
41
-
42
-        return array($signalArguments);
43
-    }
44
-
45
-    /**
46
-     * @param \Fab\Vidi\Domain\Model\Content $object
47
-     * @param $fieldNameAndPath
48
-     * @param array $contentData
49
-     * @param string $savingBehavior
50
-     * @return array
51
-     */
52
-    protected function appendOrRemoveRelations(Content $object, $fieldNameAndPath, array $contentData, $savingBehavior)
53
-    {
54
-
55
-        foreach ($contentData as $fieldName => $values) {
56
-
57
-            $resolvedObject = $this->getContentObjectResolver()->getObject($object, $fieldNameAndPath);
58
-
59
-            if (Tca::table($resolvedObject)->field($fieldName)->hasMany()) {
60
-
61
-                // true means CSV values must be converted to array.
62
-                if (!is_array($values)) {
63
-                    $values = GeneralUtility::trimExplode(',', $values);
64
-                }
65
-                $relatedValues = $this->getRelatedValues($object, $fieldNameAndPath, $fieldName);
66
-
67
-                foreach ($values as $value) {
68
-                    $appendOrRemove = $savingBehavior . 'Relations';
69
-                    $relatedValues = $this->$appendOrRemove($value, $relatedValues);
70
-                }
71
-
72
-                $contentData[$fieldName] = $relatedValues;
73
-            }
74
-        }
75
-        return $contentData;
76
-    }
77
-
78
-    /**
79
-     * @param $value
80
-     * @param array $relatedValues
81
-     * @return array
82
-     */
83
-    protected function appendRelations($value, array $relatedValues)
84
-    {
85
-        if (!in_array($value, $relatedValues)) {
86
-            $relatedValues[] = $value;
87
-        }
88
-        return $relatedValues;
89
-    }
90
-
91
-    /**
92
-     * @param $value
93
-     * @param array $relatedValues
94
-     * @return array
95
-     */
96
-    protected function removeRelations($value, array $relatedValues)
97
-    {
98
-        if (in_array($value, $relatedValues)) {
99
-            $key = array_search($value, $relatedValues);
100
-            unset($relatedValues[$key]);
101
-        }
102
-        return $relatedValues;
103
-    }
104
-
105
-    /**
106
-     * @param \Fab\Vidi\Domain\Model\Content $object
107
-     * @param string $fieldNameAndPath
108
-     * @param string $fieldName
109
-     * @return array
110
-     */
111
-    protected function getRelatedValues(Content $object, $fieldNameAndPath, $fieldName)
112
-    {
113
-
114
-        $values = [];
115
-        $relatedContentObjects = $this->getContentObjectResolver()->getValue($object, $fieldNameAndPath, $fieldName);
116
-
117
-        if (is_array($relatedContentObjects)) {
118
-            /** @var Content $relatedContentObject */
119
-            foreach ($relatedContentObjects as $relatedContentObject) {
120
-                $values[] = $relatedContentObject->getUid();
121
-            }
122
-        }
123
-
124
-        return $values;
125
-    }
126
-
127
-    /**
128
-     * @return \Fab\Vidi\Resolver\ContentObjectResolver
129
-     */
130
-    protected function getContentObjectResolver()
131
-    {
132
-        return GeneralUtility::makeInstance('Fab\Vidi\Resolver\ContentObjectResolver');
133
-    }
134
-
135
-    /**
136
-     * @return \Fab\Vidi\Resolver\FieldPathResolver
137
-     */
138
-    protected function getFieldPathResolver()
139
-    {
140
-        return GeneralUtility::makeInstance('Fab\Vidi\Resolver\FieldPathResolver');
141
-    }
25
+	/**
26
+	 * @param ProcessContentDataSignalArguments $signalArguments
27
+	 * @return array
28
+	 */
29
+	public function processRelations(ProcessContentDataSignalArguments $signalArguments)
30
+	{
31
+
32
+		$contentObject = $signalArguments->getContentObject();
33
+		$fieldNameAndPath = $signalArguments->getFieldNameAndPath();
34
+		$contentData = $signalArguments->getContentData();
35
+		$savingBehavior = $signalArguments->getSavingBehavior();
36
+
37
+		if ($savingBehavior !== SavingBehavior::REPLACE) {
38
+			$contentData = $this->appendOrRemoveRelations($contentObject, $fieldNameAndPath, $contentData, $savingBehavior);
39
+			$signalArguments->setContentData($contentData);
40
+		}
41
+
42
+		return array($signalArguments);
43
+	}
44
+
45
+	/**
46
+	 * @param \Fab\Vidi\Domain\Model\Content $object
47
+	 * @param $fieldNameAndPath
48
+	 * @param array $contentData
49
+	 * @param string $savingBehavior
50
+	 * @return array
51
+	 */
52
+	protected function appendOrRemoveRelations(Content $object, $fieldNameAndPath, array $contentData, $savingBehavior)
53
+	{
54
+
55
+		foreach ($contentData as $fieldName => $values) {
56
+
57
+			$resolvedObject = $this->getContentObjectResolver()->getObject($object, $fieldNameAndPath);
58
+
59
+			if (Tca::table($resolvedObject)->field($fieldName)->hasMany()) {
60
+
61
+				// true means CSV values must be converted to array.
62
+				if (!is_array($values)) {
63
+					$values = GeneralUtility::trimExplode(',', $values);
64
+				}
65
+				$relatedValues = $this->getRelatedValues($object, $fieldNameAndPath, $fieldName);
66
+
67
+				foreach ($values as $value) {
68
+					$appendOrRemove = $savingBehavior . 'Relations';
69
+					$relatedValues = $this->$appendOrRemove($value, $relatedValues);
70
+				}
71
+
72
+				$contentData[$fieldName] = $relatedValues;
73
+			}
74
+		}
75
+		return $contentData;
76
+	}
77
+
78
+	/**
79
+	 * @param $value
80
+	 * @param array $relatedValues
81
+	 * @return array
82
+	 */
83
+	protected function appendRelations($value, array $relatedValues)
84
+	{
85
+		if (!in_array($value, $relatedValues)) {
86
+			$relatedValues[] = $value;
87
+		}
88
+		return $relatedValues;
89
+	}
90
+
91
+	/**
92
+	 * @param $value
93
+	 * @param array $relatedValues
94
+	 * @return array
95
+	 */
96
+	protected function removeRelations($value, array $relatedValues)
97
+	{
98
+		if (in_array($value, $relatedValues)) {
99
+			$key = array_search($value, $relatedValues);
100
+			unset($relatedValues[$key]);
101
+		}
102
+		return $relatedValues;
103
+	}
104
+
105
+	/**
106
+	 * @param \Fab\Vidi\Domain\Model\Content $object
107
+	 * @param string $fieldNameAndPath
108
+	 * @param string $fieldName
109
+	 * @return array
110
+	 */
111
+	protected function getRelatedValues(Content $object, $fieldNameAndPath, $fieldName)
112
+	{
113
+
114
+		$values = [];
115
+		$relatedContentObjects = $this->getContentObjectResolver()->getValue($object, $fieldNameAndPath, $fieldName);
116
+
117
+		if (is_array($relatedContentObjects)) {
118
+			/** @var Content $relatedContentObject */
119
+			foreach ($relatedContentObjects as $relatedContentObject) {
120
+				$values[] = $relatedContentObject->getUid();
121
+			}
122
+		}
123
+
124
+		return $values;
125
+	}
126
+
127
+	/**
128
+	 * @return \Fab\Vidi\Resolver\ContentObjectResolver
129
+	 */
130
+	protected function getContentObjectResolver()
131
+	{
132
+		return GeneralUtility::makeInstance('Fab\Vidi\Resolver\ContentObjectResolver');
133
+	}
134
+
135
+	/**
136
+	 * @return \Fab\Vidi\Resolver\FieldPathResolver
137
+	 */
138
+	protected function getFieldPathResolver()
139
+	{
140
+		return GeneralUtility::makeInstance('Fab\Vidi\Resolver\FieldPathResolver');
141
+	}
142 142
 }
Please login to merge, or discard this patch.
Classes/Processor/MarkerProcessor.php 3 patches
Doc Comments   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -37,7 +37,7 @@  discard block
 block discarded – undo
37 37
 
38 38
     /**
39 39
      * @param ProcessContentDataSignalArguments $signalArguments
40
-     * @return array
40
+     * @return ProcessContentDataSignalArguments[]
41 41
      */
42 42
     public function processMarkers(ProcessContentDataSignalArguments $signalArguments)
43 43
     {
@@ -72,7 +72,7 @@  discard block
 block discarded – undo
72 72
      * @param string $updateValue
73 73
      * @param string $currentValue
74 74
      * @param int $counter
75
-     * @param $creationTime
75
+     * @param integer $creationTime
76 76
      * @return string
77 77
      */
78 78
     protected function replaceWellKnownMarkers($updateValue, $currentValue, $counter, $creationTime)
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -105,7 +105,7 @@
 block discarded – undo
105 105
             $replace = $structure[2];
106 106
 
107 107
             // Perhaps needs to be improved here if $search contains "/" precisely.
108
-            $updateValue = preg_replace('/' . $search . '/isU', $replace, $currentValue);
108
+            $updateValue = preg_replace('/'.$search.'/isU', $replace, $currentValue);
109 109
         }
110 110
         return $updateValue;
111 111
     }
Please login to merge, or discard this patch.
Indentation   +109 added lines, -109 removed lines patch added patch discarded remove patch
@@ -20,114 +20,114 @@
 block discarded – undo
20 20
 class MarkerProcessor implements SingletonInterface
21 21
 {
22 22
 
23
-    /**
24
-     * @var array
25
-     */
26
-    protected $wellKnownMarkers = array(
27
-        '{*}',
28
-        '{counter}',
29
-        '{date}',
30
-        '{creation_date}'
31
-    );
32
-
33
-    /**
34
-     * @param ProcessContentDataSignalArguments $signalArguments
35
-     * @return array
36
-     */
37
-    public function processMarkers(ProcessContentDataSignalArguments $signalArguments)
38
-    {
39
-
40
-        $contentData = $signalArguments->getContentData();
41
-        $creationTime = $this->getCreationTime($signalArguments);
42
-
43
-        // Process markers
44
-        foreach ($signalArguments->getContentData() as $fieldName => $updateValue) {
45
-            if (is_scalar($updateValue)) {
46
-
47
-                $currentValue = $this->getContentObjectResolver()->getValue(
48
-                    $signalArguments->getContentObject(),
49
-                    $signalArguments->getFieldNameAndPath(),
50
-                    $fieldName,
51
-                    $signalArguments->getLanguage()
52
-                );
53
-                $counter = $signalArguments->getCounter();
54
-
55
-                $updateValue = $this->searchAndReplace($updateValue, $currentValue);
56
-                $updateValue = $this->replaceWellKnownMarkers($updateValue, $currentValue, $counter, $creationTime);
57
-
58
-                $contentData[$fieldName] = $updateValue;
59
-            }
60
-        }
61
-
62
-        $signalArguments->setContentData($contentData);
63
-        return array($signalArguments);
64
-    }
65
-
66
-    /**
67
-     * @param string $updateValue
68
-     * @param string $currentValue
69
-     * @param int $counter
70
-     * @param $creationTime
71
-     * @return string
72
-     */
73
-    protected function replaceWellKnownMarkers($updateValue, $currentValue, $counter, $creationTime)
74
-    {
75
-
76
-        // Replaces values.
77
-        $replaces = array(
78
-            $currentValue,
79
-            $counter,
80
-            date($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy']),
81
-            date($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'], $creationTime),
82
-        );
83
-
84
-        // Replace me!
85
-        return str_replace($this->wellKnownMarkers, $replaces, $updateValue);
86
-    }
87
-
88
-    /**
89
-     * @param string $updateValue
90
-     * @param string $currentValue
91
-     * @return string
92
-     */
93
-    protected function searchAndReplace($updateValue, $currentValue)
94
-    {
95
-
96
-        if (strpos($updateValue, 's/') !== false) {
97
-            $structure = explode('/', $updateValue);
98
-            $search = $structure[1];
99
-            $replace = $structure[2];
100
-
101
-            // Perhaps needs to be improved here if $search contains "/" precisely.
102
-            $updateValue = preg_replace('/' . $search . '/isU', $replace, $currentValue);
103
-        }
104
-        return $updateValue;
105
-    }
106
-
107
-    /**
108
-     * @param ProcessContentDataSignalArguments $signalArguments
109
-     * @return int
110
-     */
111
-    protected function getCreationTime(ProcessContentDataSignalArguments $signalArguments)
112
-    {
113
-        $creationTime = 0;
114
-        $creationTimeField = Tca::table($signalArguments->getContentObject()->getDataType())->getTimeCreationField();
115
-        if ($creationTimeField) {
116
-            $creationTime = $this->getContentObjectResolver()->getValue(
117
-                $signalArguments->getContentObject(),
118
-                $signalArguments->getFieldNameAndPath(),
119
-                $creationTimeField
120
-            );
121
-        }
122
-        return $creationTime;
123
-    }
124
-
125
-    /**
126
-     * @return ContentObjectResolver
127
-     */
128
-    protected function getContentObjectResolver()
129
-    {
130
-        return GeneralUtility::makeInstance(ContentObjectResolver::class);
131
-    }
23
+	/**
24
+	 * @var array
25
+	 */
26
+	protected $wellKnownMarkers = array(
27
+		'{*}',
28
+		'{counter}',
29
+		'{date}',
30
+		'{creation_date}'
31
+	);
32
+
33
+	/**
34
+	 * @param ProcessContentDataSignalArguments $signalArguments
35
+	 * @return array
36
+	 */
37
+	public function processMarkers(ProcessContentDataSignalArguments $signalArguments)
38
+	{
39
+
40
+		$contentData = $signalArguments->getContentData();
41
+		$creationTime = $this->getCreationTime($signalArguments);
42
+
43
+		// Process markers
44
+		foreach ($signalArguments->getContentData() as $fieldName => $updateValue) {
45
+			if (is_scalar($updateValue)) {
46
+
47
+				$currentValue = $this->getContentObjectResolver()->getValue(
48
+					$signalArguments->getContentObject(),
49
+					$signalArguments->getFieldNameAndPath(),
50
+					$fieldName,
51
+					$signalArguments->getLanguage()
52
+				);
53
+				$counter = $signalArguments->getCounter();
54
+
55
+				$updateValue = $this->searchAndReplace($updateValue, $currentValue);
56
+				$updateValue = $this->replaceWellKnownMarkers($updateValue, $currentValue, $counter, $creationTime);
57
+
58
+				$contentData[$fieldName] = $updateValue;
59
+			}
60
+		}
61
+
62
+		$signalArguments->setContentData($contentData);
63
+		return array($signalArguments);
64
+	}
65
+
66
+	/**
67
+	 * @param string $updateValue
68
+	 * @param string $currentValue
69
+	 * @param int $counter
70
+	 * @param $creationTime
71
+	 * @return string
72
+	 */
73
+	protected function replaceWellKnownMarkers($updateValue, $currentValue, $counter, $creationTime)
74
+	{
75
+
76
+		// Replaces values.
77
+		$replaces = array(
78
+			$currentValue,
79
+			$counter,
80
+			date($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy']),
81
+			date($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'], $creationTime),
82
+		);
83
+
84
+		// Replace me!
85
+		return str_replace($this->wellKnownMarkers, $replaces, $updateValue);
86
+	}
87
+
88
+	/**
89
+	 * @param string $updateValue
90
+	 * @param string $currentValue
91
+	 * @return string
92
+	 */
93
+	protected function searchAndReplace($updateValue, $currentValue)
94
+	{
95
+
96
+		if (strpos($updateValue, 's/') !== false) {
97
+			$structure = explode('/', $updateValue);
98
+			$search = $structure[1];
99
+			$replace = $structure[2];
100
+
101
+			// Perhaps needs to be improved here if $search contains "/" precisely.
102
+			$updateValue = preg_replace('/' . $search . '/isU', $replace, $currentValue);
103
+		}
104
+		return $updateValue;
105
+	}
106
+
107
+	/**
108
+	 * @param ProcessContentDataSignalArguments $signalArguments
109
+	 * @return int
110
+	 */
111
+	protected function getCreationTime(ProcessContentDataSignalArguments $signalArguments)
112
+	{
113
+		$creationTime = 0;
114
+		$creationTimeField = Tca::table($signalArguments->getContentObject()->getDataType())->getTimeCreationField();
115
+		if ($creationTimeField) {
116
+			$creationTime = $this->getContentObjectResolver()->getValue(
117
+				$signalArguments->getContentObject(),
118
+				$signalArguments->getFieldNameAndPath(),
119
+				$creationTimeField
120
+			);
121
+		}
122
+		return $creationTime;
123
+	}
124
+
125
+	/**
126
+	 * @return ContentObjectResolver
127
+	 */
128
+	protected function getContentObjectResolver()
129
+	{
130
+		return GeneralUtility::makeInstance(ContentObjectResolver::class);
131
+	}
132 132
 
133 133
 }
Please login to merge, or discard this patch.