Completed
Push — master ( 080764...892a3f )
by Fabien
52:24
created
Classes/Domain/Repository/ContentRepositoryFactory.php 1 patch
Indentation   +39 added lines, -39 removed lines patch added patch discarded remove patch
@@ -17,44 +17,44 @@
 block discarded – undo
17 17
 class ContentRepositoryFactory implements SingletonInterface
18 18
 {
19 19
 
20
-    /**
21
-     * @var array
22
-     */
23
-    static protected $instances = [];
24
-
25
-    /**
26
-     * Returns a class instance of a repository.
27
-     * If not data type is given, get the value from the module loader.
28
-     *
29
-     * @param string $dataType
30
-     * @param string $sourceFieldName
31
-     * @return ContentRepository
32
-     */
33
-    static public function getInstance($dataType = null, $sourceFieldName = '')
34
-    {
35
-
36
-        /** @var ModuleLoader $moduleLoader */
37
-        if (is_null($dataType)) {
38
-
39
-            // Try to get the data type from the module loader.
40
-            $moduleLoader = GeneralUtility::makeInstance(ModuleLoader::class);
41
-            $dataType = $moduleLoader->getDataType();
42
-        }
43
-
44
-        // This should not happen.
45
-        if (!$dataType) {
46
-            throw new \RuntimeException('No data type given nor could be fetched by the module loader.', 1376118278);
47
-        }
48
-
49
-        if (empty(self::$instances[$dataType])) {
50
-            $className = 'Fab\Vidi\Domain\Repository\ContentRepository';
51
-            self::$instances[$dataType] = GeneralUtility::makeInstance($className, $dataType, $sourceFieldName);
52
-        }
53
-
54
-        /** @var ContentRepository $contentRepository */
55
-        $contentRepository = self::$instances[$dataType];
56
-        $contentRepository->setSourceFieldName($sourceFieldName);
57
-        return $contentRepository;
58
-    }
20
+	/**
21
+	 * @var array
22
+	 */
23
+	static protected $instances = [];
24
+
25
+	/**
26
+	 * Returns a class instance of a repository.
27
+	 * If not data type is given, get the value from the module loader.
28
+	 *
29
+	 * @param string $dataType
30
+	 * @param string $sourceFieldName
31
+	 * @return ContentRepository
32
+	 */
33
+	static public function getInstance($dataType = null, $sourceFieldName = '')
34
+	{
35
+
36
+		/** @var ModuleLoader $moduleLoader */
37
+		if (is_null($dataType)) {
38
+
39
+			// Try to get the data type from the module loader.
40
+			$moduleLoader = GeneralUtility::makeInstance(ModuleLoader::class);
41
+			$dataType = $moduleLoader->getDataType();
42
+		}
43
+
44
+		// This should not happen.
45
+		if (!$dataType) {
46
+			throw new \RuntimeException('No data type given nor could be fetched by the module loader.', 1376118278);
47
+		}
48
+
49
+		if (empty(self::$instances[$dataType])) {
50
+			$className = 'Fab\Vidi\Domain\Repository\ContentRepository';
51
+			self::$instances[$dataType] = GeneralUtility::makeInstance($className, $dataType, $sourceFieldName);
52
+		}
53
+
54
+		/** @var ContentRepository $contentRepository */
55
+		$contentRepository = self::$instances[$dataType];
56
+		$contentRepository->setSourceFieldName($sourceFieldName);
57
+		return $contentRepository;
58
+	}
59 59
 
60 60
 }
Please login to merge, or discard this patch.
Classes/Domain/Model/Content.php 1 patch
Indentation   +445 added lines, -445 removed lines patch added patch discarded remove patch
@@ -28,450 +28,450 @@
 block discarded – undo
28 28
 class Content implements \ArrayAccess
29 29
 {
30 30
 
31
-    /**
32
-     * @var int
33
-     */
34
-    protected $uid;
35
-
36
-    /**
37
-     * @var string
38
-     */
39
-    protected $dataType;
40
-
41
-    /**
42
-     * Constructor for a Content object.
43
-     *
44
-     * @param string $dataType will basically correspond to a table name, e.g fe_users, tt_content, ...
45
-     * @param array $contentData
46
-     * @return \Fab\Vidi\Domain\Model\Content
47
-     * @throws \InvalidArgumentException
48
-     * @throws NotExistingClassException
49
-     */
50
-    public function __construct($dataType, array $contentData = array())
51
-    {
52
-
53
-        $this->dataType = $dataType;
54
-        $this->uid = empty($contentData['uid']) ? null : (int)$contentData['uid'];
55
-
56
-        /** @var TableService $table */
57
-        $table = Tca::table($dataType);
58
-
59
-        // Initialize the array containing the allowed fields to be filled-in.
60
-        $fields = array('pid');
61
-
62
-        // If a creation time stamp has been defined for this data type.
63
-        if ($table->getTimeCreationField()) {
64
-            $fields[] = $table->getTimeCreationField();
65
-        }
66
-
67
-        // If an update time stamp has been defined for this data type.
68
-        if ($table->getTimeModificationField()) {
69
-            $fields[] = $table->getTimeModificationField();
70
-        }
71
-
72
-        // Merge the other fields allowed for this data type.
73
-        $fields = array_merge($fields, $table->getFields());
74
-
75
-        // Fetch excluded fields from the grid.
76
-        if ($this->isBackendMode()) {
77
-            $fields = $this->filterForConfiguration($fields);
78
-            $fields = $this->filterForBackendUser($fields);
79
-        }
80
-
81
-        // Get column to be displayed
82
-        foreach ($fields as $fieldName) {
83
-            if (array_key_exists($fieldName, $contentData)) {
84
-                $propertyName = Field::name($fieldName)->of($dataType)->toPropertyName();
85
-                $this->$propertyName = $contentData[$fieldName];
86
-            }
87
-        }
88
-    }
89
-
90
-    /**
91
-     * Dispatches magic methods (findBy[Property]())
92
-     *
93
-     * @param string $methodName The name of the magic method
94
-     * @param string $arguments The arguments of the magic method
95
-     * @throws UnsupportedMethodException
96
-     * @return mixed
97
-     * @api
98
-     */
99
-    public function __call($methodName, $arguments)
100
-    {
101
-        $value = null;
102
-        if (substr($methodName, 0, 3) === 'get' && strlen($methodName) > 4) {
103
-            $propertyName = strtolower(substr(substr($methodName, 3), 0, 1)) . substr(substr($methodName, 3), 1);
104
-
105
-            $fieldName = Property::name($propertyName)->of($this)->toFieldName();
106
-            $field = Tca::table($this->dataType)->field($fieldName);
107
-
108
-            $value = $this->$propertyName;
109
-
110
-            // true means it is a relation and it is not yet resolved.
111
-            if ($this->hasRelation($propertyName) && is_scalar($this->$propertyName)) {
112
-                $value = $this->resolveRelation($propertyName);
113
-            } elseif ($field->getType() === FieldType::RADIO || $field->getType() === FieldType::SELECT) {
114
-
115
-                // Attempt to convert the value into a label for radio and select fields.
116
-                $label = Tca::table($this->getDataType())->field($fieldName)->getLabelForItem($value);
117
-                if ($label) {
118
-                    $value = $label;
119
-                }
120
-            }
121
-
122
-        } elseif (substr($methodName, 0, 3) === 'set' && strlen($methodName) > 4 && isset($arguments[0])) {
123
-            $propertyName = strtolower(substr(substr($methodName, 3), 0, 1)) . substr(substr($methodName, 3), 1);
124
-            $this->$propertyName = $arguments[0];
125
-        }
126
-        return $value;
127
-    }
128
-
129
-    /**
130
-     * Tell whether the property has a relation.
131
-     *
132
-     * @param string $propertyName
133
-     * @return bool
134
-     */
135
-    protected function hasRelation($propertyName)
136
-    {
137
-        $fieldName = Property::name($propertyName)->of($this)->toFieldName();
138
-        return Tca::table($this->dataType)->field($fieldName)->hasRelation();
139
-    }
140
-
141
-    /**
142
-     * Try to "resolve" the property whether it has a relation.
143
-     * If the property has not relation it simply returns the same value.
144
-     *
145
-     * @throws \RuntimeException
146
-     * @param string $propertyName
147
-     * @return mixed
148
-     */
149
-    protected function resolveRelation($propertyName)
150
-    {
151
-
152
-        // Convert property name to field name and get the foreign data type.
153
-        $fieldName = Property::name($propertyName)->of($this)->toFieldName();
154
-        $foreignDataType = Tca::table($this->dataType)->field($fieldName)->relationDataType();
155
-
156
-        // Get the foreign repository instance form the factory
157
-        /** @var ContentRepository $foreignContentRepository */
158
-        $foreignContentRepository = ContentRepositoryFactory::getInstance($foreignDataType, $fieldName);
159
-
160
-        if (Tca::table($this->dataType)->field($fieldName)->hasRelationWithCommaSeparatedValues()) {
161
-
162
-            // Fetch values from repository
163
-            $values = GeneralUtility::trimExplode(',', $this->$propertyName);
164
-            $this->$propertyName = $foreignContentRepository->findIn('uid', $values);
165
-        } elseif (Tca::table($this->dataType)->field($fieldName)->hasMany()) {
166
-            // Include relation many-to-many and one-to-many
167
-            // Tca::table($this->dataType)->field($fieldName)->hasRelationOneToMany()
168
-            // Tca::table($this->dataType)->field($fieldName)->hasRelationManyToMany()
169
-
170
-            $foreignFieldName = Tca::table($this->dataType)->field($fieldName)->getForeignField();
171
-            if (empty($foreignFieldName)) {
172
-                $message = sprintf('Missing "foreign_field" key for field "%s" in table "%s".',
173
-                    $fieldName,
174
-                    $this->dataType
175
-                );
176
-                throw new \RuntimeException($message, 1376149186);
177
-            }
178
-
179
-            // Fetch values from repository.
180
-            $foreignPropertyName = Field::name($foreignFieldName)->of($this)->toPropertyName();
181
-            $findByProperty = 'findBy' . ucfirst($foreignPropertyName);
182
-
183
-            // Date picker (type == group) are special fields because property path must contain the table name
184
-            // to determine the relation type. Example for sys_category, property path will look like "items.sys_file"
185
-            $propertyValue = $this->uid;
186
-            if (Tca::table($foreignDataType)->field($foreignFieldName)->isGroup()) {
187
-                $propertyValue = $this->dataType . '.' . $this->uid;
188
-            }
189
-
190
-            $this->$propertyName = $foreignContentRepository->$findByProperty($propertyValue);
191
-
192
-        } elseif (Tca::table($this->dataType)->field($fieldName)->hasOne()) {
193
-
194
-            $fieldConfiguration = Tca::table($this->dataType)->field($fieldName)->getConfiguration();
195
-
196
-            // First case, we are on the "good side" of the relation, just query the repository
197
-            if (empty($fieldConfiguration['foreign_field'])) {
198
-                $this->$propertyName = $foreignContentRepository->findByUid($this->$propertyName);
199
-            } else {
200
-                // Second case, we are the "bad side" of the relation, query the foreign repository
201
-                // e.g. in case of one-to-one relation.
202
-
203
-                // We must query the opposite side to get the identifier of the foreign object.
204
-                $foreignDataType = Tca::table($this->dataType)->field($fieldName)->getForeignTable();
205
-                $foreignField = Tca::table($this->dataType)->field($fieldName)->getForeignField();
206
-                $foreignContentRepository = ContentRepositoryFactory::getInstance($foreignDataType);
207
-                $find = 'findOneBy' . GeneralUtility::underscoredToUpperCamelCase($foreignField);
208
-
209
-                /** @var Content $foreignObject */
210
-                $this->$propertyName = $foreignContentRepository->$find($this->getUid());
211
-            }
212
-
213
-        }
214
-        return $this->$propertyName;
215
-    }
216
-
217
-    /**
218
-     * @return int
219
-     */
220
-    public function getUid()
221
-    {
222
-        return $this->uid;
223
-    }
224
-
225
-    /**
226
-     * @return string
227
-     */
228
-    public function getDataType()
229
-    {
230
-        return $this->dataType;
231
-    }
232
-
233
-    /**
234
-     * Whether a offset exists
235
-     *
236
-     * @link http://php.net/manual/en/arrayaccess.offsetexists.php
237
-     * @param mixed $offset
238
-     * @return boolean true on success or false on failure.
239
-     * @throws \RuntimeException
240
-     * @throws \InvalidArgumentException
241
-     */
242
-    public function offsetExists($offset)
243
-    {
244
-        $offset = Field::name($offset)->of($this)->toPropertyName();
245
-        return isset($this->$offset);
246
-    }
247
-
248
-    /**
249
-     * Offset to retrieve
250
-     *
251
-     * @link http://php.net/manual/en/arrayaccess.offsetget.php
252
-     * @param mixed $offset
253
-     * @return mixed Can return all value types.
254
-     * @throws \RuntimeException
255
-     * @throws \InvalidArgumentException
256
-     */
257
-    public function offsetGet($offset)
258
-    {
259
-        $offset = Field::name($offset)->of($this)->toPropertyName();
260
-        $getter = 'get' . ucfirst($offset);
261
-        return $this->$getter();
262
-    }
263
-
264
-    /**
265
-     * Offset to set
266
-     *
267
-     * @link http://php.net/manual/en/arrayaccess.offsetset.php
268
-     * @param mixed $offset
269
-     * @param mixed $value
270
-     * @return $this
271
-     * @throws \RuntimeException
272
-     * @throws \InvalidArgumentException
273
-     */
274
-    public function offsetSet($offset, $value)
275
-    {
276
-        $offset = Field::name($offset)->of($this)->toPropertyName();
277
-        $setter = 'set' . ucfirst($offset);
278
-        $this->$setter($value);
279
-        return $this;
280
-    }
281
-
282
-    /**
283
-     * Offset to unset
284
-     *
285
-     * @link http://php.net/manual/en/arrayaccess.offsetunset.php
286
-     * @param mixed $offset
287
-     * @throws NotImplementedException
288
-     * @return void
289
-     */
290
-    public function offsetUnset($offset)
291
-    {
292
-        $message = 'Un-setting value for Array object is not supported';
293
-        throw new NotImplementedException($message, 1376132306);
294
-    }
295
-
296
-    /**
297
-     * Convert this to array
298
-     *
299
-     * @return array
300
-     * @throws \InvalidArgumentException
301
-     */
302
-    public function toArray()
303
-    {
304
-        $result['uid'] = $this->uid;
305
-        $propertiesAndValues = json_decode(json_encode($this), true);
306
-
307
-        foreach ($propertiesAndValues as $propertyName => $value) {
308
-            $fieldName = Property::name($propertyName)->of($this)->toFieldName();
309
-            $result[$fieldName] = $value;
310
-        }
311
-
312
-        return $result;
313
-    }
314
-
315
-    /**
316
-     * Convert this object to an array containing the resolved values.
317
-     *
318
-     * @param bool $resolveRelations
319
-     * @return array
320
-     * @throws \Exception
321
-     */
322
-    public function toValues($resolveRelations = true)
323
-    {
324
-        $result['uid'] = $this->uid;
325
-        $propertiesAndValues = json_decode(json_encode($this), true);
326
-
327
-        foreach ($propertiesAndValues as $propertyName => $value) {
328
-            $fieldName = Property::name($propertyName)->of($this)->toFieldName();
329
-
330
-            $result[$fieldName] = $value;
331
-            if ($resolveRelations) {
332
-                $field = Tca::table($this->dataType)->field($fieldName);
333
-
334
-                $resolvedValue = '';
335
-                if ($field->getType() === FieldType::FILE) {
336
-
337
-                    if ($field->hasMany()) {
338
-                        $files = FileReferenceService::getInstance()->findReferencedBy($propertyName, $this);
339
-
340
-                        $resolvedValue = [];
341
-                        foreach ($files as $file) {
342
-                            $resolvedValue[] = $file->getIdentifier();
343
-                        }
344
-                    } else {
345
-                        $files = FileReferenceService::getInstance()->findReferencedBy($propertyName, $this);
346
-                        if (!empty($files)) {
347
-                            $resolvedValue = current($files)->getIdentifier();
348
-                        }
349
-                    }
350
-
351
-                    // Reset value
352
-                    $result[$fieldName] = $resolvedValue;
353
-
354
-                } elseif (Tca::table($this->dataType)->field($fieldName)->hasRelation()) {
355
-                    $objects = $this[$fieldName];
356
-                    if (is_array($objects)) {
357
-                        $resolvedValue = [];
358
-                        foreach ($objects as $object) {
359
-                            /** @var $object Content */
360
-                            $labelField = Tca::table($object->getDataType())->getLabelField();
361
-                            $resolvedValue[] = $object[$labelField];
362
-                        }
363
-                    } elseif ($objects instanceof Content) {
364
-                        $labelField = Tca::table($objects->getDataType())->getLabelField();
365
-                        $resolvedValue = $objects[$labelField];
366
-                    }
367
-
368
-                    // Reset value
369
-                    $result[$fieldName] = $resolvedValue;
370
-                }
371
-            }
372
-        }
373
-
374
-        return $result;
375
-    }
376
-
377
-    /**
378
-     * Return the properties of this object.
379
-     *
380
-     * @return array
381
-     */
382
-    public function toProperties()
383
-    {
384
-        $result[] = 'uid';
385
-        $propertiesAndValues = json_decode(json_encode($this), true);
386
-
387
-        foreach ($propertiesAndValues as $propertyName => $value) {
388
-            $result[] = $propertyName;
389
-        }
390
-        return $result;
391
-    }
392
-
393
-    /**
394
-     * Return the properties of this object.
395
-     *
396
-     * @return array
397
-     */
398
-    public function toFields()
399
-    {
400
-        $result[] = 'uid';
401
-        $propertiesAndValues = json_decode(json_encode($this), true);
402
-
403
-        foreach ($propertiesAndValues as $propertyName => $value) {
404
-            $result[] = Property::name($propertyName)->of($this)->toFieldName();
405
-        }
406
-
407
-        return $result;
408
-    }
409
-
410
-    /**
411
-     * @return string
412
-     */
413
-    public function __toString()
414
-    {
415
-        $labelField = Tca::table($this->dataType)->getLabelField();
416
-        return $this[$labelField];
417
-    }
418
-
419
-    /**
420
-     * Remove fields according to BE User permission.
421
-     *
422
-     * @param $fields
423
-     * @return array
424
-     * @throws \Exception
425
-     */
426
-    protected function filterForBackendUser($fields)
427
-    {
428
-        if (!$this->getBackendUser()->isAdmin()) {
429
-            foreach ($fields as $key => $fieldName) {
430
-                if (Tca::table($this->dataType)->hasField($fieldName) && !Tca::table($this->dataType)->field($fieldName)->hasAccess()) {
431
-                    unset($fields[$key]);
432
-                }
433
-            }
434
-        }
435
-        return $fields;
436
-    }
437
-
438
-    /**
439
-     * Remove fields according to Grid configuration.
440
-     *
441
-     * @param $fields
442
-     * @return array
443
-     */
444
-    protected function filterForConfiguration($fields)
445
-    {
446
-
447
-        $excludedFields = Tca::grid($this->dataType)->getExcludedFields();
448
-        foreach ($fields as $key => $field) {
449
-            if (in_array($field, $excludedFields)) {
450
-                unset($fields[$key]);
451
-            }
452
-        }
453
-
454
-        return $fields;
455
-    }
456
-
457
-    /**
458
-     * Returns an instance of the current Backend User.
459
-     *
460
-     * @return BackendUserAuthentication
461
-     */
462
-    protected function getBackendUser()
463
-    {
464
-        return $GLOBALS['BE_USER'];
465
-    }
466
-
467
-    /**
468
-     * Returns whether the current mode is Backend
469
-     *
470
-     * @return bool
471
-     */
472
-    protected function isBackendMode()
473
-    {
474
-        return ApplicationType::fromRequest($GLOBALS['TYPO3_REQUEST'])->isBackend();;
475
-    }
31
+	/**
32
+	 * @var int
33
+	 */
34
+	protected $uid;
35
+
36
+	/**
37
+	 * @var string
38
+	 */
39
+	protected $dataType;
40
+
41
+	/**
42
+	 * Constructor for a Content object.
43
+	 *
44
+	 * @param string $dataType will basically correspond to a table name, e.g fe_users, tt_content, ...
45
+	 * @param array $contentData
46
+	 * @return \Fab\Vidi\Domain\Model\Content
47
+	 * @throws \InvalidArgumentException
48
+	 * @throws NotExistingClassException
49
+	 */
50
+	public function __construct($dataType, array $contentData = array())
51
+	{
52
+
53
+		$this->dataType = $dataType;
54
+		$this->uid = empty($contentData['uid']) ? null : (int)$contentData['uid'];
55
+
56
+		/** @var TableService $table */
57
+		$table = Tca::table($dataType);
58
+
59
+		// Initialize the array containing the allowed fields to be filled-in.
60
+		$fields = array('pid');
61
+
62
+		// If a creation time stamp has been defined for this data type.
63
+		if ($table->getTimeCreationField()) {
64
+			$fields[] = $table->getTimeCreationField();
65
+		}
66
+
67
+		// If an update time stamp has been defined for this data type.
68
+		if ($table->getTimeModificationField()) {
69
+			$fields[] = $table->getTimeModificationField();
70
+		}
71
+
72
+		// Merge the other fields allowed for this data type.
73
+		$fields = array_merge($fields, $table->getFields());
74
+
75
+		// Fetch excluded fields from the grid.
76
+		if ($this->isBackendMode()) {
77
+			$fields = $this->filterForConfiguration($fields);
78
+			$fields = $this->filterForBackendUser($fields);
79
+		}
80
+
81
+		// Get column to be displayed
82
+		foreach ($fields as $fieldName) {
83
+			if (array_key_exists($fieldName, $contentData)) {
84
+				$propertyName = Field::name($fieldName)->of($dataType)->toPropertyName();
85
+				$this->$propertyName = $contentData[$fieldName];
86
+			}
87
+		}
88
+	}
89
+
90
+	/**
91
+	 * Dispatches magic methods (findBy[Property]())
92
+	 *
93
+	 * @param string $methodName The name of the magic method
94
+	 * @param string $arguments The arguments of the magic method
95
+	 * @throws UnsupportedMethodException
96
+	 * @return mixed
97
+	 * @api
98
+	 */
99
+	public function __call($methodName, $arguments)
100
+	{
101
+		$value = null;
102
+		if (substr($methodName, 0, 3) === 'get' && strlen($methodName) > 4) {
103
+			$propertyName = strtolower(substr(substr($methodName, 3), 0, 1)) . substr(substr($methodName, 3), 1);
104
+
105
+			$fieldName = Property::name($propertyName)->of($this)->toFieldName();
106
+			$field = Tca::table($this->dataType)->field($fieldName);
107
+
108
+			$value = $this->$propertyName;
109
+
110
+			// true means it is a relation and it is not yet resolved.
111
+			if ($this->hasRelation($propertyName) && is_scalar($this->$propertyName)) {
112
+				$value = $this->resolveRelation($propertyName);
113
+			} elseif ($field->getType() === FieldType::RADIO || $field->getType() === FieldType::SELECT) {
114
+
115
+				// Attempt to convert the value into a label for radio and select fields.
116
+				$label = Tca::table($this->getDataType())->field($fieldName)->getLabelForItem($value);
117
+				if ($label) {
118
+					$value = $label;
119
+				}
120
+			}
121
+
122
+		} elseif (substr($methodName, 0, 3) === 'set' && strlen($methodName) > 4 && isset($arguments[0])) {
123
+			$propertyName = strtolower(substr(substr($methodName, 3), 0, 1)) . substr(substr($methodName, 3), 1);
124
+			$this->$propertyName = $arguments[0];
125
+		}
126
+		return $value;
127
+	}
128
+
129
+	/**
130
+	 * Tell whether the property has a relation.
131
+	 *
132
+	 * @param string $propertyName
133
+	 * @return bool
134
+	 */
135
+	protected function hasRelation($propertyName)
136
+	{
137
+		$fieldName = Property::name($propertyName)->of($this)->toFieldName();
138
+		return Tca::table($this->dataType)->field($fieldName)->hasRelation();
139
+	}
140
+
141
+	/**
142
+	 * Try to "resolve" the property whether it has a relation.
143
+	 * If the property has not relation it simply returns the same value.
144
+	 *
145
+	 * @throws \RuntimeException
146
+	 * @param string $propertyName
147
+	 * @return mixed
148
+	 */
149
+	protected function resolveRelation($propertyName)
150
+	{
151
+
152
+		// Convert property name to field name and get the foreign data type.
153
+		$fieldName = Property::name($propertyName)->of($this)->toFieldName();
154
+		$foreignDataType = Tca::table($this->dataType)->field($fieldName)->relationDataType();
155
+
156
+		// Get the foreign repository instance form the factory
157
+		/** @var ContentRepository $foreignContentRepository */
158
+		$foreignContentRepository = ContentRepositoryFactory::getInstance($foreignDataType, $fieldName);
159
+
160
+		if (Tca::table($this->dataType)->field($fieldName)->hasRelationWithCommaSeparatedValues()) {
161
+
162
+			// Fetch values from repository
163
+			$values = GeneralUtility::trimExplode(',', $this->$propertyName);
164
+			$this->$propertyName = $foreignContentRepository->findIn('uid', $values);
165
+		} elseif (Tca::table($this->dataType)->field($fieldName)->hasMany()) {
166
+			// Include relation many-to-many and one-to-many
167
+			// Tca::table($this->dataType)->field($fieldName)->hasRelationOneToMany()
168
+			// Tca::table($this->dataType)->field($fieldName)->hasRelationManyToMany()
169
+
170
+			$foreignFieldName = Tca::table($this->dataType)->field($fieldName)->getForeignField();
171
+			if (empty($foreignFieldName)) {
172
+				$message = sprintf('Missing "foreign_field" key for field "%s" in table "%s".',
173
+					$fieldName,
174
+					$this->dataType
175
+				);
176
+				throw new \RuntimeException($message, 1376149186);
177
+			}
178
+
179
+			// Fetch values from repository.
180
+			$foreignPropertyName = Field::name($foreignFieldName)->of($this)->toPropertyName();
181
+			$findByProperty = 'findBy' . ucfirst($foreignPropertyName);
182
+
183
+			// Date picker (type == group) are special fields because property path must contain the table name
184
+			// to determine the relation type. Example for sys_category, property path will look like "items.sys_file"
185
+			$propertyValue = $this->uid;
186
+			if (Tca::table($foreignDataType)->field($foreignFieldName)->isGroup()) {
187
+				$propertyValue = $this->dataType . '.' . $this->uid;
188
+			}
189
+
190
+			$this->$propertyName = $foreignContentRepository->$findByProperty($propertyValue);
191
+
192
+		} elseif (Tca::table($this->dataType)->field($fieldName)->hasOne()) {
193
+
194
+			$fieldConfiguration = Tca::table($this->dataType)->field($fieldName)->getConfiguration();
195
+
196
+			// First case, we are on the "good side" of the relation, just query the repository
197
+			if (empty($fieldConfiguration['foreign_field'])) {
198
+				$this->$propertyName = $foreignContentRepository->findByUid($this->$propertyName);
199
+			} else {
200
+				// Second case, we are the "bad side" of the relation, query the foreign repository
201
+				// e.g. in case of one-to-one relation.
202
+
203
+				// We must query the opposite side to get the identifier of the foreign object.
204
+				$foreignDataType = Tca::table($this->dataType)->field($fieldName)->getForeignTable();
205
+				$foreignField = Tca::table($this->dataType)->field($fieldName)->getForeignField();
206
+				$foreignContentRepository = ContentRepositoryFactory::getInstance($foreignDataType);
207
+				$find = 'findOneBy' . GeneralUtility::underscoredToUpperCamelCase($foreignField);
208
+
209
+				/** @var Content $foreignObject */
210
+				$this->$propertyName = $foreignContentRepository->$find($this->getUid());
211
+			}
212
+
213
+		}
214
+		return $this->$propertyName;
215
+	}
216
+
217
+	/**
218
+	 * @return int
219
+	 */
220
+	public function getUid()
221
+	{
222
+		return $this->uid;
223
+	}
224
+
225
+	/**
226
+	 * @return string
227
+	 */
228
+	public function getDataType()
229
+	{
230
+		return $this->dataType;
231
+	}
232
+
233
+	/**
234
+	 * Whether a offset exists
235
+	 *
236
+	 * @link http://php.net/manual/en/arrayaccess.offsetexists.php
237
+	 * @param mixed $offset
238
+	 * @return boolean true on success or false on failure.
239
+	 * @throws \RuntimeException
240
+	 * @throws \InvalidArgumentException
241
+	 */
242
+	public function offsetExists($offset)
243
+	{
244
+		$offset = Field::name($offset)->of($this)->toPropertyName();
245
+		return isset($this->$offset);
246
+	}
247
+
248
+	/**
249
+	 * Offset to retrieve
250
+	 *
251
+	 * @link http://php.net/manual/en/arrayaccess.offsetget.php
252
+	 * @param mixed $offset
253
+	 * @return mixed Can return all value types.
254
+	 * @throws \RuntimeException
255
+	 * @throws \InvalidArgumentException
256
+	 */
257
+	public function offsetGet($offset)
258
+	{
259
+		$offset = Field::name($offset)->of($this)->toPropertyName();
260
+		$getter = 'get' . ucfirst($offset);
261
+		return $this->$getter();
262
+	}
263
+
264
+	/**
265
+	 * Offset to set
266
+	 *
267
+	 * @link http://php.net/manual/en/arrayaccess.offsetset.php
268
+	 * @param mixed $offset
269
+	 * @param mixed $value
270
+	 * @return $this
271
+	 * @throws \RuntimeException
272
+	 * @throws \InvalidArgumentException
273
+	 */
274
+	public function offsetSet($offset, $value)
275
+	{
276
+		$offset = Field::name($offset)->of($this)->toPropertyName();
277
+		$setter = 'set' . ucfirst($offset);
278
+		$this->$setter($value);
279
+		return $this;
280
+	}
281
+
282
+	/**
283
+	 * Offset to unset
284
+	 *
285
+	 * @link http://php.net/manual/en/arrayaccess.offsetunset.php
286
+	 * @param mixed $offset
287
+	 * @throws NotImplementedException
288
+	 * @return void
289
+	 */
290
+	public function offsetUnset($offset)
291
+	{
292
+		$message = 'Un-setting value for Array object is not supported';
293
+		throw new NotImplementedException($message, 1376132306);
294
+	}
295
+
296
+	/**
297
+	 * Convert this to array
298
+	 *
299
+	 * @return array
300
+	 * @throws \InvalidArgumentException
301
+	 */
302
+	public function toArray()
303
+	{
304
+		$result['uid'] = $this->uid;
305
+		$propertiesAndValues = json_decode(json_encode($this), true);
306
+
307
+		foreach ($propertiesAndValues as $propertyName => $value) {
308
+			$fieldName = Property::name($propertyName)->of($this)->toFieldName();
309
+			$result[$fieldName] = $value;
310
+		}
311
+
312
+		return $result;
313
+	}
314
+
315
+	/**
316
+	 * Convert this object to an array containing the resolved values.
317
+	 *
318
+	 * @param bool $resolveRelations
319
+	 * @return array
320
+	 * @throws \Exception
321
+	 */
322
+	public function toValues($resolveRelations = true)
323
+	{
324
+		$result['uid'] = $this->uid;
325
+		$propertiesAndValues = json_decode(json_encode($this), true);
326
+
327
+		foreach ($propertiesAndValues as $propertyName => $value) {
328
+			$fieldName = Property::name($propertyName)->of($this)->toFieldName();
329
+
330
+			$result[$fieldName] = $value;
331
+			if ($resolveRelations) {
332
+				$field = Tca::table($this->dataType)->field($fieldName);
333
+
334
+				$resolvedValue = '';
335
+				if ($field->getType() === FieldType::FILE) {
336
+
337
+					if ($field->hasMany()) {
338
+						$files = FileReferenceService::getInstance()->findReferencedBy($propertyName, $this);
339
+
340
+						$resolvedValue = [];
341
+						foreach ($files as $file) {
342
+							$resolvedValue[] = $file->getIdentifier();
343
+						}
344
+					} else {
345
+						$files = FileReferenceService::getInstance()->findReferencedBy($propertyName, $this);
346
+						if (!empty($files)) {
347
+							$resolvedValue = current($files)->getIdentifier();
348
+						}
349
+					}
350
+
351
+					// Reset value
352
+					$result[$fieldName] = $resolvedValue;
353
+
354
+				} elseif (Tca::table($this->dataType)->field($fieldName)->hasRelation()) {
355
+					$objects = $this[$fieldName];
356
+					if (is_array($objects)) {
357
+						$resolvedValue = [];
358
+						foreach ($objects as $object) {
359
+							/** @var $object Content */
360
+							$labelField = Tca::table($object->getDataType())->getLabelField();
361
+							$resolvedValue[] = $object[$labelField];
362
+						}
363
+					} elseif ($objects instanceof Content) {
364
+						$labelField = Tca::table($objects->getDataType())->getLabelField();
365
+						$resolvedValue = $objects[$labelField];
366
+					}
367
+
368
+					// Reset value
369
+					$result[$fieldName] = $resolvedValue;
370
+				}
371
+			}
372
+		}
373
+
374
+		return $result;
375
+	}
376
+
377
+	/**
378
+	 * Return the properties of this object.
379
+	 *
380
+	 * @return array
381
+	 */
382
+	public function toProperties()
383
+	{
384
+		$result[] = 'uid';
385
+		$propertiesAndValues = json_decode(json_encode($this), true);
386
+
387
+		foreach ($propertiesAndValues as $propertyName => $value) {
388
+			$result[] = $propertyName;
389
+		}
390
+		return $result;
391
+	}
392
+
393
+	/**
394
+	 * Return the properties of this object.
395
+	 *
396
+	 * @return array
397
+	 */
398
+	public function toFields()
399
+	{
400
+		$result[] = 'uid';
401
+		$propertiesAndValues = json_decode(json_encode($this), true);
402
+
403
+		foreach ($propertiesAndValues as $propertyName => $value) {
404
+			$result[] = Property::name($propertyName)->of($this)->toFieldName();
405
+		}
406
+
407
+		return $result;
408
+	}
409
+
410
+	/**
411
+	 * @return string
412
+	 */
413
+	public function __toString()
414
+	{
415
+		$labelField = Tca::table($this->dataType)->getLabelField();
416
+		return $this[$labelField];
417
+	}
418
+
419
+	/**
420
+	 * Remove fields according to BE User permission.
421
+	 *
422
+	 * @param $fields
423
+	 * @return array
424
+	 * @throws \Exception
425
+	 */
426
+	protected function filterForBackendUser($fields)
427
+	{
428
+		if (!$this->getBackendUser()->isAdmin()) {
429
+			foreach ($fields as $key => $fieldName) {
430
+				if (Tca::table($this->dataType)->hasField($fieldName) && !Tca::table($this->dataType)->field($fieldName)->hasAccess()) {
431
+					unset($fields[$key]);
432
+				}
433
+			}
434
+		}
435
+		return $fields;
436
+	}
437
+
438
+	/**
439
+	 * Remove fields according to Grid configuration.
440
+	 *
441
+	 * @param $fields
442
+	 * @return array
443
+	 */
444
+	protected function filterForConfiguration($fields)
445
+	{
446
+
447
+		$excludedFields = Tca::grid($this->dataType)->getExcludedFields();
448
+		foreach ($fields as $key => $field) {
449
+			if (in_array($field, $excludedFields)) {
450
+				unset($fields[$key]);
451
+			}
452
+		}
453
+
454
+		return $fields;
455
+	}
456
+
457
+	/**
458
+	 * Returns an instance of the current Backend User.
459
+	 *
460
+	 * @return BackendUserAuthentication
461
+	 */
462
+	protected function getBackendUser()
463
+	{
464
+		return $GLOBALS['BE_USER'];
465
+	}
466
+
467
+	/**
468
+	 * Returns whether the current mode is Backend
469
+	 *
470
+	 * @return bool
471
+	 */
472
+	protected function isBackendMode()
473
+	{
474
+		return ApplicationType::fromRequest($GLOBALS['TYPO3_REQUEST'])->isBackend();;
475
+	}
476 476
 
477 477
 }
Please login to merge, or discard this patch.
Classes/Domain/Validator/ToolValidator.php 1 patch
Indentation   +28 added lines, -28 removed lines patch added patch discarded remove patch
@@ -18,36 +18,36 @@
 block discarded – undo
18 18
 class ToolValidator extends AbstractValidator
19 19
 {
20 20
 
21
-    /**
22
-     * Check whether $tool is valid.
23
-     *
24
-     * @param string $tool
25
-     * @return void
26
-     */
27
-    public function isValid($tool)
28
-    {
21
+	/**
22
+	 * Check whether $tool is valid.
23
+	 *
24
+	 * @param string $tool
25
+	 * @return void
26
+	 */
27
+	public function isValid($tool)
28
+	{
29 29
 
30
-        $dataType = $this->getModuleLoader()->getDataType();
31
-        $isValid = ToolRegistry::getInstance()->isAllowed($dataType, $tool);
30
+		$dataType = $this->getModuleLoader()->getDataType();
31
+		$isValid = ToolRegistry::getInstance()->isAllowed($dataType, $tool);
32 32
 
33
-        if (!$isValid) {
34
-            $message = sprintf('This Tool "%s" is not allowed for the current data type.', $tool);
35
-            $this->addError($message, 1409041510);
36
-        }
33
+		if (!$isValid) {
34
+			$message = sprintf('This Tool "%s" is not allowed for the current data type.', $tool);
35
+			$this->addError($message, 1409041510);
36
+		}
37 37
 
38
-        if (!class_exists($tool)) {
39
-            $message = sprintf('I could not find class "%s"', $tool);
40
-            $this->addError($message, 1409041511);
41
-        }
42
-    }
38
+		if (!class_exists($tool)) {
39
+			$message = sprintf('I could not find class "%s"', $tool);
40
+			$this->addError($message, 1409041511);
41
+		}
42
+	}
43 43
 
44
-    /**
45
-     * Get the Vidi Module Loader.
46
-     *
47
-     * @return ModuleLoader|object
48
-     */
49
-    protected function getModuleLoader()
50
-    {
51
-        return GeneralUtility::makeInstance(ModuleLoader::class);
52
-    }
44
+	/**
45
+	 * Get the Vidi Module Loader.
46
+	 *
47
+	 * @return ModuleLoader|object
48
+	 */
49
+	protected function getModuleLoader()
50
+	{
51
+		return GeneralUtility::makeInstance(ModuleLoader::class);
52
+	}
53 53
 }
Please login to merge, or discard this patch.
Classes/Domain/Validator/LanguageValidator.php 1 patch
Indentation   +20 added lines, -20 removed lines patch added patch discarded remove patch
@@ -16,27 +16,27 @@
 block discarded – undo
16 16
 class LanguageValidator
17 17
 {
18 18
 
19
-    /**
20
-     * Check whether the $language is valid.
21
-     *
22
-     * @param int $language
23
-     * @throws \Exception
24
-     * @return void
25
-     */
26
-    public function validate($language)
27
-    {
19
+	/**
20
+	 * Check whether the $language is valid.
21
+	 *
22
+	 * @param int $language
23
+	 * @throws \Exception
24
+	 * @return void
25
+	 */
26
+	public function validate($language)
27
+	{
28 28
 
29
-        if (!$this->getLanguageService()->languageExists((int)$language)) {
30
-            throw new \Exception('The language "' . $language . '" does not exist', 1351605542);
31
-        }
32
-    }
29
+		if (!$this->getLanguageService()->languageExists((int)$language)) {
30
+			throw new \Exception('The language "' . $language . '" does not exist', 1351605542);
31
+		}
32
+	}
33 33
 
34
-    /**
35
-     * @return LanguageService|object
36
-     */
37
-    protected function getLanguageService()
38
-    {
39
-        return GeneralUtility::makeInstance(LanguageService::class);
40
-    }
34
+	/**
35
+	 * @return LanguageService|object
36
+	 */
37
+	protected function getLanguageService()
38
+	{
39
+		return GeneralUtility::makeInstance(LanguageService::class);
40
+	}
41 41
 
42 42
 }
Please login to merge, or discard this patch.
Classes/Controller/ClipboardController.php 1 patch
Indentation   +74 added lines, -74 removed lines patch added patch discarded remove patch
@@ -19,79 +19,79 @@
 block discarded – undo
19 19
 class ClipboardController extends ActionController
20 20
 {
21 21
 
22
-    /**
23
-     * Save data into the clipboard.
24
-     *
25
-     * @param array $matches
26
-     * @return string
27
-     */
28
-    public function saveAction(array $matches = array())
29
-    {
30
-
31
-        $matcher = MatcherObjectFactory::getInstance()->getMatcher($matches);
32
-        $this->getClipboardService()->save($matcher);
33
-
34
-        // Fetch objects via the Content Service.
35
-        $contentService = $this->getContentService()->findBy($matcher);
36
-        $numberOfObjects = $contentService->getNumberOfObjects();
37
-
38
-        if ($numberOfObjects === 0) {
39
-            $this->getClipboardService()->flush();
40
-        }
41
-
42
-        # Json header is not automatically sent in the BE...
43
-        $this->response->setHeader('Content-Type', 'application/json');
44
-        $this->response->sendHeaders();
45
-        return json_encode($numberOfObjects);
46
-    }
47
-
48
-    /**
49
-     * Completely flush the clipboard.
50
-     *
51
-     * @return string
52
-     */
53
-    public function flushAction()
54
-    {
55
-        $this->getClipboardService()->flush();
56
-
57
-        # Json header is not automatically sent in the BE...
58
-        $this->response->setHeader('Content-Type', 'application/json');
59
-        $this->response->sendHeaders();
60
-        return json_encode(true);
61
-    }
62
-
63
-    /**
64
-     * Show the content of the clipboard.
65
-     */
66
-    public function showAction()
67
-    {
68
-
69
-        // Retrieve matcher object from clipboard.
70
-        $matcher = $this->getClipboardService()->getMatcher();
71
-
72
-        // Fetch objects via the Content Service.
73
-        $contentService = $this->getContentService()->findBy($matcher);
74
-
75
-        // count number of items and display it.
76
-        $this->view->assign('target', GeneralUtility::_GP('id'));
77
-        $this->view->assign('numberOfObjects', $contentService->getNumberOfObjects());
78
-        $this->view->assign('objects', $contentService->getObjects());
79
-    }
80
-
81
-    /**
82
-     * @return ClipboardService|object
83
-     */
84
-    protected function getClipboardService()
85
-    {
86
-        return GeneralUtility::makeInstance(ClipboardService::class);
87
-    }
88
-
89
-    /**
90
-     * @return ContentService|object
91
-     */
92
-    protected function getContentService()
93
-    {
94
-        return GeneralUtility::makeInstance(ContentService::class);
95
-    }
22
+	/**
23
+	 * Save data into the clipboard.
24
+	 *
25
+	 * @param array $matches
26
+	 * @return string
27
+	 */
28
+	public function saveAction(array $matches = array())
29
+	{
30
+
31
+		$matcher = MatcherObjectFactory::getInstance()->getMatcher($matches);
32
+		$this->getClipboardService()->save($matcher);
33
+
34
+		// Fetch objects via the Content Service.
35
+		$contentService = $this->getContentService()->findBy($matcher);
36
+		$numberOfObjects = $contentService->getNumberOfObjects();
37
+
38
+		if ($numberOfObjects === 0) {
39
+			$this->getClipboardService()->flush();
40
+		}
41
+
42
+		# Json header is not automatically sent in the BE...
43
+		$this->response->setHeader('Content-Type', 'application/json');
44
+		$this->response->sendHeaders();
45
+		return json_encode($numberOfObjects);
46
+	}
47
+
48
+	/**
49
+	 * Completely flush the clipboard.
50
+	 *
51
+	 * @return string
52
+	 */
53
+	public function flushAction()
54
+	{
55
+		$this->getClipboardService()->flush();
56
+
57
+		# Json header is not automatically sent in the BE...
58
+		$this->response->setHeader('Content-Type', 'application/json');
59
+		$this->response->sendHeaders();
60
+		return json_encode(true);
61
+	}
62
+
63
+	/**
64
+	 * Show the content of the clipboard.
65
+	 */
66
+	public function showAction()
67
+	{
68
+
69
+		// Retrieve matcher object from clipboard.
70
+		$matcher = $this->getClipboardService()->getMatcher();
71
+
72
+		// Fetch objects via the Content Service.
73
+		$contentService = $this->getContentService()->findBy($matcher);
74
+
75
+		// count number of items and display it.
76
+		$this->view->assign('target', GeneralUtility::_GP('id'));
77
+		$this->view->assign('numberOfObjects', $contentService->getNumberOfObjects());
78
+		$this->view->assign('objects', $contentService->getObjects());
79
+	}
80
+
81
+	/**
82
+	 * @return ClipboardService|object
83
+	 */
84
+	protected function getClipboardService()
85
+	{
86
+		return GeneralUtility::makeInstance(ClipboardService::class);
87
+	}
88
+
89
+	/**
90
+	 * @return ContentService|object
91
+	 */
92
+	protected function getContentService()
93
+	{
94
+		return GeneralUtility::makeInstance(ContentService::class);
95
+	}
96 96
 
97 97
 }
Please login to merge, or discard this patch.
Classes/Controller/ToolController.php 1 patch
Indentation   +37 added lines, -37 removed lines patch added patch discarded remove patch
@@ -20,46 +20,46 @@
 block discarded – undo
20 20
 class ToolController extends ActionController
21 21
 {
22 22
 
23
-    /**
24
-     * @return void
25
-     */
26
-    public function welcomeAction()
27
-    {
28
-        $items = [];
29
-        $tools = ToolRegistry::getInstance()->getTools($this->getModuleLoader()->getDataType());
23
+	/**
24
+	 * @return void
25
+	 */
26
+	public function welcomeAction()
27
+	{
28
+		$items = [];
29
+		$tools = ToolRegistry::getInstance()->getTools($this->getModuleLoader()->getDataType());
30 30
 
31
-        foreach ($tools as $index => $tool) {
32
-            $item = [];
33
-            $item['title'] = $tool->getTitle();
34
-            $item['description'] = $tool->getDescription();
31
+		foreach ($tools as $index => $tool) {
32
+			$item = [];
33
+			$item['title'] = $tool->getTitle();
34
+			$item['description'] = $tool->getDescription();
35 35
 
36
-            $items[] = $item;
37
-        }
38
-        $this->view->assign('items', $items);
39
-    }
36
+			$items[] = $item;
37
+		}
38
+		$this->view->assign('items', $items);
39
+	}
40 40
 
41
-    /**
42
-     * @param string $tool
43
-     * @param array $arguments
44
-     * @return void
45
-     * @Extbase\Validate("Fab\Vidi\Domain\Validator\ToolValidator", param="tool")
46
-     */
47
-    public function workAction(string $tool, array $arguments = array())
48
-    {
49
-        /** @var ToolInterface $tool */
50
-        $tool = GeneralUtility::makeInstance($tool);
51
-        $workResult = $tool->work($arguments);
52
-        $this->view->assign('result', $workResult);
53
-    }
41
+	/**
42
+	 * @param string $tool
43
+	 * @param array $arguments
44
+	 * @return void
45
+	 * @Extbase\Validate("Fab\Vidi\Domain\Validator\ToolValidator", param="tool")
46
+	 */
47
+	public function workAction(string $tool, array $arguments = array())
48
+	{
49
+		/** @var ToolInterface $tool */
50
+		$tool = GeneralUtility::makeInstance($tool);
51
+		$workResult = $tool->work($arguments);
52
+		$this->view->assign('result', $workResult);
53
+	}
54 54
 
55
-    /**
56
-     * Get the Vidi Module Loader.
57
-     *
58
-     * @return ModuleLoader|object
59
-     */
60
-    protected function getModuleLoader()
61
-    {
62
-        return GeneralUtility::makeInstance(ModuleLoader::class);
63
-    }
55
+	/**
56
+	 * Get the Vidi Module Loader.
57
+	 *
58
+	 * @return ModuleLoader|object
59
+	 */
60
+	protected function getModuleLoader()
61
+	{
62
+		return GeneralUtility::makeInstance(ModuleLoader::class);
63
+	}
64 64
 
65 65
 }
Please login to merge, or discard this patch.
Classes/Controller/ContentController.php 1 patch
Indentation   +743 added lines, -743 removed lines patch added patch discarded remove patch
@@ -45,748 +45,748 @@
 block discarded – undo
45 45
 class ContentController extends ActionController
46 46
 {
47 47
 
48
-    /**
49
-     * @var SelectionRepository
50
-     * @Inject
51
-     */
52
-    public $selectionRepository;
53
-
54
-    /**
55
-     * Initialize every action.
56
-     */
57
-    public function initializeAction()
58
-    {
59
-        $pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
60
-        $pageRenderer->addInlineLanguageLabelFile('EXT:vidi/Resources/Private/Language/locallang.xlf');
61
-
62
-        // Configure property mapping to retrieve the file object.
63
-        if ($this->arguments->hasArgument('columns')) {
64
-
65
-            /** @var CsvToArrayConverter $typeConverter */
66
-            $typeConverter = $this->objectManager->get(CsvToArrayConverter::class);
67
-
68
-            $propertyMappingConfiguration = $this->arguments->getArgument('columns')->getPropertyMappingConfiguration();
69
-            $propertyMappingConfiguration->setTypeConverter($typeConverter);
70
-        }
71
-    }
72
-
73
-    /**
74
-     * List action for this controller.
75
-     *
76
-     * @return void
77
-     */
78
-    public function indexAction()
79
-    {
80
-        $dataType = $this->getModuleLoader()->getDataType();
81
-        $selections = $this->selectionRepository->findByDataTypeForCurrentBackendUser($dataType);
82
-        $this->view->assign('selections', $selections);
83
-
84
-        $columns = Tca::grid()->getFields();
85
-        $this->view->assign('columns', $columns);
86
-        $this->view->assign('numberOfColumns', count($columns));
87
-    }
88
-
89
-    /**
90
-     * List Row action for this controller. Output a json list of contents
91
-     *
92
-     * @param array $columns corresponds to columns to be rendered.
93
-     * @param array $matches
94
-     * @Validate("Fab\Vidi\Domain\Validator\ColumnsValidator", param="columns")
95
-     * @Validate("Fab\Vidi\Domain\Validator\MatchesValidator", param="matches")
96
-     * @return void
97
-     */
98
-    public function listAction(array $columns = [], $matches = [])
99
-    {
100
-        // Initialize some objects related to the query.
101
-        $matcher = MatcherObjectFactory::getInstance()->getMatcher($matches);
102
-        $order = OrderObjectFactory::getInstance()->getOrder();
103
-        $pager = PagerObjectFactory::getInstance()->getPager();
104
-
105
-        // Fetch objects via the Content Service.
106
-        $contentService = $this->getContentService()->findBy($matcher, $order, $pager->getLimit(), $pager->getOffset());
107
-        $pager->setCount($contentService->getNumberOfObjects());
108
-
109
-        // Assign values.
110
-        $this->view->assign('columns', $columns);
111
-        $this->view->assign('objects', $contentService->getObjects());
112
-        $this->view->assign('numberOfObjects', $contentService->getNumberOfObjects());
113
-        $this->view->assign('pager', $pager);
114
-
115
-        $this->view->assign('response', $this->responseFactory->createResponse());
116
-    }
117
-
118
-    /**
119
-     * Retrieve Content objects first according to matching criteria and then "update" them.
120
-     * Important to notice the field name can contains a path, e.g. metadata.title and therefore must be analysed.
121
-     *
122
-     * Possible values for $matches:
123
-     * -----------------------------
124
-     *
125
-     * $matches = array(uid => 1), will be taken as $query->equals
126
-     * $matches = array(uid => 1,2,3), will be taken as $query->in
127
-     * $matches = array(field_name1 => bar, field_name2 => bax), will be separated by AND.
128
-     *
129
-     * Possible values for $content:
130
-     * -----------------------------
131
-     *
132
-     * $content = array(field_name => bar)
133
-     * $content = array(field_name => array(value1, value2)) <-- will be CSV converted by "value1,value2"
134
-     *
135
-     * @param string $fieldNameAndPath
136
-     * @param array $content
137
-     * @param array $matches
138
-     * @param string $savingBehavior
139
-     * @param int $language
140
-     * @param array $columns
141
-     * @throws InvalidKeyInArrayException
142
-     */
143
-    public function updateAction($fieldNameAndPath, array $content, array $matches = [], $savingBehavior = SavingBehavior::REPLACE, $language = 0, $columns = [])
144
-    {
145
-
146
-        // Instantiate the Matcher object according different rules.
147
-        $matcher = MatcherObjectFactory::getInstance()->getMatcher($matches);
148
-        $order = OrderObjectFactory::getInstance()->getOrder();
149
-
150
-        // Fetch objects via the Content Service.
151
-        $contentService = $this->getContentService()->findBy($matcher, $order);
152
-
153
-        // Get the real field that is going to be updated.
154
-        $updatedFieldName = $this->getFieldPathResolver()->stripFieldPath($fieldNameAndPath);
155
-
156
-        // Get result object for storing data along the processing.
157
-        $result = $this->getJsonResult();
158
-        $result->setNumberOfObjects($contentService->getNumberOfObjects());
159
-
160
-        foreach ($contentService->getObjects() as $index => $object) {
161
-
162
-            $identifier = $this->getContentObjectResolver()->getValue($object, $fieldNameAndPath, 'uid', $language);
163
-
164
-            // It could be the identifier is not found because the translation
165
-            // of the record does not yet exist when mass-editing
166
-            if ((int)$identifier <= 0) {
167
-                continue;
168
-            }
169
-
170
-            $dataType = $this->getContentObjectResolver()->getDataType($object, $fieldNameAndPath);
171
-
172
-            $signalResult = $this->emitProcessContentDataSignal($object, $fieldNameAndPath, $content, $index + 1, $savingBehavior, $language);
173
-            $contentData = $signalResult->getContentData();
174
-
175
-            // Add identifier to content data, required by TCEMain.
176
-            $contentData['uid'] = $identifier;
177
-
178
-            /** @var Content $dataObject */
179
-            $dataObject = GeneralUtility::makeInstance(Content::class, $dataType, $contentData);
180
-
181
-            // Properly update object.
182
-            ContentRepositoryFactory::getInstance($dataType)->update($dataObject);
183
-
184
-            // Get the possible error messages and store them.
185
-            $errorMessages = ContentRepositoryFactory::getInstance()->getErrorMessages();
186
-            $result->addErrorMessages($errorMessages);
187
-
188
-            // We only want to see the detail result if there is one object updated.
189
-            // Required for inline editing + it will display some useful info on the GUI in the flash messages.
190
-            if ($contentService->getNumberOfObjects() === 1) {
191
-
192
-                // Fetch the updated object from repository.
193
-                $updatedObject = ContentRepositoryFactory::getInstance()->findByUid($object->getUid());
194
-
195
-                // Re-fetch the updated result.
196
-                $updatedResult = $this->getContentObjectResolver()->getValue($updatedObject, $fieldNameAndPath, $updatedFieldName, $language);
197
-                if (is_array($updatedResult)) {
198
-                    $_updatedResult = []; // reset result set.
199
-
200
-                    /** @var Content $contentObject */
201
-                    foreach ($updatedResult as $contentObject) {
202
-                        $labelField = Tca::table($contentObject)->getLabelField();
203
-                        $values = array(
204
-                            'uid' => $contentObject->getUid(),
205
-                            'name' => $contentObject[$labelField],
206
-                        );
207
-                        $_updatedResult[] = $values;
208
-                    }
209
-
210
-                    $updatedResult = $_updatedResult;
211
-                }
212
-
213
-                $labelField = Tca::table($object)->getLabelField();
214
-
215
-                $processedObjectData = array(
216
-                    'uid' => $object->getUid(),
217
-                    'name' => $object[$labelField],
218
-                    'updatedField' => $fieldNameAndPath,
219
-                    'updatedValue' => $updatedResult,
220
-                );
221
-                $result->setProcessedObject($processedObjectData);
222
-
223
-                if (!empty($columns)) {
224
-                    /** @var Row $row */
225
-                    $row = GeneralUtility::makeInstance(Row::class, $columns);
226
-                    $result->setRow($row->render($updatedObject));
227
-                }
228
-            }
229
-        }
230
-
231
-        $response = $this->responseFactory->createResponse()
232
-            ->withHeader('Content-Type', 'application/json; charset=utf-8');
233
-        $response->getBody()->write(json_encode($result));
234
-        return $response;
235
-    }
236
-
237
-    /**
238
-     * Set the sorting of a record giving the previous object.
239
-     *
240
-     * @param array $matches
241
-     * @param int $previousIdentifier
242
-     */
243
-    public function sortAction(array $matches = [], $previousIdentifier = null)
244
-    {
245
-
246
-        $matcher = MatcherObjectFactory::getInstance()->getMatcher($matches);
247
-
248
-        // Fetch objects via the Content Service.
249
-        $contentService = $this->getContentService()->findBy($matcher);
250
-
251
-        // Compute the label field name of the table.
252
-        $tableTitleField = Tca::table()->getLabelField();
253
-
254
-        // Get result object for storing data along the processing.
255
-        $result = $this->getJsonResult();
256
-        $result->setNumberOfObjects($contentService->getNumberOfObjects());
257
-
258
-        foreach ($contentService->getObjects() as $object) {
259
-
260
-            // Store the first object, so that the "action" message can be more explicit when deleting only one record.
261
-            if ($contentService->getNumberOfObjects() === 1) {
262
-                $tableTitleValue = $object[$tableTitleField];
263
-                $processedObjectData = array(
264
-                    'uid' => $object->getUid(),
265
-                    'name' => $tableTitleValue,
266
-                );
267
-                $result->setProcessedObject($processedObjectData);
268
-            }
269
-
270
-            // The $target corresponds to the pid to move the records to.
271
-            // It can also be a negative value in case of sorting. The negative value would be the uid of its predecessor.
272
-            $target = is_null($previousIdentifier) ? $object->getPid() : (-(int)$previousIdentifier);
273
-
274
-            // Work out the object.
275
-            ContentRepositoryFactory::getInstance()->move($object, $target);
276
-
277
-            // Get the possible error messages and store them.
278
-            $errorMessages = ContentRepositoryFactory::getInstance()->getErrorMessages();
279
-            $result->addErrorMessages($errorMessages);
280
-        }
281
-
282
-        $response = $this->responseFactory->createResponse()
283
-            ->withHeader('Content-Type', 'application/json; charset=utf-8');
284
-        $response->getBody()->write(json_encode($result));
285
-        return $response;
286
-    }
287
-
288
-    /**
289
-     * Returns an editing form for a given field name of a Content object.
290
-     * Argument $fieldNameAndPath corresponds to the field name to be edited.
291
-     * Important to notice it can contains a path, e.g. metadata.title and therefore must be analysed.
292
-     *
293
-     * Possible values for $matches, refer to method "updateAction".
294
-     *
295
-     * @param string $fieldNameAndPath
296
-     * @param array $matches
297
-     * @param bool $hasRecursiveSelection
298
-     * @throws \Exception
299
-     */
300
-    public function editAction($fieldNameAndPath, array $matches = [], $hasRecursiveSelection = false)
301
-    {
302
-
303
-        // Instantiate the Matcher object according different rules.
304
-        $matcher = MatcherObjectFactory::getInstance()->getMatcher($matches);
305
-
306
-        // Fetch objects via the Content Service.
307
-        $contentService = $this->getContentService()->findBy($matcher);
308
-
309
-        $dataType = $this->getFieldPathResolver()->getDataType($fieldNameAndPath);
310
-        $fieldName = $this->getFieldPathResolver()->stripFieldPath($fieldNameAndPath);
311
-
312
-        $fieldType = Tca::table($dataType)->field($fieldName)->getType();
313
-        $this->view->assign('fieldType', ucfirst($fieldType));
314
-        $this->view->assign('dataType', $dataType);
315
-        $this->view->assign('fieldName', $fieldName);
316
-        $this->view->assign('matches', $matches);
317
-        $this->view->assign('fieldNameAndPath', $fieldNameAndPath);
318
-        $this->view->assign('numberOfObjects', $contentService->getNumberOfObjects());
319
-        $this->view->assign('hasRecursiveSelection', $hasRecursiveSelection);
320
-        $this->view->assign('editWholeSelection', empty($matches['uid'])); // necessary??
321
-
322
-        // Fetch content and its relations.
323
-        if ($fieldType === FieldType::MULTISELECT) {
324
-
325
-            $object = ContentRepositoryFactory::getInstance()->findOneBy($matcher);
326
-            $identifier = $this->getContentObjectResolver()->getValue($object, $fieldNameAndPath, 'uid');
327
-            $dataType = $this->getContentObjectResolver()->getDataType($object, $fieldNameAndPath);
328
-
329
-            $content = ContentRepositoryFactory::getInstance($dataType)->findByUid($identifier);
330
-
331
-            // Makes sure the object was retrieved. Security!
332
-            if (!$content) {
333
-                $message = sprintf('I could not retrieved content object of type "%s" with identifier %s.', $dataType, $identifier);
334
-                throw new \Exception($message, 1402350182);
335
-            }
336
-
337
-            $relatedDataType = Tca::table($dataType)->field($fieldName)->getForeignTable();
338
-
339
-            // Initialize the matcher object.
340
-            /** @var Matcher $matcher */
341
-            $matcher = GeneralUtility::makeInstance(Matcher::class, [], $relatedDataType);
342
-
343
-            // Default ordering for related data type.
344
-            $defaultOrderings = Tca::table($relatedDataType)->getDefaultOrderings();
345
-            /** @var Order $order */
346
-            $defaultOrder = GeneralUtility::makeInstance(Order::class, $defaultOrderings);
347
-
348
-            // Fetch related contents
349
-            $relatedContents = ContentRepositoryFactory::getInstance($relatedDataType)->findBy($matcher, $defaultOrder);
350
-
351
-            if (Tca::table($dataType)->field($fieldName)->isRenderModeTree()) {
352
-
353
-                $fieldConfiguration = Tca::table($dataType)->field($fieldName)->getConfiguration();
354
-                $parentField = $fieldConfiguration['treeConfig']['parentField'];
355
-
356
-                $flatTree = [];
357
-                foreach ($relatedContents as $node) {
358
-                    $flatTree[$node->getUid()] = array(
359
-                        'item' => $node,
360
-                        'parent' => $node[$parentField] ? $node[$parentField]['uid'] : null,
361
-                    );
362
-                }
363
-
364
-                $tree = [];
365
-
366
-                // If leaves are selected without its parents selected, those are shown as parent
367
-                foreach ($flatTree as $id => &$flatNode) {
368
-                    if (!isset($flatTree[$flatNode['parent']])) {
369
-                        $flatNode['parent'] = null;
370
-                    }
371
-                }
372
-
373
-                foreach ($flatTree as $id => &$node) {
374
-                    if ($node['parent'] === null) {
375
-                        $tree[$id] = &$node;
376
-                    } else {
377
-                        $flatTree[$node['parent']]['children'][$id] = &$node;
378
-                    }
379
-                }
380
-
381
-                $relatedContents = $tree;
382
-            }
383
-
384
-            $this->view->assign('content', $content);
385
-            $this->view->assign('relatedContents', $relatedContents);
386
-            $this->view->assign('relatedDataType', $relatedDataType);
387
-            $this->view->assign('relatedContentTitle', Tca::table($relatedDataType)->getTitle());
388
-            $this->view->assign(
389
-                'renderMode',
390
-                Tca::table($dataType)->field($fieldName)->isRenderModeTree() ? FieldType::TREE : null
391
-            );
392
-        }
393
-    }
394
-
395
-    /**
396
-     * Retrieve Content objects first according to matching criteria and then "delete" them.
397
-     *
398
-     * Possible values for $matches, refer to method "updateAction".
399
-     *
400
-     * @param array $matches
401
-     */
402
-    public function deleteAction(array $matches = [])
403
-    {
404
-
405
-        $matcher = MatcherObjectFactory::getInstance()->getMatcher($matches);
406
-
407
-        // Fetch objects via the Content Service.
408
-        $contentService = $this->getContentService()->findBy($matcher);
409
-
410
-        // Compute the label field name of the table.
411
-        $tableTitleField = Tca::table()->getLabelField();
412
-
413
-        // Get result object for storing data along the processing.
414
-        $result = $this->getJsonResult();
415
-        $result->setNumberOfObjects($contentService->getNumberOfObjects());
416
-
417
-        foreach ($contentService->getObjects() as $object) {
418
-
419
-            // Store the first object, so that the delete message can be more explicit when deleting only one record.
420
-            if ($contentService->getNumberOfObjects() === 1) {
421
-                $tableTitleValue = $object[$tableTitleField];
422
-                $processedObjectData = array(
423
-                    'uid' => $object->getUid(),
424
-                    'name' => $tableTitleValue,
425
-                );
426
-                $result->setProcessedObject($processedObjectData);
427
-            }
428
-
429
-            // Properly delete object.
430
-            ContentRepositoryFactory::getInstance()->remove($object);
431
-
432
-            // Get the possible error messages and store them.
433
-            $errorMessages = ContentRepositoryFactory::getInstance()->getErrorMessages();
434
-            $result->addErrorMessages($errorMessages);
435
-        }
436
-
437
-        $response = $this->responseFactory->createResponse()
438
-            ->withHeader('Content-Type', 'application/json; charset=utf-8');
439
-        $response->getBody()->write(json_encode($result));
440
-        return $response;
441
-    }
442
-
443
-    /**
444
-     * Retrieve Content objects first according to matching criteria and then "copy" them.
445
-     *
446
-     * Possible values for $matches, refer to method "updateAction".
447
-     *
448
-     * @param string $target
449
-     * @param array $matches
450
-     * @throws \Exception
451
-     * @return string
452
-     */
453
-    public function copyAction($target, array $matches = [])
454
-    {
455
-        // @todo
456
-        throw new \Exception('Not yet implemented', 1410192546);
457
-    }
458
-
459
-    /**
460
-     * Retrieve Content objects from the Clipboard then "copy" them according to the target.
461
-     *
462
-     * @param string $target
463
-     * @throws \Exception
464
-     */
465
-    public function copyClipboardAction($target)
466
-    {
467
-
468
-        // Retrieve matcher object from clipboard.
469
-        $matcher = $this->getClipboardService()->getMatcher();
470
-
471
-        // Fetch objects via the Content Service.
472
-        $contentService = $this->getContentService()->findBy($matcher);
473
-
474
-        // Compute the label field name of the table.
475
-        $tableTitleField = Tca::table()->getLabelField();
476
-
477
-        // Get result object for storing data along the processing.
478
-        $result = $this->getJsonResult();
479
-        $result->setNumberOfObjects($contentService->getNumberOfObjects());
480
-
481
-        foreach ($contentService->getObjects() as $object) {
482
-
483
-            // Store the first object, so that the "action" message can be more explicit when deleting only one record.
484
-            if ($contentService->getNumberOfObjects() === 1) {
485
-                $tableTitleValue = $object[$tableTitleField];
486
-                $processedObjectData = array(
487
-                    'uid' => $object->getUid(),
488
-                    'name' => $tableTitleValue,
489
-                );
490
-                $result->setProcessedObject($processedObjectData);
491
-            }
492
-
493
-            // Work out the object.
494
-            ContentRepositoryFactory::getInstance()->copy($object, $target);
495
-
496
-            // Get the possible error messages and store them.
497
-            $errorMessages = ContentRepositoryFactory::getInstance()->getErrorMessages();
498
-            $result->addErrorMessages($errorMessages);
499
-        }
500
-
501
-        // Flush Clipboard if told so.
502
-        if (GeneralUtility::_GP('flushClipboard')) {
503
-            $this->getClipboardService()->flush();
504
-        }
505
-
506
-        $response = $this->responseFactory->createResponse()
507
-            ->withHeader('Content-Type', 'application/json; charset=utf-8');
508
-        $response->getBody()->write(json_encode($result));
509
-        return $response;
510
-    }
511
-
512
-    /**
513
-     * Retrieve Content objects first according to matching criteria and then "move" them.
514
-     *
515
-     * Possible values for $matches, refer to method "updateAction".
516
-     *
517
-     * @param string $target
518
-     * @param array $matches
519
-     */
520
-    public function moveAction($target, array $matches = [])
521
-    {
522
-
523
-        $matcher = MatcherObjectFactory::getInstance()->getMatcher($matches);
524
-
525
-        // Fetch objects via the Content Service.
526
-        $contentService = $this->getContentService()->findBy($matcher);
527
-
528
-        // Compute the label field name of the table.
529
-        $tableTitleField = Tca::table()->getLabelField();
530
-
531
-        // Get result object for storing data along the processing.
532
-        $result = $this->getJsonResult();
533
-        $result->setNumberOfObjects($contentService->getNumberOfObjects());
534
-
535
-        foreach ($contentService->getObjects() as $object) {
536
-
537
-            // Store the first object, so that the "action" message can be more explicit when deleting only one record.
538
-            if ($contentService->getNumberOfObjects() === 1) {
539
-                $tableTitleValue = $object[$tableTitleField];
540
-                $processedObjectData = array(
541
-                    'uid' => $object->getUid(),
542
-                    'name' => $tableTitleValue,
543
-                );
544
-                $result->setProcessedObject($processedObjectData);
545
-            }
546
-
547
-            // Work out the object.
548
-            ContentRepositoryFactory::getInstance()->move($object, $target);
549
-
550
-            // Get the possible error messages and store them.
551
-            $errorMessages = ContentRepositoryFactory::getInstance()->getErrorMessages();
552
-            $result->addErrorMessages($errorMessages);
553
-        }
554
-
555
-        $response = $this->responseFactory->createResponse()
556
-            ->withHeader('Content-Type', 'application/json; charset=utf-8');
557
-        $response->getBody()->write(json_encode($result));
558
-        return $response;
559
-    }
560
-
561
-    /**
562
-     * Retrieve Content objects from the Clipboard then "move" them according to the target.
563
-     *
564
-     * @param string $target
565
-     */
566
-    public function moveClipboardAction($target)
567
-    {
568
-
569
-        // Retrieve matcher object from clipboard.
570
-        $matcher = $this->getClipboardService()->getMatcher();
571
-
572
-        // Fetch objects via the Content Service.
573
-        $contentService = $this->getContentService()->findBy($matcher);
574
-
575
-        // Compute the label field name of the table.
576
-        $tableTitleField = Tca::table()->getLabelField();
577
-
578
-        // Get result object for storing data along the processing.
579
-        $result = $this->getJsonResult();
580
-        $result->setNumberOfObjects($contentService->getNumberOfObjects());
581
-
582
-        foreach ($contentService->getObjects() as $object) {
583
-
584
-            // Store the first object, so that the "action" message can be more explicit when deleting only one record.
585
-            if ($contentService->getNumberOfObjects() === 1) {
586
-                $tableTitleValue = $object[$tableTitleField];
587
-                $processedObjectData = array(
588
-                    'uid' => $object->getUid(),
589
-                    'name' => $tableTitleValue,
590
-                );
591
-                $result->setProcessedObject($processedObjectData);
592
-            }
593
-
594
-            // Work out the object.
595
-            ContentRepositoryFactory::getInstance()->move($object, $target);
596
-
597
-            // Get the possible error messages and store them.
598
-            $errorMessages = ContentRepositoryFactory::getInstance()->getErrorMessages();
599
-            $result->addErrorMessages($errorMessages);
600
-        }
601
-
602
-        // Flush Clipboard if told so.
603
-        if (GeneralUtility::_GP('flushClipboard')) {
604
-            $this->getClipboardService()->flush();
605
-        }
606
-
607
-        $response = $this->responseFactory->createResponse()
608
-            ->withHeader('Content-Type', 'application/json; charset=utf-8');
609
-        $response->getBody()->write(json_encode($result));
610
-        return $response;
611
-    }
612
-
613
-    /**
614
-     * Retrieve Content objects first according to matching criteria and then "localize" them.
615
-     *
616
-     * Possible values for $matches, refer to method "updateAction".
617
-     *
618
-     * @param string $fieldNameAndPath
619
-     * @param array $matches
620
-     * @param int $language
621
-     * @throws \Exception
622
-     */
623
-    public function localizeAction($fieldNameAndPath, array $matches = [], $language = 0)
624
-    {
625
-
626
-        $matcher = MatcherObjectFactory::getInstance()->getMatcher($matches);
627
-
628
-        // Fetch objects via the Content Service.
629
-        $contentService = $this->getContentService()->findBy($matcher);
630
-
631
-        // Get result object for storing data along the processing.
632
-        $result = $this->getJsonResult();
633
-        $result->setNumberOfObjects($contentService->getNumberOfObjects());
634
-
635
-        foreach ($contentService->getObjects() as $object) {
636
-
637
-            $identifier = $this->getContentObjectResolver()->getValue($object, $fieldNameAndPath, 'uid');
638
-            $dataType = $this->getContentObjectResolver()->getDataType($object, $fieldNameAndPath);
639
-
640
-            // Fetch the source object to be localized.
641
-            /** @var Content $content */
642
-            $content = ContentRepositoryFactory::getInstance($dataType)->findByIdentifier($identifier);
643
-
644
-            // Makes sure the object was retrieved. Security!
645
-            if (!$content) {
646
-                $message = sprintf('Something went wrong when retrieving content "%s" with identifier "%s".', $dataType, $identifier);
647
-                throw new \Exception($message, 1412343097);
648
-            }
649
-
650
-            // Handover the localization to the Repository.
651
-            ContentRepositoryFactory::getInstance($dataType)->localize($content, $language);
652
-
653
-            // Get the possible error messages and store them.
654
-            $errorMessages = ContentRepositoryFactory::getInstance()->getErrorMessages();
655
-
656
-            // Redirect to TCEForm so that the BE User can do its job!
657
-            if ($contentService->getNumberOfObjects() === 1) {
658
-
659
-                if (!empty($errorMessages)) {
660
-                    $message = sprintf('Something went wrong when localizing content "%s" with identifier "%s". <br/>%s',
661
-                        $dataType,
662
-                        $identifier,
663
-                        implode('<br/>', $errorMessages)
664
-                    );
665
-                    throw new \Exception($message, 1412343098);
666
-                }
667
-
668
-                $localizedContent = $this->getLanguageService()->getLocalizedContent($content, $language);
669
-                if (empty($localizedContent)) {
670
-                    $message = sprintf('Oups! I could not retrieve localized content of type "%s" with identifier "%s"',
671
-                        $content->getDataType(),
672
-                        $content->getUid()
673
-                    );
674
-                    throw new \Exception($message, 1412343099);
675
-                }
676
-
677
-                /** @var EditUri $uri */
678
-                $uriRenderer = GeneralUtility::makeInstance(EditUri::class);
679
-                $uri = $uriRenderer->render($localizedContent);
680
-                HttpUtility::redirect($uri);
681
-                break; // no need to further continue
682
-            }
683
-
684
-            $result->addErrorMessages($errorMessages);
685
-        }
686
-
687
-        $response = $this->responseFactory->createResponse()
688
-            ->withHeader('Content-Type', 'application/json; charset=utf-8');
689
-        $response->getBody()->write(json_encode($result));
690
-        return $response;
691
-    }
692
-
693
-    /**
694
-     * Get the Vidi Module Loader.
695
-     *
696
-     * @return ContentService
697
-     */
698
-    protected function getContentService()
699
-    {
700
-        return GeneralUtility::makeInstance(ContentService::class);
701
-    }
702
-
703
-    /**
704
-     * @return ContentObjectResolver
705
-     */
706
-    protected function getContentObjectResolver()
707
-    {
708
-        return GeneralUtility::makeInstance(ContentObjectResolver::class);
709
-    }
710
-
711
-    /**
712
-     * @return FieldPathResolver
713
-     */
714
-    protected function getFieldPathResolver()
715
-    {
716
-        return GeneralUtility::makeInstance(FieldPathResolver::class);
717
-    }
718
-
719
-    /**
720
-     * @return JsonResult|object
721
-     */
722
-    protected function getJsonResult()
723
-    {
724
-        return GeneralUtility::makeInstance(JsonResult::class);
725
-    }
726
-
727
-    /**
728
-     * Signal that is called for post-processing content data send to the server for update.
729
-     *
730
-     * @param Content $contentObject
731
-     * @param $fieldNameAndPath
732
-     * @param $contentData
733
-     * @param $counter
734
-     * @param $savingBehavior
735
-     * @param $language
736
-     * @return ProcessContentDataSignalArguments
737
-     */
738
-    protected function emitProcessContentDataSignal(Content $contentObject, $fieldNameAndPath, $contentData, $counter, $savingBehavior, $language)
739
-    {
740
-
741
-        /** @var ProcessContentDataSignalArguments $signalArguments */
742
-        $signalArguments = GeneralUtility::makeInstance(ProcessContentDataSignalArguments::class);
743
-        $signalArguments->setContentObject($contentObject)
744
-            ->setFieldNameAndPath($fieldNameAndPath)
745
-            ->setContentData($contentData)
746
-            ->setCounter($counter)
747
-            ->setSavingBehavior($savingBehavior)
748
-            ->setLanguage($language);
749
-
750
-        $signalResult = $this->getSignalSlotDispatcher()->dispatch('Fab\Vidi\Controller\Backend\ContentController', 'processContentData', array($signalArguments));
751
-        return $signalResult[0];
752
-    }
753
-
754
-    /**
755
-     * Get the SignalSlot dispatcher.
756
-     *
757
-     * @return Dispatcher
758
-     */
759
-    protected function getSignalSlotDispatcher()
760
-    {
761
-        return $this->objectManager->get(Dispatcher::class);
762
-    }
763
-
764
-    /**
765
-     * Get the Clipboard service.
766
-     *
767
-     * @return ClipboardService
768
-     */
769
-    protected function getClipboardService()
770
-    {
771
-        return GeneralUtility::makeInstance(ClipboardService::class);
772
-    }
773
-
774
-    /**
775
-     * @return LanguageService
776
-     */
777
-    protected function getLanguageService()
778
-    {
779
-        return GeneralUtility::makeInstance(LanguageService::class);
780
-    }
781
-
782
-    /**
783
-     * Get the Vidi Module Loader.
784
-     *
785
-     * @return ModuleLoader
786
-     */
787
-    protected function getModuleLoader()
788
-    {
789
-        return GeneralUtility::makeInstance(ModuleLoader::class);
790
-    }
48
+	/**
49
+	 * @var SelectionRepository
50
+	 * @Inject
51
+	 */
52
+	public $selectionRepository;
53
+
54
+	/**
55
+	 * Initialize every action.
56
+	 */
57
+	public function initializeAction()
58
+	{
59
+		$pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
60
+		$pageRenderer->addInlineLanguageLabelFile('EXT:vidi/Resources/Private/Language/locallang.xlf');
61
+
62
+		// Configure property mapping to retrieve the file object.
63
+		if ($this->arguments->hasArgument('columns')) {
64
+
65
+			/** @var CsvToArrayConverter $typeConverter */
66
+			$typeConverter = $this->objectManager->get(CsvToArrayConverter::class);
67
+
68
+			$propertyMappingConfiguration = $this->arguments->getArgument('columns')->getPropertyMappingConfiguration();
69
+			$propertyMappingConfiguration->setTypeConverter($typeConverter);
70
+		}
71
+	}
72
+
73
+	/**
74
+	 * List action for this controller.
75
+	 *
76
+	 * @return void
77
+	 */
78
+	public function indexAction()
79
+	{
80
+		$dataType = $this->getModuleLoader()->getDataType();
81
+		$selections = $this->selectionRepository->findByDataTypeForCurrentBackendUser($dataType);
82
+		$this->view->assign('selections', $selections);
83
+
84
+		$columns = Tca::grid()->getFields();
85
+		$this->view->assign('columns', $columns);
86
+		$this->view->assign('numberOfColumns', count($columns));
87
+	}
88
+
89
+	/**
90
+	 * List Row action for this controller. Output a json list of contents
91
+	 *
92
+	 * @param array $columns corresponds to columns to be rendered.
93
+	 * @param array $matches
94
+	 * @Validate("Fab\Vidi\Domain\Validator\ColumnsValidator", param="columns")
95
+	 * @Validate("Fab\Vidi\Domain\Validator\MatchesValidator", param="matches")
96
+	 * @return void
97
+	 */
98
+	public function listAction(array $columns = [], $matches = [])
99
+	{
100
+		// Initialize some objects related to the query.
101
+		$matcher = MatcherObjectFactory::getInstance()->getMatcher($matches);
102
+		$order = OrderObjectFactory::getInstance()->getOrder();
103
+		$pager = PagerObjectFactory::getInstance()->getPager();
104
+
105
+		// Fetch objects via the Content Service.
106
+		$contentService = $this->getContentService()->findBy($matcher, $order, $pager->getLimit(), $pager->getOffset());
107
+		$pager->setCount($contentService->getNumberOfObjects());
108
+
109
+		// Assign values.
110
+		$this->view->assign('columns', $columns);
111
+		$this->view->assign('objects', $contentService->getObjects());
112
+		$this->view->assign('numberOfObjects', $contentService->getNumberOfObjects());
113
+		$this->view->assign('pager', $pager);
114
+
115
+		$this->view->assign('response', $this->responseFactory->createResponse());
116
+	}
117
+
118
+	/**
119
+	 * Retrieve Content objects first according to matching criteria and then "update" them.
120
+	 * Important to notice the field name can contains a path, e.g. metadata.title and therefore must be analysed.
121
+	 *
122
+	 * Possible values for $matches:
123
+	 * -----------------------------
124
+	 *
125
+	 * $matches = array(uid => 1), will be taken as $query->equals
126
+	 * $matches = array(uid => 1,2,3), will be taken as $query->in
127
+	 * $matches = array(field_name1 => bar, field_name2 => bax), will be separated by AND.
128
+	 *
129
+	 * Possible values for $content:
130
+	 * -----------------------------
131
+	 *
132
+	 * $content = array(field_name => bar)
133
+	 * $content = array(field_name => array(value1, value2)) <-- will be CSV converted by "value1,value2"
134
+	 *
135
+	 * @param string $fieldNameAndPath
136
+	 * @param array $content
137
+	 * @param array $matches
138
+	 * @param string $savingBehavior
139
+	 * @param int $language
140
+	 * @param array $columns
141
+	 * @throws InvalidKeyInArrayException
142
+	 */
143
+	public function updateAction($fieldNameAndPath, array $content, array $matches = [], $savingBehavior = SavingBehavior::REPLACE, $language = 0, $columns = [])
144
+	{
145
+
146
+		// Instantiate the Matcher object according different rules.
147
+		$matcher = MatcherObjectFactory::getInstance()->getMatcher($matches);
148
+		$order = OrderObjectFactory::getInstance()->getOrder();
149
+
150
+		// Fetch objects via the Content Service.
151
+		$contentService = $this->getContentService()->findBy($matcher, $order);
152
+
153
+		// Get the real field that is going to be updated.
154
+		$updatedFieldName = $this->getFieldPathResolver()->stripFieldPath($fieldNameAndPath);
155
+
156
+		// Get result object for storing data along the processing.
157
+		$result = $this->getJsonResult();
158
+		$result->setNumberOfObjects($contentService->getNumberOfObjects());
159
+
160
+		foreach ($contentService->getObjects() as $index => $object) {
161
+
162
+			$identifier = $this->getContentObjectResolver()->getValue($object, $fieldNameAndPath, 'uid', $language);
163
+
164
+			// It could be the identifier is not found because the translation
165
+			// of the record does not yet exist when mass-editing
166
+			if ((int)$identifier <= 0) {
167
+				continue;
168
+			}
169
+
170
+			$dataType = $this->getContentObjectResolver()->getDataType($object, $fieldNameAndPath);
171
+
172
+			$signalResult = $this->emitProcessContentDataSignal($object, $fieldNameAndPath, $content, $index + 1, $savingBehavior, $language);
173
+			$contentData = $signalResult->getContentData();
174
+
175
+			// Add identifier to content data, required by TCEMain.
176
+			$contentData['uid'] = $identifier;
177
+
178
+			/** @var Content $dataObject */
179
+			$dataObject = GeneralUtility::makeInstance(Content::class, $dataType, $contentData);
180
+
181
+			// Properly update object.
182
+			ContentRepositoryFactory::getInstance($dataType)->update($dataObject);
183
+
184
+			// Get the possible error messages and store them.
185
+			$errorMessages = ContentRepositoryFactory::getInstance()->getErrorMessages();
186
+			$result->addErrorMessages($errorMessages);
187
+
188
+			// We only want to see the detail result if there is one object updated.
189
+			// Required for inline editing + it will display some useful info on the GUI in the flash messages.
190
+			if ($contentService->getNumberOfObjects() === 1) {
191
+
192
+				// Fetch the updated object from repository.
193
+				$updatedObject = ContentRepositoryFactory::getInstance()->findByUid($object->getUid());
194
+
195
+				// Re-fetch the updated result.
196
+				$updatedResult = $this->getContentObjectResolver()->getValue($updatedObject, $fieldNameAndPath, $updatedFieldName, $language);
197
+				if (is_array($updatedResult)) {
198
+					$_updatedResult = []; // reset result set.
199
+
200
+					/** @var Content $contentObject */
201
+					foreach ($updatedResult as $contentObject) {
202
+						$labelField = Tca::table($contentObject)->getLabelField();
203
+						$values = array(
204
+							'uid' => $contentObject->getUid(),
205
+							'name' => $contentObject[$labelField],
206
+						);
207
+						$_updatedResult[] = $values;
208
+					}
209
+
210
+					$updatedResult = $_updatedResult;
211
+				}
212
+
213
+				$labelField = Tca::table($object)->getLabelField();
214
+
215
+				$processedObjectData = array(
216
+					'uid' => $object->getUid(),
217
+					'name' => $object[$labelField],
218
+					'updatedField' => $fieldNameAndPath,
219
+					'updatedValue' => $updatedResult,
220
+				);
221
+				$result->setProcessedObject($processedObjectData);
222
+
223
+				if (!empty($columns)) {
224
+					/** @var Row $row */
225
+					$row = GeneralUtility::makeInstance(Row::class, $columns);
226
+					$result->setRow($row->render($updatedObject));
227
+				}
228
+			}
229
+		}
230
+
231
+		$response = $this->responseFactory->createResponse()
232
+			->withHeader('Content-Type', 'application/json; charset=utf-8');
233
+		$response->getBody()->write(json_encode($result));
234
+		return $response;
235
+	}
236
+
237
+	/**
238
+	 * Set the sorting of a record giving the previous object.
239
+	 *
240
+	 * @param array $matches
241
+	 * @param int $previousIdentifier
242
+	 */
243
+	public function sortAction(array $matches = [], $previousIdentifier = null)
244
+	{
245
+
246
+		$matcher = MatcherObjectFactory::getInstance()->getMatcher($matches);
247
+
248
+		// Fetch objects via the Content Service.
249
+		$contentService = $this->getContentService()->findBy($matcher);
250
+
251
+		// Compute the label field name of the table.
252
+		$tableTitleField = Tca::table()->getLabelField();
253
+
254
+		// Get result object for storing data along the processing.
255
+		$result = $this->getJsonResult();
256
+		$result->setNumberOfObjects($contentService->getNumberOfObjects());
257
+
258
+		foreach ($contentService->getObjects() as $object) {
259
+
260
+			// Store the first object, so that the "action" message can be more explicit when deleting only one record.
261
+			if ($contentService->getNumberOfObjects() === 1) {
262
+				$tableTitleValue = $object[$tableTitleField];
263
+				$processedObjectData = array(
264
+					'uid' => $object->getUid(),
265
+					'name' => $tableTitleValue,
266
+				);
267
+				$result->setProcessedObject($processedObjectData);
268
+			}
269
+
270
+			// The $target corresponds to the pid to move the records to.
271
+			// It can also be a negative value in case of sorting. The negative value would be the uid of its predecessor.
272
+			$target = is_null($previousIdentifier) ? $object->getPid() : (-(int)$previousIdentifier);
273
+
274
+			// Work out the object.
275
+			ContentRepositoryFactory::getInstance()->move($object, $target);
276
+
277
+			// Get the possible error messages and store them.
278
+			$errorMessages = ContentRepositoryFactory::getInstance()->getErrorMessages();
279
+			$result->addErrorMessages($errorMessages);
280
+		}
281
+
282
+		$response = $this->responseFactory->createResponse()
283
+			->withHeader('Content-Type', 'application/json; charset=utf-8');
284
+		$response->getBody()->write(json_encode($result));
285
+		return $response;
286
+	}
287
+
288
+	/**
289
+	 * Returns an editing form for a given field name of a Content object.
290
+	 * Argument $fieldNameAndPath corresponds to the field name to be edited.
291
+	 * Important to notice it can contains a path, e.g. metadata.title and therefore must be analysed.
292
+	 *
293
+	 * Possible values for $matches, refer to method "updateAction".
294
+	 *
295
+	 * @param string $fieldNameAndPath
296
+	 * @param array $matches
297
+	 * @param bool $hasRecursiveSelection
298
+	 * @throws \Exception
299
+	 */
300
+	public function editAction($fieldNameAndPath, array $matches = [], $hasRecursiveSelection = false)
301
+	{
302
+
303
+		// Instantiate the Matcher object according different rules.
304
+		$matcher = MatcherObjectFactory::getInstance()->getMatcher($matches);
305
+
306
+		// Fetch objects via the Content Service.
307
+		$contentService = $this->getContentService()->findBy($matcher);
308
+
309
+		$dataType = $this->getFieldPathResolver()->getDataType($fieldNameAndPath);
310
+		$fieldName = $this->getFieldPathResolver()->stripFieldPath($fieldNameAndPath);
311
+
312
+		$fieldType = Tca::table($dataType)->field($fieldName)->getType();
313
+		$this->view->assign('fieldType', ucfirst($fieldType));
314
+		$this->view->assign('dataType', $dataType);
315
+		$this->view->assign('fieldName', $fieldName);
316
+		$this->view->assign('matches', $matches);
317
+		$this->view->assign('fieldNameAndPath', $fieldNameAndPath);
318
+		$this->view->assign('numberOfObjects', $contentService->getNumberOfObjects());
319
+		$this->view->assign('hasRecursiveSelection', $hasRecursiveSelection);
320
+		$this->view->assign('editWholeSelection', empty($matches['uid'])); // necessary??
321
+
322
+		// Fetch content and its relations.
323
+		if ($fieldType === FieldType::MULTISELECT) {
324
+
325
+			$object = ContentRepositoryFactory::getInstance()->findOneBy($matcher);
326
+			$identifier = $this->getContentObjectResolver()->getValue($object, $fieldNameAndPath, 'uid');
327
+			$dataType = $this->getContentObjectResolver()->getDataType($object, $fieldNameAndPath);
328
+
329
+			$content = ContentRepositoryFactory::getInstance($dataType)->findByUid($identifier);
330
+
331
+			// Makes sure the object was retrieved. Security!
332
+			if (!$content) {
333
+				$message = sprintf('I could not retrieved content object of type "%s" with identifier %s.', $dataType, $identifier);
334
+				throw new \Exception($message, 1402350182);
335
+			}
336
+
337
+			$relatedDataType = Tca::table($dataType)->field($fieldName)->getForeignTable();
338
+
339
+			// Initialize the matcher object.
340
+			/** @var Matcher $matcher */
341
+			$matcher = GeneralUtility::makeInstance(Matcher::class, [], $relatedDataType);
342
+
343
+			// Default ordering for related data type.
344
+			$defaultOrderings = Tca::table($relatedDataType)->getDefaultOrderings();
345
+			/** @var Order $order */
346
+			$defaultOrder = GeneralUtility::makeInstance(Order::class, $defaultOrderings);
347
+
348
+			// Fetch related contents
349
+			$relatedContents = ContentRepositoryFactory::getInstance($relatedDataType)->findBy($matcher, $defaultOrder);
350
+
351
+			if (Tca::table($dataType)->field($fieldName)->isRenderModeTree()) {
352
+
353
+				$fieldConfiguration = Tca::table($dataType)->field($fieldName)->getConfiguration();
354
+				$parentField = $fieldConfiguration['treeConfig']['parentField'];
355
+
356
+				$flatTree = [];
357
+				foreach ($relatedContents as $node) {
358
+					$flatTree[$node->getUid()] = array(
359
+						'item' => $node,
360
+						'parent' => $node[$parentField] ? $node[$parentField]['uid'] : null,
361
+					);
362
+				}
363
+
364
+				$tree = [];
365
+
366
+				// If leaves are selected without its parents selected, those are shown as parent
367
+				foreach ($flatTree as $id => &$flatNode) {
368
+					if (!isset($flatTree[$flatNode['parent']])) {
369
+						$flatNode['parent'] = null;
370
+					}
371
+				}
372
+
373
+				foreach ($flatTree as $id => &$node) {
374
+					if ($node['parent'] === null) {
375
+						$tree[$id] = &$node;
376
+					} else {
377
+						$flatTree[$node['parent']]['children'][$id] = &$node;
378
+					}
379
+				}
380
+
381
+				$relatedContents = $tree;
382
+			}
383
+
384
+			$this->view->assign('content', $content);
385
+			$this->view->assign('relatedContents', $relatedContents);
386
+			$this->view->assign('relatedDataType', $relatedDataType);
387
+			$this->view->assign('relatedContentTitle', Tca::table($relatedDataType)->getTitle());
388
+			$this->view->assign(
389
+				'renderMode',
390
+				Tca::table($dataType)->field($fieldName)->isRenderModeTree() ? FieldType::TREE : null
391
+			);
392
+		}
393
+	}
394
+
395
+	/**
396
+	 * Retrieve Content objects first according to matching criteria and then "delete" them.
397
+	 *
398
+	 * Possible values for $matches, refer to method "updateAction".
399
+	 *
400
+	 * @param array $matches
401
+	 */
402
+	public function deleteAction(array $matches = [])
403
+	{
404
+
405
+		$matcher = MatcherObjectFactory::getInstance()->getMatcher($matches);
406
+
407
+		// Fetch objects via the Content Service.
408
+		$contentService = $this->getContentService()->findBy($matcher);
409
+
410
+		// Compute the label field name of the table.
411
+		$tableTitleField = Tca::table()->getLabelField();
412
+
413
+		// Get result object for storing data along the processing.
414
+		$result = $this->getJsonResult();
415
+		$result->setNumberOfObjects($contentService->getNumberOfObjects());
416
+
417
+		foreach ($contentService->getObjects() as $object) {
418
+
419
+			// Store the first object, so that the delete message can be more explicit when deleting only one record.
420
+			if ($contentService->getNumberOfObjects() === 1) {
421
+				$tableTitleValue = $object[$tableTitleField];
422
+				$processedObjectData = array(
423
+					'uid' => $object->getUid(),
424
+					'name' => $tableTitleValue,
425
+				);
426
+				$result->setProcessedObject($processedObjectData);
427
+			}
428
+
429
+			// Properly delete object.
430
+			ContentRepositoryFactory::getInstance()->remove($object);
431
+
432
+			// Get the possible error messages and store them.
433
+			$errorMessages = ContentRepositoryFactory::getInstance()->getErrorMessages();
434
+			$result->addErrorMessages($errorMessages);
435
+		}
436
+
437
+		$response = $this->responseFactory->createResponse()
438
+			->withHeader('Content-Type', 'application/json; charset=utf-8');
439
+		$response->getBody()->write(json_encode($result));
440
+		return $response;
441
+	}
442
+
443
+	/**
444
+	 * Retrieve Content objects first according to matching criteria and then "copy" them.
445
+	 *
446
+	 * Possible values for $matches, refer to method "updateAction".
447
+	 *
448
+	 * @param string $target
449
+	 * @param array $matches
450
+	 * @throws \Exception
451
+	 * @return string
452
+	 */
453
+	public function copyAction($target, array $matches = [])
454
+	{
455
+		// @todo
456
+		throw new \Exception('Not yet implemented', 1410192546);
457
+	}
458
+
459
+	/**
460
+	 * Retrieve Content objects from the Clipboard then "copy" them according to the target.
461
+	 *
462
+	 * @param string $target
463
+	 * @throws \Exception
464
+	 */
465
+	public function copyClipboardAction($target)
466
+	{
467
+
468
+		// Retrieve matcher object from clipboard.
469
+		$matcher = $this->getClipboardService()->getMatcher();
470
+
471
+		// Fetch objects via the Content Service.
472
+		$contentService = $this->getContentService()->findBy($matcher);
473
+
474
+		// Compute the label field name of the table.
475
+		$tableTitleField = Tca::table()->getLabelField();
476
+
477
+		// Get result object for storing data along the processing.
478
+		$result = $this->getJsonResult();
479
+		$result->setNumberOfObjects($contentService->getNumberOfObjects());
480
+
481
+		foreach ($contentService->getObjects() as $object) {
482
+
483
+			// Store the first object, so that the "action" message can be more explicit when deleting only one record.
484
+			if ($contentService->getNumberOfObjects() === 1) {
485
+				$tableTitleValue = $object[$tableTitleField];
486
+				$processedObjectData = array(
487
+					'uid' => $object->getUid(),
488
+					'name' => $tableTitleValue,
489
+				);
490
+				$result->setProcessedObject($processedObjectData);
491
+			}
492
+
493
+			// Work out the object.
494
+			ContentRepositoryFactory::getInstance()->copy($object, $target);
495
+
496
+			// Get the possible error messages and store them.
497
+			$errorMessages = ContentRepositoryFactory::getInstance()->getErrorMessages();
498
+			$result->addErrorMessages($errorMessages);
499
+		}
500
+
501
+		// Flush Clipboard if told so.
502
+		if (GeneralUtility::_GP('flushClipboard')) {
503
+			$this->getClipboardService()->flush();
504
+		}
505
+
506
+		$response = $this->responseFactory->createResponse()
507
+			->withHeader('Content-Type', 'application/json; charset=utf-8');
508
+		$response->getBody()->write(json_encode($result));
509
+		return $response;
510
+	}
511
+
512
+	/**
513
+	 * Retrieve Content objects first according to matching criteria and then "move" them.
514
+	 *
515
+	 * Possible values for $matches, refer to method "updateAction".
516
+	 *
517
+	 * @param string $target
518
+	 * @param array $matches
519
+	 */
520
+	public function moveAction($target, array $matches = [])
521
+	{
522
+
523
+		$matcher = MatcherObjectFactory::getInstance()->getMatcher($matches);
524
+
525
+		// Fetch objects via the Content Service.
526
+		$contentService = $this->getContentService()->findBy($matcher);
527
+
528
+		// Compute the label field name of the table.
529
+		$tableTitleField = Tca::table()->getLabelField();
530
+
531
+		// Get result object for storing data along the processing.
532
+		$result = $this->getJsonResult();
533
+		$result->setNumberOfObjects($contentService->getNumberOfObjects());
534
+
535
+		foreach ($contentService->getObjects() as $object) {
536
+
537
+			// Store the first object, so that the "action" message can be more explicit when deleting only one record.
538
+			if ($contentService->getNumberOfObjects() === 1) {
539
+				$tableTitleValue = $object[$tableTitleField];
540
+				$processedObjectData = array(
541
+					'uid' => $object->getUid(),
542
+					'name' => $tableTitleValue,
543
+				);
544
+				$result->setProcessedObject($processedObjectData);
545
+			}
546
+
547
+			// Work out the object.
548
+			ContentRepositoryFactory::getInstance()->move($object, $target);
549
+
550
+			// Get the possible error messages and store them.
551
+			$errorMessages = ContentRepositoryFactory::getInstance()->getErrorMessages();
552
+			$result->addErrorMessages($errorMessages);
553
+		}
554
+
555
+		$response = $this->responseFactory->createResponse()
556
+			->withHeader('Content-Type', 'application/json; charset=utf-8');
557
+		$response->getBody()->write(json_encode($result));
558
+		return $response;
559
+	}
560
+
561
+	/**
562
+	 * Retrieve Content objects from the Clipboard then "move" them according to the target.
563
+	 *
564
+	 * @param string $target
565
+	 */
566
+	public function moveClipboardAction($target)
567
+	{
568
+
569
+		// Retrieve matcher object from clipboard.
570
+		$matcher = $this->getClipboardService()->getMatcher();
571
+
572
+		// Fetch objects via the Content Service.
573
+		$contentService = $this->getContentService()->findBy($matcher);
574
+
575
+		// Compute the label field name of the table.
576
+		$tableTitleField = Tca::table()->getLabelField();
577
+
578
+		// Get result object for storing data along the processing.
579
+		$result = $this->getJsonResult();
580
+		$result->setNumberOfObjects($contentService->getNumberOfObjects());
581
+
582
+		foreach ($contentService->getObjects() as $object) {
583
+
584
+			// Store the first object, so that the "action" message can be more explicit when deleting only one record.
585
+			if ($contentService->getNumberOfObjects() === 1) {
586
+				$tableTitleValue = $object[$tableTitleField];
587
+				$processedObjectData = array(
588
+					'uid' => $object->getUid(),
589
+					'name' => $tableTitleValue,
590
+				);
591
+				$result->setProcessedObject($processedObjectData);
592
+			}
593
+
594
+			// Work out the object.
595
+			ContentRepositoryFactory::getInstance()->move($object, $target);
596
+
597
+			// Get the possible error messages and store them.
598
+			$errorMessages = ContentRepositoryFactory::getInstance()->getErrorMessages();
599
+			$result->addErrorMessages($errorMessages);
600
+		}
601
+
602
+		// Flush Clipboard if told so.
603
+		if (GeneralUtility::_GP('flushClipboard')) {
604
+			$this->getClipboardService()->flush();
605
+		}
606
+
607
+		$response = $this->responseFactory->createResponse()
608
+			->withHeader('Content-Type', 'application/json; charset=utf-8');
609
+		$response->getBody()->write(json_encode($result));
610
+		return $response;
611
+	}
612
+
613
+	/**
614
+	 * Retrieve Content objects first according to matching criteria and then "localize" them.
615
+	 *
616
+	 * Possible values for $matches, refer to method "updateAction".
617
+	 *
618
+	 * @param string $fieldNameAndPath
619
+	 * @param array $matches
620
+	 * @param int $language
621
+	 * @throws \Exception
622
+	 */
623
+	public function localizeAction($fieldNameAndPath, array $matches = [], $language = 0)
624
+	{
625
+
626
+		$matcher = MatcherObjectFactory::getInstance()->getMatcher($matches);
627
+
628
+		// Fetch objects via the Content Service.
629
+		$contentService = $this->getContentService()->findBy($matcher);
630
+
631
+		// Get result object for storing data along the processing.
632
+		$result = $this->getJsonResult();
633
+		$result->setNumberOfObjects($contentService->getNumberOfObjects());
634
+
635
+		foreach ($contentService->getObjects() as $object) {
636
+
637
+			$identifier = $this->getContentObjectResolver()->getValue($object, $fieldNameAndPath, 'uid');
638
+			$dataType = $this->getContentObjectResolver()->getDataType($object, $fieldNameAndPath);
639
+
640
+			// Fetch the source object to be localized.
641
+			/** @var Content $content */
642
+			$content = ContentRepositoryFactory::getInstance($dataType)->findByIdentifier($identifier);
643
+
644
+			// Makes sure the object was retrieved. Security!
645
+			if (!$content) {
646
+				$message = sprintf('Something went wrong when retrieving content "%s" with identifier "%s".', $dataType, $identifier);
647
+				throw new \Exception($message, 1412343097);
648
+			}
649
+
650
+			// Handover the localization to the Repository.
651
+			ContentRepositoryFactory::getInstance($dataType)->localize($content, $language);
652
+
653
+			// Get the possible error messages and store them.
654
+			$errorMessages = ContentRepositoryFactory::getInstance()->getErrorMessages();
655
+
656
+			// Redirect to TCEForm so that the BE User can do its job!
657
+			if ($contentService->getNumberOfObjects() === 1) {
658
+
659
+				if (!empty($errorMessages)) {
660
+					$message = sprintf('Something went wrong when localizing content "%s" with identifier "%s". <br/>%s',
661
+						$dataType,
662
+						$identifier,
663
+						implode('<br/>', $errorMessages)
664
+					);
665
+					throw new \Exception($message, 1412343098);
666
+				}
667
+
668
+				$localizedContent = $this->getLanguageService()->getLocalizedContent($content, $language);
669
+				if (empty($localizedContent)) {
670
+					$message = sprintf('Oups! I could not retrieve localized content of type "%s" with identifier "%s"',
671
+						$content->getDataType(),
672
+						$content->getUid()
673
+					);
674
+					throw new \Exception($message, 1412343099);
675
+				}
676
+
677
+				/** @var EditUri $uri */
678
+				$uriRenderer = GeneralUtility::makeInstance(EditUri::class);
679
+				$uri = $uriRenderer->render($localizedContent);
680
+				HttpUtility::redirect($uri);
681
+				break; // no need to further continue
682
+			}
683
+
684
+			$result->addErrorMessages($errorMessages);
685
+		}
686
+
687
+		$response = $this->responseFactory->createResponse()
688
+			->withHeader('Content-Type', 'application/json; charset=utf-8');
689
+		$response->getBody()->write(json_encode($result));
690
+		return $response;
691
+	}
692
+
693
+	/**
694
+	 * Get the Vidi Module Loader.
695
+	 *
696
+	 * @return ContentService
697
+	 */
698
+	protected function getContentService()
699
+	{
700
+		return GeneralUtility::makeInstance(ContentService::class);
701
+	}
702
+
703
+	/**
704
+	 * @return ContentObjectResolver
705
+	 */
706
+	protected function getContentObjectResolver()
707
+	{
708
+		return GeneralUtility::makeInstance(ContentObjectResolver::class);
709
+	}
710
+
711
+	/**
712
+	 * @return FieldPathResolver
713
+	 */
714
+	protected function getFieldPathResolver()
715
+	{
716
+		return GeneralUtility::makeInstance(FieldPathResolver::class);
717
+	}
718
+
719
+	/**
720
+	 * @return JsonResult|object
721
+	 */
722
+	protected function getJsonResult()
723
+	{
724
+		return GeneralUtility::makeInstance(JsonResult::class);
725
+	}
726
+
727
+	/**
728
+	 * Signal that is called for post-processing content data send to the server for update.
729
+	 *
730
+	 * @param Content $contentObject
731
+	 * @param $fieldNameAndPath
732
+	 * @param $contentData
733
+	 * @param $counter
734
+	 * @param $savingBehavior
735
+	 * @param $language
736
+	 * @return ProcessContentDataSignalArguments
737
+	 */
738
+	protected function emitProcessContentDataSignal(Content $contentObject, $fieldNameAndPath, $contentData, $counter, $savingBehavior, $language)
739
+	{
740
+
741
+		/** @var ProcessContentDataSignalArguments $signalArguments */
742
+		$signalArguments = GeneralUtility::makeInstance(ProcessContentDataSignalArguments::class);
743
+		$signalArguments->setContentObject($contentObject)
744
+			->setFieldNameAndPath($fieldNameAndPath)
745
+			->setContentData($contentData)
746
+			->setCounter($counter)
747
+			->setSavingBehavior($savingBehavior)
748
+			->setLanguage($language);
749
+
750
+		$signalResult = $this->getSignalSlotDispatcher()->dispatch('Fab\Vidi\Controller\Backend\ContentController', 'processContentData', array($signalArguments));
751
+		return $signalResult[0];
752
+	}
753
+
754
+	/**
755
+	 * Get the SignalSlot dispatcher.
756
+	 *
757
+	 * @return Dispatcher
758
+	 */
759
+	protected function getSignalSlotDispatcher()
760
+	{
761
+		return $this->objectManager->get(Dispatcher::class);
762
+	}
763
+
764
+	/**
765
+	 * Get the Clipboard service.
766
+	 *
767
+	 * @return ClipboardService
768
+	 */
769
+	protected function getClipboardService()
770
+	{
771
+		return GeneralUtility::makeInstance(ClipboardService::class);
772
+	}
773
+
774
+	/**
775
+	 * @return LanguageService
776
+	 */
777
+	protected function getLanguageService()
778
+	{
779
+		return GeneralUtility::makeInstance(LanguageService::class);
780
+	}
781
+
782
+	/**
783
+	 * Get the Vidi Module Loader.
784
+	 *
785
+	 * @return ModuleLoader
786
+	 */
787
+	protected function getModuleLoader()
788
+	{
789
+		return GeneralUtility::makeInstance(ModuleLoader::class);
790
+	}
791 791
 
792 792
 }
Please login to merge, or discard this patch.
Classes/Controller/SelectionController.php 1 patch
Indentation   +80 added lines, -80 removed lines patch added patch discarded remove patch
@@ -26,94 +26,94 @@
 block discarded – undo
26 26
 class SelectionController extends ActionController
27 27
 {
28 28
 
29
-    /**
30
-     * @var SelectionRepository
31
-     * @Inject
32
-     */
33
-    public $selectionRepository;
29
+	/**
30
+	 * @var SelectionRepository
31
+	 * @Inject
32
+	 */
33
+	public $selectionRepository;
34 34
 
35
-    /**
36
-     * @param Selection $selection
37
-     * @throws InvalidKeyInArrayException
38
-     */
39
-    public function createAction(Selection $selection = null)
40
-    {
41
-        $selection->setDataType($this->getModuleLoader()->getDataType());
35
+	/**
36
+	 * @param Selection $selection
37
+	 * @throws InvalidKeyInArrayException
38
+	 */
39
+	public function createAction(Selection $selection = null)
40
+	{
41
+		$selection->setDataType($this->getModuleLoader()->getDataType());
42 42
 
43
-        $selection->setOwner($this->getBackendUser()->user['uid']);
44
-        $this->selectionRepository->add($selection);
45
-        $this->redirect('edit', 'Selection', 'vidi', array('dataType' => $selection->getDataType()));
46
-    }
43
+		$selection->setOwner($this->getBackendUser()->user['uid']);
44
+		$this->selectionRepository->add($selection);
45
+		$this->redirect('edit', 'Selection', 'vidi', array('dataType' => $selection->getDataType()));
46
+	}
47 47
 
48
-    /**
49
-     * @param Selection $selection
50
-     * @return string
51
-     * @throws IllegalObjectTypeException
52
-     */
53
-    public function deleteAction(Selection $selection)
54
-    {
55
-        $this->selectionRepository->remove($selection);
56
-        return 'ok';
57
-    }
48
+	/**
49
+	 * @param Selection $selection
50
+	 * @return string
51
+	 * @throws IllegalObjectTypeException
52
+	 */
53
+	public function deleteAction(Selection $selection)
54
+	{
55
+		$this->selectionRepository->remove($selection);
56
+		return 'ok';
57
+	}
58 58
 
59
-    /**
60
-     * @param Selection $selection
61
-     * @throws IllegalObjectTypeException
62
-     * @throws UnknownObjectException
63
-     * @throws StopActionException
64
-     */
65
-    public function updateAction(Selection $selection)
66
-    {
67
-        $this->selectionRepository->update($selection);
68
-        $this->redirect('show', 'Selection', 'vidi', array('selection' => $selection->getUid()));
69
-    }
59
+	/**
60
+	 * @param Selection $selection
61
+	 * @throws IllegalObjectTypeException
62
+	 * @throws UnknownObjectException
63
+	 * @throws StopActionException
64
+	 */
65
+	public function updateAction(Selection $selection)
66
+	{
67
+		$this->selectionRepository->update($selection);
68
+		$this->redirect('show', 'Selection', 'vidi', array('selection' => $selection->getUid()));
69
+	}
70 70
 
71
-    /**
72
-     * @param Selection $selection
73
-     */
74
-    public function showAction(Selection $selection)
75
-    {
76
-        $this->view->assign('selection', $selection);
77
-    }
71
+	/**
72
+	 * @param Selection $selection
73
+	 */
74
+	public function showAction(Selection $selection)
75
+	{
76
+		$this->view->assign('selection', $selection);
77
+	}
78 78
 
79
-    /**
80
-     * Returns an editing form for a given data type.
81
-     *
82
-     * @param string $dataType
83
-     */
84
-    public function editAction($dataType)
85
-    {
86
-        $selections = $this->selectionRepository->findByDataTypeForCurrentBackendUser($dataType);
87
-        $this->view->assign('selections', $selections);
88
-    }
79
+	/**
80
+	 * Returns an editing form for a given data type.
81
+	 *
82
+	 * @param string $dataType
83
+	 */
84
+	public function editAction($dataType)
85
+	{
86
+		$selections = $this->selectionRepository->findByDataTypeForCurrentBackendUser($dataType);
87
+		$this->view->assign('selections', $selections);
88
+	}
89 89
 
90
-    /**
91
-     * @param string $dataType
92
-     */
93
-    public function listAction($dataType)
94
-    {
95
-        $selections = $this->selectionRepository->findByDataTypeForCurrentBackendUser($dataType);
96
-        $this->view->assign('selections', $selections);
97
-    }
90
+	/**
91
+	 * @param string $dataType
92
+	 */
93
+	public function listAction($dataType)
94
+	{
95
+		$selections = $this->selectionRepository->findByDataTypeForCurrentBackendUser($dataType);
96
+		$this->view->assign('selections', $selections);
97
+	}
98 98
 
99
-    /**
100
-     * Get the Vidi Module Loader.
101
-     *
102
-     * @return ModuleLoader
103
-     */
104
-    protected function getModuleLoader()
105
-    {
106
-        return GeneralUtility::makeInstance(ModuleLoader::class);
107
-    }
99
+	/**
100
+	 * Get the Vidi Module Loader.
101
+	 *
102
+	 * @return ModuleLoader
103
+	 */
104
+	protected function getModuleLoader()
105
+	{
106
+		return GeneralUtility::makeInstance(ModuleLoader::class);
107
+	}
108 108
 
109
-    /**
110
-     * Returns an instance of the current Backend User.
111
-     *
112
-     * @return BackendUserAuthentication
113
-     */
114
-    protected function getBackendUser()
115
-    {
116
-        return $GLOBALS['BE_USER'];
117
-    }
109
+	/**
110
+	 * Returns an instance of the current Backend User.
111
+	 *
112
+	 * @return BackendUserAuthentication
113
+	 */
114
+	protected function getBackendUser()
115
+	{
116
+		return $GLOBALS['BE_USER'];
117
+	}
118 118
 
119 119
 }
Please login to merge, or discard this patch.
Classes/Controller/UserPreferencesController.php 1 patch
Indentation   +56 added lines, -56 removed lines patch added patch discarded remove patch
@@ -20,69 +20,69 @@
 block discarded – undo
20 20
 class UserPreferencesController extends ActionController
21 21
 {
22 22
 
23
-    /**
24
-     * @param string $key
25
-     * @param string $value
26
-     * @param string $preferenceSignature
27
-     * @return string
28
-     */
29
-    public function saveAction($key, $value, $preferenceSignature)
30
-    {
23
+	/**
24
+	 * @param string $key
25
+	 * @param string $value
26
+	 * @param string $preferenceSignature
27
+	 * @return string
28
+	 */
29
+	public function saveAction($key, $value, $preferenceSignature)
30
+	{
31 31
 
32
-        $dataType = $this->getModuleLoader()->getDataType();
32
+		$dataType = $this->getModuleLoader()->getDataType();
33 33
 
34
-        $key = $dataType . '_' . $this->getBackendUserIdentifier() . '_' . $key;
35
-        $this->getCacheInstance()->set($key, $value, [], 0);
34
+		$key = $dataType . '_' . $this->getBackendUserIdentifier() . '_' . $key;
35
+		$this->getCacheInstance()->set($key, $value, [], 0);
36 36
 
37
-        $key = $dataType . '_' . $this->getBackendUserIdentifier() . '_signature';
38
-        $this->getCacheInstance()->set($key, $preferenceSignature, [], 0);
37
+		$key = $dataType . '_' . $this->getBackendUserIdentifier() . '_signature';
38
+		$this->getCacheInstance()->set($key, $preferenceSignature, [], 0);
39 39
 
40
-        return 'OK';
41
-    }
40
+		return 'OK';
41
+	}
42 42
 
43
-    /**
44
-     * @return int
45
-     */
46
-    protected function getBackendUserIdentifier()
47
-    {
48
-        return $this->getBackendUser()->user['uid'];
49
-    }
43
+	/**
44
+	 * @return int
45
+	 */
46
+	protected function getBackendUserIdentifier()
47
+	{
48
+		return $this->getBackendUser()->user['uid'];
49
+	}
50 50
 
51
-    /**
52
-     * Returns an instance of the current Backend User.
53
-     *
54
-     * @return BackendUserAuthentication
55
-     */
56
-    protected function getBackendUser()
57
-    {
58
-        return $GLOBALS['BE_USER'];
59
-    }
51
+	/**
52
+	 * Returns an instance of the current Backend User.
53
+	 *
54
+	 * @return BackendUserAuthentication
55
+	 */
56
+	protected function getBackendUser()
57
+	{
58
+		return $GLOBALS['BE_USER'];
59
+	}
60 60
 
61
-    /**
62
-     * Get the Vidi Module Loader.
63
-     *
64
-     * @return ModuleLoader
65
-     */
66
-    protected function getModuleLoader()
67
-    {
68
-        return GeneralUtility::makeInstance(ModuleLoader::class);
69
-    }
61
+	/**
62
+	 * Get the Vidi Module Loader.
63
+	 *
64
+	 * @return ModuleLoader
65
+	 */
66
+	protected function getModuleLoader()
67
+	{
68
+		return GeneralUtility::makeInstance(ModuleLoader::class);
69
+	}
70 70
 
71
-    /**
72
-     * @return AbstractFrontend
73
-     */
74
-    protected function getCacheInstance()
75
-    {
76
-        return $this->getCacheManager()->getCache('vidi');
77
-    }
71
+	/**
72
+	 * @return AbstractFrontend
73
+	 */
74
+	protected function getCacheInstance()
75
+	{
76
+		return $this->getCacheManager()->getCache('vidi');
77
+	}
78 78
 
79
-    /**
80
-     * Return the Cache Manager
81
-     *
82
-     * @return CacheManager
83
-     */
84
-    protected function getCacheManager()
85
-    {
86
-        return GeneralUtility::makeInstance(CacheManager::class);
87
-    }
79
+	/**
80
+	 * Return the Cache Manager
81
+	 *
82
+	 * @return CacheManager
83
+	 */
84
+	protected function getCacheManager()
85
+	{
86
+		return GeneralUtility::makeInstance(CacheManager::class);
87
+	}
88 88
 }
Please login to merge, or discard this patch.