Completed
Push — master ( a54493...36663b )
by Fabien
05:49
created

ContentController   F

Complexity

Total Complexity 58

Size/Duplication

Total Lines 764
Duplicated Lines 21.99 %

Coupling/Cohesion

Components 2
Dependencies 22

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 58
c 1
b 0
f 0
lcom 2
cbo 22
dl 168
loc 764
rs 1.3677

22 Methods

Rating   Name   Duplication   Size   Complexity  
A initializeAction() 0 15 2
A indexAction() 0 10 1
A listAction() 0 18 1
C updateAction() 0 92 7
B sortAction() 0 43 4
C editAction() 0 94 11
B deleteAction() 39 39 3
A copyAction() 0 5 1
B copyClipboardAction() 45 45 4
B moveAction() 39 39 3
B moveClipboardAction() 45 45 4
B localizeAction() 0 68 6
A getContentService() 0 4 1
A getContentObjectResolver() 0 4 1
A getFieldPathResolver() 0 4 1
A getJsonView() 0 9 2
A getJsonResult() 0 4 1
A emitProcessContentDataSignal() 0 15 1
A getSignalSlotDispatcher() 0 4 1
A getClipboardService() 0 4 1
A getLanguageService() 0 4 1
A getModuleLoader() 0 4 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like ContentController often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ContentController, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace Fab\Vidi\Controller;
3
4
/**
5
 * This file is part of the TYPO3 CMS project.
6
 *
7
 * It is free software; you can redistribute it and/or modify it under
8
 * the terms of the GNU General Public License, either version 2
9
 * of the License, or any later version.
10
 *
11
 * For the full copyright and license information, please read the
12
 * LICENSE.txt file that was distributed with this source code.
13
 *
14
 * The TYPO3 project - inspiring people to share!
15
 */
16
17
use Fab\Vidi\Tca\FieldType;
18
use Fab\Vidi\View\Grid\Row;
19
use TYPO3\CMS\Core\Page\PageRenderer;
20
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
21
use TYPO3\CMS\Core\Utility\GeneralUtility;
22
use TYPO3\CMS\Core\Utility\HttpUtility;
23
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
24
use Fab\Vidi\Behavior\SavingBehavior;
25
use Fab\Vidi\Domain\Repository\ContentRepositoryFactory;
26
use Fab\Vidi\Domain\Model\Content;
27
use Fab\Vidi\Mvc\JsonView;
28
use Fab\Vidi\Mvc\JsonResult;
29
use Fab\Vidi\Persistence\MatcherObjectFactory;
30
use Fab\Vidi\Persistence\OrderObjectFactory;
31
use Fab\Vidi\Persistence\PagerObjectFactory;
32
use Fab\Vidi\Signal\ProcessContentDataSignalArguments;
33
use Fab\Vidi\Tca\Tca;
34
35
/**
36
 * Controller which handles actions related to Vidi in the Backend.
37
 */
38
class ContentController extends ActionController
39
{
40
41
    /**
42
     * @var \Fab\Vidi\Domain\Repository\SelectionRepository
43
     * @inject
44
     */
45
    protected $selectionRepository;
46
47
    /**
48
     * Initialize every action.
49
     */
50
    public function initializeAction()
51
    {
52
        $pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
53
        $pageRenderer->addInlineLanguageLabelFile('EXT:vidi/Resources/Private/Language/locallang.xlf');
54
55
        // Configure property mapping to retrieve the file object.
56
        if ($this->arguments->hasArgument('columns')) {
57
58
            /** @var \Fab\Vidi\TypeConverter\CsvToArrayConverter $typeConverter */
59
            $typeConverter = $this->objectManager->get('Fab\Vidi\TypeConverter\CsvToArrayConverter');
60
61
            $propertyMappingConfiguration = $this->arguments->getArgument('columns')->getPropertyMappingConfiguration();
62
            $propertyMappingConfiguration->setTypeConverter($typeConverter);
63
        }
64
    }
65
66
    /**
67
     * List action for this controller.
68
     *
69
     * @return void
70
     */
71
    public function indexAction()
72
    {
73
        $dataType = $this->getModuleLoader()->getDataType();
74
        $selections = $this->selectionRepository->findByDataTypeForCurrentBackendUser($dataType);
75
        $this->view->assign('selections', $selections);
76
77
        $columns = Tca::grid()->getFields();
78
        $this->view->assign('columns', $columns);
79
        $this->view->assign('numberOfColumns', count($columns));
80
    }
81
82
    /**
83
     * List Row action for this controller. Output a json list of contents
84
     *
85
     * @param array $columns corresponds to columns to be rendered.
86
     * @param array $matches
87
     * @validate $columns Fab\Vidi\Domain\Validator\ColumnsValidator
88
     * @validate $matches Fab\Vidi\Domain\Validator\MatchesValidator
89
     * @return void
90
     */
91
    public function listAction(array $columns = array(), $matches = array())
92
    {
93
        // Initialize some objects related to the query.
94
        $matcher = MatcherObjectFactory::getInstance()->getMatcher($matches);
95
        $order = OrderObjectFactory::getInstance()->getOrder();
96
        $pager = PagerObjectFactory::getInstance()->getPager();
97
98
        // Fetch objects via the Content Service.
99
        $contentService = $this->getContentService()->findBy($matcher, $order, $pager->getLimit(), $pager->getOffset());
100
        $pager->setCount($contentService->getNumberOfObjects());
101
102
        // Assign values.
103
        $this->view->assign('columns', $columns);
104
        $this->view->assign('objects', $contentService->getObjects());
105
        $this->view->assign('numberOfObjects', $contentService->getNumberOfObjects());
106
        $this->view->assign('pager', $pager);
107
        $this->view->assign('response', $this->response);
108
    }
109
110
    /**
111
     * Retrieve Content objects first according to matching criteria and then "update" them.
112
     * Important to notice the field name can contains a path, e.g. metadata.title and therefore must be analysed.
113
     *
114
     * Possible values for $matches:
115
     * -----------------------------
116
     *
117
     * $matches = array(uid => 1), will be taken as $query->equals
118
     * $matches = array(uid => 1,2,3), will be taken as $query->in
119
     * $matches = array(field_name1 => bar, field_name2 => bax), will be separated by AND.
120
     *
121
     * Possible values for $content:
122
     * -----------------------------
123
     *
124
     * $content = array(field_name => bar)
125
     * $content = array(field_name => array(value1, value2)) <-- will be CSV converted by "value1,value2"
126
     *
127
     * @param string $fieldNameAndPath
128
     * @param array $content
129
     * @param array $matches
130
     * @param string $savingBehavior
131
     * @param int $language
132
     * @param array $columns
133
     * @return string
134
     * @throws \Fab\Vidi\Exception\InvalidKeyInArrayException
135
     */
136
    public function updateAction($fieldNameAndPath, array $content, array $matches = array(), $savingBehavior = SavingBehavior::REPLACE, $language = 0, $columns = array())
137
    {
138
139
        // Instantiate the Matcher object according different rules.
140
        $matcher = MatcherObjectFactory::getInstance()->getMatcher($matches);
141
        $order = OrderObjectFactory::getInstance()->getOrder();
142
143
        // Fetch objects via the Content Service.
144
        $contentService = $this->getContentService()->findBy($matcher, $order);
145
146
        // Get the real field that is going to be updated.
147
        $updatedFieldName = $this->getFieldPathResolver()->stripFieldPath($fieldNameAndPath);
148
149
        // Get result object for storing data along the processing.
150
        $result = $this->getJsonResult();
151
        $result->setNumberOfObjects($contentService->getNumberOfObjects());
152
153
        foreach ($contentService->getObjects() as $index => $object) {
154
155
            $identifier = $this->getContentObjectResolver()->getValue($object, $fieldNameAndPath, 'uid', $language);
156
157
            // It could be the identifier is not found because the translation
158
            // of the record does not yet exist when mass-editing
159
            if ((int)$identifier <= 0) {
160
                continue;
161
            }
162
163
            $dataType = $this->getContentObjectResolver()->getDataType($object, $fieldNameAndPath);
164
165
            $signalResult = $this->emitProcessContentDataSignal($object, $fieldNameAndPath, $content, $index + 1, $savingBehavior, $language);
166
            $contentData = $signalResult->getContentData();
167
168
            // Add identifier to content data, required by TCEMain.
169
            $contentData['uid'] = $identifier;
170
171
            /** @var Content $dataObject */
172
            $dataObject = GeneralUtility::makeInstance('Fab\Vidi\Domain\Model\Content', $dataType, $contentData);
173
174
            // Properly update object.
175
            ContentRepositoryFactory::getInstance($dataType)->update($dataObject);
176
177
            // Get the possible error messages and store them.
178
            $errorMessages = ContentRepositoryFactory::getInstance()->getErrorMessages();
179
            $result->addErrorMessages($errorMessages);
0 ignored issues
show
Documentation introduced by
$errorMessages is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
180
181
            // We only want to see the detail result if there is one object updated.
182
            // Required for inline editing + it will display some useful info on the GUI in the flash messages.
183
            if ($contentService->getNumberOfObjects() === 1) {
184
185
                // Fetch the updated object from repository.
186
                $updatedObject = ContentRepositoryFactory::getInstance()->findByUid($object->getUid());
187
188
                // Re-fetch the updated result.
189
                $updatedResult = $this->getContentObjectResolver()->getValue($updatedObject, $fieldNameAndPath, $updatedFieldName, $language);
190
                if (is_array($updatedResult)) {
191
                    $_updatedResult = array(); // reset result set.
192
193
                    /** @var Content $contentObject */
194
                    foreach ($updatedResult as $contentObject) {
195
                        $labelField = Tca::table($contentObject)->getLabelField();
196
                        $values = array(
197
                            'uid' => $contentObject->getUid(),
198
                            'name' => $contentObject[$labelField],
199
                        );
200
                        $_updatedResult[] = $values;
201
                    }
202
203
                    $updatedResult = $_updatedResult;
204
                }
205
206
                $labelField = Tca::table($object)->getLabelField();
207
208
                $processedObjectData = array(
209
                    'uid' => $object->getUid(),
210
                    'name' => $object[$labelField],
211
                    'updatedField' => $fieldNameAndPath,
212
                    'updatedValue' => $updatedResult,
213
                );
214
                $result->setProcessedObject($processedObjectData);
215
216
                if (!empty($columns)) {
217
                    /** @var Row $row */
218
                    $row = GeneralUtility::makeInstance('Fab\Vidi\View\Grid\Row', $columns);
219
                    $result->setRow($row->render($updatedObject));
220
                }
221
            }
222
        }
223
224
        // Set the result and render the JSON view.
225
        $this->getJsonView()->setResult($result);
226
        return $this->getJsonView()->render();
227
    }
228
229
    /**
230
     * Set the sorting of a record giving the previous object.
231
     *
232
     * @param array $matches
233
     * @param int $previousIdentifier
234
     * @return string
235
     */
236
    public function sortAction(array $matches = array(), $previousIdentifier = NULL)
237
    {
238
239
        $matcher = MatcherObjectFactory::getInstance()->getMatcher($matches);
240
241
        // Fetch objects via the Content Service.
242
        $contentService = $this->getContentService()->findBy($matcher);
243
244
        // Compute the label field name of the table.
245
        $tableTitleField = Tca::table()->getLabelField();
246
247
        // Get result object for storing data along the processing.
248
        $result = $this->getJsonResult();
249
        $result->setNumberOfObjects($contentService->getNumberOfObjects());
250
251
        foreach ($contentService->getObjects() as $object) {
252
253
            // Store the first object, so that the "action" message can be more explicit when deleting only one record.
254
            if ($contentService->getNumberOfObjects() === 1) {
255
                $tableTitleValue = $object[$tableTitleField];
256
                $processedObjectData = array(
257
                    'uid' => $object->getUid(),
258
                    'name' => $tableTitleValue,
259
                );
260
                $result->setProcessedObject($processedObjectData);
261
            }
262
263
            // The $target corresponds to the pid to move the records to.
264
            // It can also be a negative value in case of sorting. The negative value would be the uid of its predecessor.
265
            $target = is_null($previousIdentifier) ? $object->getPid() : (-(int)$previousIdentifier);
0 ignored issues
show
Documentation Bug introduced by
The method getPid does not exist on object<Fab\Vidi\Domain\Model\Content>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
266
267
            // Work out the object.
268
            ContentRepositoryFactory::getInstance()->move($object, $target);
269
270
            // Get the possible error messages and store them.
271
            $errorMessages = ContentRepositoryFactory::getInstance()->getErrorMessages();
272
            $result->addErrorMessages($errorMessages);
0 ignored issues
show
Documentation introduced by
$errorMessages is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
273
        }
274
275
        // Set the result and render the JSON view.
276
        $this->getJsonView()->setResult($result);
277
        return $this->getJsonView()->render();
278
    }
279
280
    /**
281
     * Returns an editing form for a given field name of a Content object.
282
     * Argument $fieldNameAndPath corresponds to the field name to be edited.
283
     * Important to notice it can contains a path, e.g. metadata.title and therefore must be analysed.
284
     *
285
     * Possible values for $matches, refer to method "updateAction".
286
     *
287
     * @param string $fieldNameAndPath
288
     * @param array $matches
289
     * @param bool $hasRecursiveSelection
290
     * @throws \Exception
291
     */
292
    public function editAction($fieldNameAndPath, array $matches = array(), $hasRecursiveSelection = FALSE)
293
    {
294
295
        // Instantiate the Matcher object according different rules.
296
        $matcher = MatcherObjectFactory::getInstance()->getMatcher($matches);
297
298
        // Fetch objects via the Content Service.
299
        $contentService = $this->getContentService()->findBy($matcher);
300
301
        $dataType = $this->getFieldPathResolver()->getDataType($fieldNameAndPath);
302
        $fieldName = $this->getFieldPathResolver()->stripFieldPath($fieldNameAndPath);
303
304
        $fieldType = Tca::table($dataType)->field($fieldName)->getType();
305
        $this->view->assign('fieldType', ucfirst($fieldType));
306
        $this->view->assign('dataType', $dataType);
307
        $this->view->assign('fieldName', $fieldName);
308
        $this->view->assign('matches', $matches);
309
        $this->view->assign('fieldNameAndPath', $fieldNameAndPath);
310
        $this->view->assign('numberOfObjects', $contentService->getNumberOfObjects());
311
        $this->view->assign('hasRecursiveSelection', $hasRecursiveSelection);
312
        $this->view->assign('editWholeSelection', empty($matches['uid'])); // necessary??
313
314
        // Fetch content and its relations.
315
        if ($fieldType === FieldType::MULTISELECT) {
316
317
            $object = ContentRepositoryFactory::getInstance()->findOneBy($matcher);
318
            $identifier = $this->getContentObjectResolver()->getValue($object, $fieldNameAndPath, 'uid');
319
            $dataType = $this->getContentObjectResolver()->getDataType($object, $fieldNameAndPath);
320
321
            $content = ContentRepositoryFactory::getInstance($dataType)->findByUid($identifier);
322
323
            // Makes sure the object was retrieved. Security!
324
            if (!$content) {
325
                $message = sprintf('I could not retrieved content object of type "%s" with identifier %s.', $dataType, $identifier);
326
                throw new \Exception($message, 1402350182);
327
            }
328
329
            $relatedDataType = Tca::table($dataType)->field($fieldName)->getForeignTable();
330
331
            // Initialize the matcher object.
332
            /** @var \Fab\Vidi\Persistence\Matcher $matcher */
333
            $matcher = GeneralUtility::makeInstance('Fab\Vidi\Persistence\Matcher', array(), $relatedDataType);
334
335
            // Default ordering for related data type.
336
            $defaultOrderings = Tca::table($relatedDataType)->getDefaultOrderings();
337
            /** @var \Fab\Vidi\Persistence\Order $order */
338
            $defaultOrder = GeneralUtility::makeInstance('Fab\Vidi\Persistence\Order', $defaultOrderings);
339
340
            // Fetch related contents
341
            $relatedContents = ContentRepositoryFactory::getInstance($relatedDataType)->findBy($matcher, $defaultOrder);
342
343
            if (Tca::table($dataType)->field($fieldName)->isRenderModeTree()) {
344
345
                $fieldConfiguration = Tca::table($dataType)->field($fieldName)->getConfiguration();
346
                $parentField = $fieldConfiguration['treeConfig']['parentField'];
347
348
                $flatTree = array();
349
                foreach ($relatedContents as $node) {
350
                    $flatTree[$node->getUid()] = array(
351
                        'item' => $node,
352
                        'parent' => $node[$parentField] ? $node[$parentField]['uid'] : NULL,
353
                    );
354
                }
355
356
                $tree = array();
357
358
                // If leaves are selected without its parents selected, those are shown as parent
359
                foreach ($flatTree as $id => &$flatNode) {
360
                    if (!isset($flatTree[$flatNode['parent']])) {
361
                        $flatNode['parent'] = NULL;
362
                    }
363
                }
364
365
                foreach ($flatTree as $id => &$node) {
366
                    if ($node['parent'] === NULL) {
367
                        $tree[$id] = &$node;
368
                    } else {
369
                        $flatTree[$node['parent']]['children'][$id] = &$node;
370
                    }
371
                }
372
373
                $relatedContents = $tree;
374
            }
375
376
            $this->view->assign('content', $content);
377
            $this->view->assign('relatedContents', $relatedContents);
378
            $this->view->assign('relatedDataType', $relatedDataType);
379
            $this->view->assign('relatedContentTitle', Tca::table($relatedDataType)->getTitle());
380
            $this->view->assign(
381
                'renderMode',
382
                Tca::table($dataType)->field($fieldName)->isRenderModeTree() ? FieldType::TREE : NULL
383
            );
384
        }
385
    }
386
387
    /**
388
     * Retrieve Content objects first according to matching criteria and then "delete" them.
389
     *
390
     * Possible values for $matches, refer to method "updateAction".
391
     *
392
     * @param array $matches
393
     * @return string
394
     */
395 View Code Duplication
    public function deleteAction(array $matches = array())
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
396
    {
397
398
        $matcher = MatcherObjectFactory::getInstance()->getMatcher($matches);
399
400
        // Fetch objects via the Content Service.
401
        $contentService = $this->getContentService()->findBy($matcher);
402
403
        // Compute the label field name of the table.
404
        $tableTitleField = Tca::table()->getLabelField();
405
406
        // Get result object for storing data along the processing.
407
        $result = $this->getJsonResult();
408
        $result->setNumberOfObjects($contentService->getNumberOfObjects());
409
410
        foreach ($contentService->getObjects() as $object) {
411
412
            // Store the first object, so that the delete message can be more explicit when deleting only one record.
413
            if ($contentService->getNumberOfObjects() === 1) {
414
                $tableTitleValue = $object[$tableTitleField];
415
                $processedObjectData = array(
416
                    'uid' => $object->getUid(),
417
                    'name' => $tableTitleValue,
418
                );
419
                $result->setProcessedObject($processedObjectData);
420
            }
421
422
            // Properly delete object.
423
            ContentRepositoryFactory::getInstance()->remove($object);
424
425
            // Get the possible error messages and store them.
426
            $errorMessages = ContentRepositoryFactory::getInstance()->getErrorMessages();
427
            $result->addErrorMessages($errorMessages);
0 ignored issues
show
Documentation introduced by
$errorMessages is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
428
        }
429
430
        // Set the result and render the JSON view.
431
        $this->getJsonView()->setResult($result);
432
        return $this->getJsonView()->render();
433
    }
434
435
    /**
436
     * Retrieve Content objects first according to matching criteria and then "copy" them.
437
     *
438
     * Possible values for $matches, refer to method "updateAction".
439
     *
440
     * @param string $target
441
     * @param array $matches
442
     * @throws \Exception
443
     * @return string
444
     */
445
    public function copyAction($target, array $matches = array())
446
    {
447
        // @todo
448
        throw new \Exception('Not yet implemented', 1410192546);
449
    }
450
451
    /**
452
     * Retrieve Content objects from the Clipboard then "copy" them according to the target.
453
     *
454
     * @param string $target
455
     * @throws \Exception
456
     * @return string
457
     */
458 View Code Duplication
    public function copyClipboardAction($target)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
459
    {
460
461
        // Retrieve matcher object from clipboard.
462
        $matcher = $this->getClipboardService()->getMatcher();
463
464
        // Fetch objects via the Content Service.
465
        $contentService = $this->getContentService()->findBy($matcher);
466
467
        // Compute the label field name of the table.
468
        $tableTitleField = Tca::table()->getLabelField();
469
470
        // Get result object for storing data along the processing.
471
        $result = $this->getJsonResult();
472
        $result->setNumberOfObjects($contentService->getNumberOfObjects());
473
474
        foreach ($contentService->getObjects() as $object) {
475
476
            // Store the first object, so that the "action" message can be more explicit when deleting only one record.
477
            if ($contentService->getNumberOfObjects() === 1) {
478
                $tableTitleValue = $object[$tableTitleField];
479
                $processedObjectData = array(
480
                    'uid' => $object->getUid(),
481
                    'name' => $tableTitleValue,
482
                );
483
                $result->setProcessedObject($processedObjectData);
484
            }
485
486
            // Work out the object.
487
            ContentRepositoryFactory::getInstance()->copy($object, $target);
488
489
            // Get the possible error messages and store them.
490
            $errorMessages = ContentRepositoryFactory::getInstance()->getErrorMessages();
491
            $result->addErrorMessages($errorMessages);
0 ignored issues
show
Documentation introduced by
$errorMessages is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
492
        }
493
494
        // Flush Clipboard if told so.
495
        if (GeneralUtility::_GP('flushClipboard')) {
496
            $this->getClipboardService()->flush();
497
        }
498
499
        // Set the result and render the JSON view.
500
        $this->getJsonView()->setResult($result);
501
        return $this->getJsonView()->render();
502
    }
503
504
    /**
505
     * Retrieve Content objects first according to matching criteria and then "move" them.
506
     *
507
     * Possible values for $matches, refer to method "updateAction".
508
     *
509
     * @param string $target
510
     * @param array $matches
511
     * @return string
512
     */
513 View Code Duplication
    public function moveAction($target, array $matches = array())
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
514
    {
515
516
        $matcher = MatcherObjectFactory::getInstance()->getMatcher($matches);
517
518
        // Fetch objects via the Content Service.
519
        $contentService = $this->getContentService()->findBy($matcher);
520
521
        // Compute the label field name of the table.
522
        $tableTitleField = Tca::table()->getLabelField();
523
524
        // Get result object for storing data along the processing.
525
        $result = $this->getJsonResult();
526
        $result->setNumberOfObjects($contentService->getNumberOfObjects());
527
528
        foreach ($contentService->getObjects() as $object) {
529
530
            // Store the first object, so that the "action" message can be more explicit when deleting only one record.
531
            if ($contentService->getNumberOfObjects() === 1) {
532
                $tableTitleValue = $object[$tableTitleField];
533
                $processedObjectData = array(
534
                    'uid' => $object->getUid(),
535
                    'name' => $tableTitleValue,
536
                );
537
                $result->setProcessedObject($processedObjectData);
538
            }
539
540
            // Work out the object.
541
            ContentRepositoryFactory::getInstance()->move($object, $target);
542
543
            // Get the possible error messages and store them.
544
            $errorMessages = ContentRepositoryFactory::getInstance()->getErrorMessages();
545
            $result->addErrorMessages($errorMessages);
0 ignored issues
show
Documentation introduced by
$errorMessages is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
546
        }
547
548
        // Set the result and render the JSON view.
549
        $this->getJsonView()->setResult($result);
550
        return $this->getJsonView()->render();
551
    }
552
553
    /**
554
     * Retrieve Content objects from the Clipboard then "move" them according to the target.
555
     *
556
     * @param string $target
557
     * @return string
558
     */
559 View Code Duplication
    public function moveClipboardAction($target)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
560
    {
561
562
        // Retrieve matcher object from clipboard.
563
        $matcher = $this->getClipboardService()->getMatcher();
564
565
        // Fetch objects via the Content Service.
566
        $contentService = $this->getContentService()->findBy($matcher);
567
568
        // Compute the label field name of the table.
569
        $tableTitleField = Tca::table()->getLabelField();
570
571
        // Get result object for storing data along the processing.
572
        $result = $this->getJsonResult();
573
        $result->setNumberOfObjects($contentService->getNumberOfObjects());
574
575
        foreach ($contentService->getObjects() as $object) {
576
577
            // Store the first object, so that the "action" message can be more explicit when deleting only one record.
578
            if ($contentService->getNumberOfObjects() === 1) {
579
                $tableTitleValue = $object[$tableTitleField];
580
                $processedObjectData = array(
581
                    'uid' => $object->getUid(),
582
                    'name' => $tableTitleValue,
583
                );
584
                $result->setProcessedObject($processedObjectData);
585
            }
586
587
            // Work out the object.
588
            ContentRepositoryFactory::getInstance()->move($object, $target);
589
590
            // Get the possible error messages and store them.
591
            $errorMessages = ContentRepositoryFactory::getInstance()->getErrorMessages();
592
            $result->addErrorMessages($errorMessages);
0 ignored issues
show
Documentation introduced by
$errorMessages is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
593
        }
594
595
        // Flush Clipboard if told so.
596
        if (GeneralUtility::_GP('flushClipboard')) {
597
            $this->getClipboardService()->flush();
598
        }
599
600
        // Set the result and render the JSON view.
601
        $this->getJsonView()->setResult($result);
602
        return $this->getJsonView()->render();
603
    }
604
605
    /**
606
     * Retrieve Content objects first according to matching criteria and then "localize" them.
607
     *
608
     * Possible values for $matches, refer to method "updateAction".
609
     *
610
     * @param string $fieldNameAndPath
611
     * @param array $matches
612
     * @param int $language
613
     * @return string
614
     * @throws \Exception
615
     */
616
    public function localizeAction($fieldNameAndPath, array $matches = array(), $language = 0)
617
    {
618
619
        $matcher = MatcherObjectFactory::getInstance()->getMatcher($matches);
620
621
        // Fetch objects via the Content Service.
622
        $contentService = $this->getContentService()->findBy($matcher);
623
624
        // Get result object for storing data along the processing.
625
        $result = $this->getJsonResult();
626
        $result->setNumberOfObjects($contentService->getNumberOfObjects());
627
628
        foreach ($contentService->getObjects() as $object) {
629
630
            $identifier = $this->getContentObjectResolver()->getValue($object, $fieldNameAndPath, 'uid');
631
            $dataType = $this->getContentObjectResolver()->getDataType($object, $fieldNameAndPath);
632
633
            // Fetch the source object to be localized.
634
            /** @var Content $content */
635
            $content = ContentRepositoryFactory::getInstance($dataType)->findByIdentifier($identifier);
636
637
            // Makes sure the object was retrieved. Security!
638
            if (!$content) {
639
                $message = sprintf('Something went wrong when retrieving content "%s" with identifier "%s".', $dataType, $identifier);
640
                throw new \Exception($message, 1412343097);
641
            }
642
643
            // Handover the localization to the Repository.
644
            ContentRepositoryFactory::getInstance($dataType)->localize($content, $language);
645
646
            // Get the possible error messages and store them.
647
            $errorMessages = ContentRepositoryFactory::getInstance()->getErrorMessages();
648
649
            // Redirect to TCEForm so that the BE User can do its job!
650
            if ($contentService->getNumberOfObjects() === 1) {
651
652
                if (!empty($errorMessages)) {
653
                    $message = sprintf('Something went wrong when localizing content "%s" with identifier "%s". <br/>%s',
654
                        $dataType,
655
                        $identifier,
656
                        implode('<br/>', $errorMessages)
657
                    );
658
                    throw new \Exception($message, 1412343098);
659
                }
660
661
                $localizedContent = $this->getLanguageService()->getLocalizedContent($content, $language);
662
                if (empty($localizedContent)) {
663
                    $message = sprintf('Oups! I could not retrieve localized content of type "%s" with identifier "%s"',
664
                        $content->getDataType(),
665
                        $content->getUid()
666
                    );
667
                    throw new \Exception($message, 1412343099);
668
                }
669
670
                /** @var \Fab\Vidi\View\Uri\EditUri $uri */
671
                $uriRenderer = GeneralUtility::makeInstance('Fab\Vidi\View\Uri\EditUri');
672
                $uri = $uriRenderer->render($localizedContent);
673
                HttpUtility::redirect($uri);
674
                break; // no need to further continue
675
            }
676
677
            $result->addErrorMessages($errorMessages);
0 ignored issues
show
Documentation introduced by
$errorMessages is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
678
        }
679
680
        // Set the result and render the JSON view.
681
        $this->getJsonView()->setResult($result);
682
        return $this->getJsonView()->render();
683
    }
684
685
    /**
686
     * Get the Vidi Module Loader.
687
     *
688
     * @return \Fab\Vidi\Service\ContentService
689
     */
690
    protected function getContentService()
691
    {
692
        return GeneralUtility::makeInstance('Fab\Vidi\Service\ContentService');
693
    }
694
695
    /**
696
     * @return \Fab\Vidi\Resolver\ContentObjectResolver
697
     */
698
    protected function getContentObjectResolver()
699
    {
700
        return GeneralUtility::makeInstance('Fab\Vidi\Resolver\ContentObjectResolver');
701
    }
702
703
    /**
704
     * @return \Fab\Vidi\Resolver\FieldPathResolver
705
     */
706
    protected function getFieldPathResolver()
707
    {
708
        return GeneralUtility::makeInstance('Fab\Vidi\Resolver\FieldPathResolver');
709
    }
710
711
    /**
712
     * Return a special view for handling JSON
713
     * Goal is to have this view injected but require more configuration.
714
     *
715
     * @return JsonView
716
     */
717
    protected function getJsonView()
718
    {
719
        if (!$this->view instanceof JsonView) {
720
            /** @var JsonView $view */
721
            $this->view = $this->objectManager->get('Fab\Vidi\Mvc\JsonView');
722
            $this->view->setResponse($this->response);
723
        }
724
        return $this->view;
725
    }
726
727
    /**
728
     * @return JsonResult
729
     */
730
    protected function getJsonResult()
731
    {
732
        return GeneralUtility::makeInstance('Fab\Vidi\Mvc\JsonResult');
733
    }
734
735
    /**
736
     * Signal that is called for post-processing content data send to the server for update.
737
     *
738
     * @param Content $contentObject
739
     * @param $fieldNameAndPath
740
     * @param $contentData
741
     * @param $counter
742
     * @param $savingBehavior
743
     * @param $language
744
     * @return ProcessContentDataSignalArguments
745
     * @signal
746
     */
747
    protected function emitProcessContentDataSignal(Content $contentObject, $fieldNameAndPath, $contentData, $counter, $savingBehavior, $language)
748
    {
749
750
        /** @var \Fab\Vidi\Signal\ProcessContentDataSignalArguments $signalArguments */
751
        $signalArguments = GeneralUtility::makeInstance('Fab\Vidi\Signal\ProcessContentDataSignalArguments');
752
        $signalArguments->setContentObject($contentObject)
753
            ->setFieldNameAndPath($fieldNameAndPath)
754
            ->setContentData($contentData)
755
            ->setCounter($counter)
756
            ->setSavingBehavior($savingBehavior)
757
            ->setLanguage($language);
758
759
        $signalResult = $this->getSignalSlotDispatcher()->dispatch('Fab\Vidi\Controller\Backend\ContentController', 'processContentData', array($signalArguments));
760
        return $signalResult[0];
761
    }
762
763
    /**
764
     * Get the SignalSlot dispatcher.
765
     *
766
     * @return \TYPO3\CMS\Extbase\SignalSlot\Dispatcher
767
     */
768
    protected function getSignalSlotDispatcher()
769
    {
770
        return $this->objectManager->get('TYPO3\\CMS\\Extbase\\SignalSlot\\Dispatcher');
771
    }
772
773
    /**
774
     * Get the Clipboard service.
775
     *
776
     * @return \Fab\Vidi\Service\ClipboardService
777
     */
778
    protected function getClipboardService()
779
    {
780
        return GeneralUtility::makeInstance('Fab\Vidi\Service\ClipboardService');
781
    }
782
783
    /**
784
     * @return \Fab\Vidi\Language\LanguageService
785
     */
786
    protected function getLanguageService()
787
    {
788
        return GeneralUtility::makeInstance('Fab\Vidi\Language\LanguageService');
789
    }
790
791
    /**
792
     * Get the Vidi Module Loader.
793
     *
794
     * @return \Fab\Vidi\Module\ModuleLoader
795
     */
796
    protected function getModuleLoader()
797
    {
798
        return GeneralUtility::makeInstance('Fab\Vidi\Module\ModuleLoader');
799
    }
800
801
}
802