Completed
Push — master ( dfcf5d...d319e3 )
by Fabien
03:27
created
Classes/Domain/Repository/ContentRepository.php 2 patches
Doc Comments   +3 added lines, -2 removed lines patch added patch discarded remove patch
@@ -279,7 +279,7 @@  discard block
 block discarded – undo
279 279
      * Update a content with new information.
280 280
      *
281 281
      * @param Content $content
282
-     * @param $language
282
+     * @param integer $language
283 283
      * @return bool
284 284
      */
285 285
     public function localize($content, $language)
@@ -360,6 +360,7 @@  discard block
 block discarded – undo
360 360
      * Copy a content within this repository.
361 361
      *
362 362
      * @param Content $content
363
+     * @param string $target
363 364
      * @return bool
364 365
      */
365 366
     public function copy($content, $target)
@@ -512,7 +513,7 @@  discard block
 block discarded – undo
512 513
     /**
513 514
      * Sets the default query settings to be used in this repository
514 515
      *
515
-     * @param QuerySettingsInterface $defaultQuerySettings The query settings to be used by default
516
+     * @param QuerySettings $defaultQuerySettings The query settings to be used by default
516 517
      * @throws \BadMethodCallException
517 518
      * @return void
518 519
      * @api
Please login to merge, or discard this patch.
Indentation   +820 added lines, -820 removed lines patch added patch discarded remove patch
@@ -41,825 +41,825 @@
 block discarded – undo
41 41
 class ContentRepository implements RepositoryInterface
42 42
 {
43 43
 
44
-    /**
45
-     * Tell whether it is a raw result (array) or object being returned.
46
-     *
47
-     * @var bool
48
-     */
49
-    protected $rawResult = false;
50
-
51
-    /**
52
-     * The data type to be returned, e.g fe_users, fe_groups, tt_content, etc...
53
-     *
54
-     * @var string
55
-     */
56
-    protected $dataType;
57
-
58
-    /**
59
-     * The source field is useful in the context of MM relations to know who is the caller
60
-     * e.g findByItems which eventually corresponds to a field name.
61
-     *
62
-     * @var string
63
-     */
64
-    protected $sourceFieldName = '';
65
-
66
-    /**
67
-     * @var array
68
-     */
69
-    protected $errorMessages = array();
70
-
71
-    /**
72
-     * @var QuerySettingsInterface
73
-     */
74
-    protected $defaultQuerySettings;
75
-
76
-    /**
77
-     * Constructor
78
-     *
79
-     * @param string $dataType
80
-     */
81
-    public function __construct($dataType)
82
-    {
83
-        $this->dataType = $dataType;
84
-    }
85
-
86
-    /**
87
-     * Returns all objects of this repository.
88
-     *
89
-     * @return Content[]
90
-     */
91
-    public function findAll()
92
-    {
93
-        $query = $this->createQuery();
94
-        return $query->execute();
95
-    }
96
-
97
-    /**
98
-     * Returns all "distinct" values for a given property.
99
-     *
100
-     * @param string $propertyName
101
-     * @param Matcher $matcher
102
-     * @return Content[]
103
-     */
104
-    public function findDistinctValues($propertyName, Matcher $matcher = null)
105
-    {
106
-        $query = $this->createQuery();
107
-        $query->setDistinct($propertyName);
108
-
109
-        // Remove empty values from selection.
110
-        $constraint = $query->logicalNot($query->equals($propertyName, ''));
111
-
112
-        // Add some additional constraints from the Matcher object.
113
-        $matcherConstraint = null;
114
-        if (!is_null($matcher)) {
115
-            $matcherConstraint = $this->computeConstraints($query, $matcher);
116
-        }
117
-
118
-        // Assemble the final constraints or not.
119
-        if ($matcherConstraint) {
120
-            $query->logicalAnd($matcherConstraint, $constraint);
121
-            $query->matching($query->logicalAnd($matcherConstraint, $constraint));
122
-        } else {
123
-            $query->matching($constraint);
124
-        }
125
-
126
-        return $query->execute();
127
-    }
128
-
129
-    /**
130
-     * Returns all "distinct" values for a given property.
131
-     *
132
-     * @param string $propertyName
133
-     * @param Matcher $matcher
134
-     * @return int
135
-     */
136
-    public function countDistinctValues($propertyName, Matcher $matcher = null)
137
-    {
138
-        $query = $this->createQuery();
139
-        $query->setDistinct($propertyName);
140
-
141
-        // Remove empty values from selection.
142
-        $constraint = $query->logicalNot($query->equals($propertyName, ''));
143
-
144
-        // Add some additional constraints from the Matcher object.
145
-        $matcherConstraint = null;
146
-        if (!is_null($matcher)) {
147
-            $matcherConstraint = $this->computeConstraints($query, $matcher);
148
-        }
149
-
150
-        // Assemble the final constraints or not.
151
-        if ($matcherConstraint) {
152
-            $query->logicalAnd($matcherConstraint, $constraint);
153
-            $query->matching($query->logicalAnd($matcherConstraint, $constraint));
154
-        } else {
155
-            $query->matching($constraint);
156
-        }
157
-
158
-        return $query->count();
159
-    }
160
-
161
-    /**
162
-     * Finds an object matching the given identifier.
163
-     *
164
-     * @param int $uid The identifier of the object to find
165
-     * @return Content|null
166
-     * @api
167
-     */
168
-    public function findByUid($uid)
169
-    {
170
-        return $this->findByIdentifier($uid);
171
-    }
172
-
173
-    /**
174
-     * Finds all Contents given specified matches.
175
-     *
176
-     * @param string $propertyName
177
-     * @param array $values
178
-     * @return Content[]
179
-     */
180
-    public function findIn($propertyName, array $values)
181
-    {
182
-        $query = $this->createQuery();
183
-        $query->matching($query->in($propertyName, $values));
184
-        return $query->execute();
185
-    }
186
-
187
-    /**
188
-     * Finds all Contents given specified matches.
189
-     *
190
-     * @param Matcher $matcher
191
-     * @param Order $order The order
192
-     * @param int $limit
193
-     * @param int $offset
194
-     * @return Content[]
195
-     */
196
-    public function findBy(Matcher $matcher, Order $order = null, $limit = null, $offset = null)
197
-    {
198
-
199
-        $query = $this->createQuery();
200
-
201
-        $limit = (int)$limit; // make sure to cast
202
-        if ($limit > 0) {
203
-            $query->setLimit($limit);
204
-        }
205
-
206
-        if ($order) {
207
-            $query->setOrderings($order->getOrderings());
208
-
209
-            // Loops around the orderings adding if necessary a dummy condition
210
-            // to make sure the relations can be resolved when transforming the query to plain SQL.
211
-            foreach ($order->getOrderings() as $ordering => $direction) {
212
-                if ($this->hasForeignRelationIn($ordering)) {
213
-                    $relationalField = $this->getForeignRelationFrom($ordering);
214
-                    $matcher->like($relationalField . '.uid', '');
215
-                }
216
-            }
217
-        }
218
-
219
-        if ($offset) {
220
-            $query->setOffset($offset);
221
-        }
222
-
223
-        $constraints = $this->computeConstraints($query, $matcher);
224
-
225
-        if ($constraints) {
226
-            $query->matching($constraints);
227
-        }
228
-
229
-        return $query->execute();
230
-    }
231
-
232
-    /**
233
-     * Find one Content object given specified matches.
234
-     *
235
-     * @param Matcher $matcher
236
-     * @return Content
237
-     */
238
-    public function findOneBy(Matcher $matcher)
239
-    {
240
-
241
-        $query = $this->createQuery();
242
-
243
-        $constraints = $this->computeConstraints($query, $matcher);
244
-
245
-        if ($constraints) {
246
-            $query->matching($constraints);
247
-        }
248
-
249
-        $query->setLimit(1); // only take one!
250
-
251
-        $resultSet = $query->execute();
252
-        if ($resultSet) {
253
-            $resultSet = current($resultSet);
254
-        }
255
-        return $resultSet;
256
-    }
257
-
258
-    /**
259
-     * Count all Contents given specified matches.
260
-     *
261
-     * @param Matcher $matcher
262
-     * @return int
263
-     */
264
-    public function countBy(Matcher $matcher)
265
-    {
266
-
267
-        $query = $this->createQuery();
268
-
269
-        $constraints = $this->computeConstraints($query, $matcher);
270
-
271
-        if ($constraints) {
272
-            $query->matching($constraints);
273
-        }
274
-
275
-        return $query->count();
276
-    }
277
-
278
-    /**
279
-     * Update a content with new information.
280
-     *
281
-     * @param Content $content
282
-     * @param $language
283
-     * @return bool
284
-     */
285
-    public function localize($content, $language)
286
-    {
287
-
288
-        // Security check
289
-        $this->getContentValidator()->validate($content);
290
-        $this->getLanguageValidator()->validate($language);
291
-
292
-        $dataType = $content->getDataType();
293
-        $handler = $this->getDataHandlerFactory()->action(ProcessAction::LOCALIZE)->forType($dataType)->getDataHandler();
294
-
295
-        $handlerResult = $handler->processLocalize($content, $language);
296
-        $this->errorMessages = $handler->getErrorMessages();
297
-        return $handlerResult;
298
-    }
299
-
300
-    /**
301
-     * Update a content with new information.
302
-     *
303
-     * @param Content $content
304
-     * @return bool
305
-     */
306
-    public function update($content)
307
-    {
308
-
309
-        // Security check.
310
-        $this->getContentValidator()->validate($content);
311
-
312
-        $dataType = $content->getDataType();
313
-        $handler = $this->getDataHandlerFactory()->action(ProcessAction::UPDATE)->forType($dataType)->getDataHandler();
314
-
315
-        $handlerResult = $handler->processUpdate($content);
316
-        $this->errorMessages = $handler->getErrorMessages();
317
-        return $handlerResult;
318
-    }
319
-
320
-    /**
321
-     * Removes an object from this repository.
322
-     *
323
-     * @param Content $content
324
-     * @return boolean
325
-     */
326
-    public function remove($content)
327
-    {
328
-        $dataType = $content->getDataType();
329
-        $handler = $this->getDataHandlerFactory()->action(ProcessAction::REMOVE)->forType($dataType)->getDataHandler();
330
-
331
-        $handlerResult = $handler->processRemove($content);
332
-        $this->errorMessages = $handler->getErrorMessages();
333
-        return $handlerResult;
334
-    }
335
-
336
-    /**
337
-     * Move a content within this repository.
338
-     * The $target corresponds to the pid to move the records to.
339
-     * It can also be a negative value in case of sorting. The negative value would be the uid of its predecessor.
340
-     *
341
-     * @param Content $content
342
-     * @param string $target
343
-     * @return bool
344
-     */
345
-    public function move($content, $target)
346
-    {
347
-
348
-        // Security check.
349
-        $this->getContentValidator()->validate($content);
350
-
351
-        $dataType = $content->getDataType();
352
-        $handler = $this->getDataHandlerFactory()->action(ProcessAction::MOVE)->forType($dataType)->getDataHandler();
353
-
354
-        $handlerResult = $handler->processMove($content, $target);
355
-        $this->errorMessages = $handler->getErrorMessages();
356
-        return $handlerResult;
357
-    }
358
-
359
-    /**
360
-     * Copy a content within this repository.
361
-     *
362
-     * @param Content $content
363
-     * @return bool
364
-     */
365
-    public function copy($content, $target)
366
-    {
367
-
368
-        // Security check.
369
-        $this->getContentValidator()->validate($content);
370
-
371
-        $dataType = $content->getDataType();
372
-        $handler = $this->getDataHandlerFactory()->action(ProcessAction::COPY)->forType($dataType)->getDataHandler();
373
-
374
-        $handlerResult = $handler->processCopy($content, $target);
375
-        $this->errorMessages = $handler->getErrorMessages();
376
-        return $handlerResult;
377
-    }
378
-
379
-    /**
380
-     * Adds an object to this repository.
381
-     *
382
-     * @param object $object The object to add
383
-     * @throws \BadMethodCallException
384
-     * @return void
385
-     * @api
386
-     */
387
-    public function add($object)
388
-    {
389
-        throw new \BadMethodCallException('Repository does not support the add() method.', 1375805599);
390
-    }
391
-
392
-    /**
393
-     * Returns the total number objects of this repository.
394
-     *
395
-     * @return integer The object count
396
-     * @api
397
-     */
398
-    public function countAll()
399
-    {
400
-        $query = $this->createQuery();
401
-        return $query->count();
402
-    }
403
-
404
-    /**
405
-     * Removes all objects of this repository as if remove() was called for
406
-     * all of them.
407
-     *
408
-     * @return void
409
-     * @api
410
-     */
411
-    public function removeAll()
412
-    {
413
-        // TODO: Implement removeAll() method.
414
-    }
415
-
416
-    /**
417
-     * Finds an object matching the given identifier.
418
-     *
419
-     * @param mixed $identifier The identifier of the object to find
420
-     * @return Content|null
421
-     * @api
422
-     */
423
-    public function findByIdentifier($identifier)
424
-    {
425
-        $query = $this->createQuery();
426
-
427
-        $result = $query->matching($query->equals('uid', $identifier))
428
-            ->execute();
429
-
430
-        if (is_array($result)) {
431
-            $result = current($result);
432
-        }
433
-
434
-        return $result;
435
-    }
436
-
437
-    /**
438
-     * Dispatches magic methods (findBy[Property]())
439
-     *
440
-     * @param string $methodName The name of the magic method
441
-     * @param string $arguments The arguments of the magic method
442
-     * @throws UnsupportedMethodException
443
-     * @return mixed
444
-     * @api
445
-     */
446
-    public function __call($methodName, $arguments)
447
-    {
448
-        if (substr($methodName, 0, 6) === 'findBy' && strlen($methodName) > 7) {
449
-            $propertyName = strtolower(substr(substr($methodName, 6), 0, 1)) . substr(substr($methodName, 6), 1);
450
-            $result = $this->processMagicCall($propertyName, $arguments[0]);
451
-        } elseif (substr($methodName, 0, 9) === 'findOneBy' && strlen($methodName) > 10) {
452
-            $propertyName = strtolower(substr(substr($methodName, 9), 0, 1)) . substr(substr($methodName, 9), 1);
453
-            $result = $this->processMagicCall($propertyName, $arguments[0], 'one');
454
-        } elseif (substr($methodName, 0, 7) === 'countBy' && strlen($methodName) > 8) {
455
-            $propertyName = strtolower(substr(substr($methodName, 7), 0, 1)) . substr(substr($methodName, 7), 1);
456
-            $result = $this->processMagicCall($propertyName, $arguments[0], 'count');
457
-        } else {
458
-            throw new UnsupportedMethodException('The method "' . $methodName . '" is not supported by the repository.', 1360838010);
459
-        }
460
-        return $result;
461
-    }
462
-
463
-    /**
464
-     * Returns a query for objects of this repository
465
-     *
466
-     * @return Query
467
-     * @api
468
-     */
469
-    public function createQuery()
470
-    {
471
-        /** @var Query $query */
472
-        $query = $this->getObjectManager()->get(Query::class, $this->dataType);
473
-        $query->setSourceFieldName($this->sourceFieldName);
474
-
475
-        if ($this->defaultQuerySettings) {
476
-            $query->setQuerySettings($this->defaultQuerySettings);
477
-        } else {
478
-
479
-            // Initialize and pass the query settings at this level.
480
-            /** @var QuerySettings $querySettings */
481
-            $querySettings = $this->getObjectManager()->get(QuerySettings::class);
482
-
483
-            // Default choice for the BE.
484
-            if ($this->isBackendMode()) {
485
-                $querySettings->setIgnoreEnableFields(true);
486
-            }
487
-
488
-            $query->setQuerySettings($querySettings);
489
-        }
490
-
491
-        return $query;
492
-    }
493
-
494
-    /**
495
-     * Sets the property names to order the result by per default.
496
-     * Expected like this:
497
-     * array(
498
-     * 'foo' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_ASCENDING,
499
-     * 'bar' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_DESCENDING
500
-     * )
501
-     *
502
-     * @param array $defaultOrderings The property names to order by
503
-     * @throws \BadMethodCallException
504
-     * @return void
505
-     * @api
506
-     */
507
-    public function setDefaultOrderings(array $defaultOrderings)
508
-    {
509
-        throw new \BadMethodCallException('Repository does not support the setDefaultOrderings() method.', 1375805598);
510
-    }
511
-
512
-    /**
513
-     * Sets the default query settings to be used in this repository
514
-     *
515
-     * @param QuerySettingsInterface $defaultQuerySettings The query settings to be used by default
516
-     * @throws \BadMethodCallException
517
-     * @return void
518
-     * @api
519
-     */
520
-    public function setDefaultQuerySettings(QuerySettingsInterface $defaultQuerySettings)
521
-    {
522
-        $this->defaultQuerySettings = $defaultQuerySettings;
523
-    }
524
-
525
-    /**
526
-     * @return array
527
-     */
528
-    public function getErrorMessages()
529
-    {
530
-        return $this->errorMessages;
531
-    }
532
-
533
-    /**
534
-     * @param string $sourceFieldName
535
-     * @return $this
536
-     */
537
-    public function setSourceFieldName($sourceFieldName)
538
-    {
539
-        $this->sourceFieldName = $sourceFieldName;
540
-        return $this;
541
-    }
542
-
543
-    /**
544
-     * @return string
545
-     */
546
-    public function getDataType()
547
-    {
548
-        return $this->dataType;
549
-    }
550
-
551
-    /**
552
-     * Tell whether the order has a foreign table in its expression, e.g. "metadata.title".
553
-     *
554
-     * @param string $ordering
555
-     * @return bool
556
-     */
557
-    protected function hasForeignRelationIn($ordering)
558
-    {
559
-        return strpos($ordering, '.') !== false;
560
-    }
561
-
562
-    /**
563
-     * Extract the foreign relation of the ordering "metadata.title" -> "metadata"
564
-     *
565
-     * @param string $ordering
566
-     * @return string
567
-     */
568
-    protected function getForeignRelationFrom($ordering)
569
-    {
570
-        $parts = explode('.', $ordering);
571
-        return $parts[0];
572
-    }
573
-
574
-    /**
575
-     * Get the constraints
576
-     *
577
-     * @param Query $query
578
-     * @param Matcher $matcher
579
-     * @return ConstraintInterface|null
580
-     */
581
-    protected function computeConstraints(Query $query, Matcher $matcher)
582
-    {
583
-
584
-        $constraints = null;
585
-
586
-        $collectedConstraints = array();
587
-
588
-        // Search term
589
-        $constraint = $this->computeSearchTermConstraint($query, $matcher);
590
-        if ($constraint) {
591
-            $collectedConstraints[] = $constraint;
592
-        }
593
-
594
-        foreach ($matcher->getSupportedOperators() as $operator) {
595
-            $constraint = $this->computeConstraint($query, $matcher, $operator);
596
-            if ($constraint) {
597
-                $collectedConstraints[] = $constraint;
598
-            }
599
-        }
600
-
601
-        if (count($collectedConstraints) > 1) {
602
-            $logical = $matcher->getDefaultLogicalSeparator();
603
-            $constraints = $query->$logical($collectedConstraints);
604
-        } elseif (!empty($collectedConstraints)) {
605
-
606
-            // true means there is one constraint only and should become the result
607
-            $constraints = current($collectedConstraints);
608
-        }
609
-
610
-        // Trigger signal for post processing the computed constraints object.
611
-        $constraints = $this->emitPostProcessConstraintsSignal($query, $constraints);
612
-
613
-        return $constraints;
614
-    }
615
-
616
-    /**
617
-     * Computes the search constraint and returns it.
618
-     *
619
-     * @param Query $query
620
-     * @param Matcher $matcher
621
-     * @return ConstraintInterface|null
622
-     */
623
-    protected function computeSearchTermConstraint(Query $query, Matcher $matcher)
624
-    {
625
-
626
-        $result = null;
627
-
628
-        // Search term case
629
-        if ($matcher->getSearchTerm()) {
630
-
631
-            $fields = GeneralUtility::trimExplode(',', Tca::table($this->dataType)->getSearchFields(), true);
632
-
633
-            $constraints = array();
634
-            $likeClause = sprintf('%%%s%%', $matcher->getSearchTerm());
635
-            foreach ($fields as $fieldNameAndPath) {
636
-                if ($this->isSuitableForLike($fieldNameAndPath, $matcher->getSearchTerm())) {
637
-
638
-                    $dataType = $this->getFieldPathResolver()->getDataType($fieldNameAndPath, $this->dataType);
639
-                    $fieldName = $this->getFieldPathResolver()->stripFieldPath($fieldNameAndPath, $this->dataType);
640
-
641
-                    if (Tca::table($dataType)->hasField($fieldName) && Tca::table($dataType)->field($fieldName)->hasRelation()) {
642
-                        $foreignTable = Tca::table($dataType)->field($fieldName)->getForeignTable();
643
-                        $fieldNameAndPath = $fieldNameAndPath . '.' . Tca::table($foreignTable)->getLabelField();
644
-                    }
645
-                    $constraints[] = $query->like($fieldNameAndPath, $likeClause);
646
-                }
647
-            }
648
-            $logical = $matcher->getLogicalSeparatorForSearchTerm();
649
-            $result = $query->$logical($constraints);
650
-        }
651
-
652
-        return $result;
653
-    }
654
-
655
-    /**
656
-     * It does not make sense to have a "like" in presence of numerical field, e.g "uid".
657
-     * Tell whether the given value makes sense for a "like" clause.
658
-     *
659
-     * @param string $fieldNameAndPath
660
-     * @param string $value
661
-     * @return bool
662
-     */
663
-    protected function isSuitableForLike($fieldNameAndPath, $value)
664
-    {
665
-        $isSuitable = true;
666
-
667
-        // true means it is a string
668
-        if (!MathUtility::canBeInterpretedAsInteger($value)) {
669
-
670
-            $dataType = $this->getFieldPathResolver()->getDataType($fieldNameAndPath, $this->dataType);
671
-            $fieldName = $this->getFieldPathResolver()->stripFieldPath($fieldNameAndPath, $this->dataType);
672
-
673
-            if (Tca::table($dataType)->field($fieldName)->isNumerical()
674
-                && !Tca::table($dataType)->field($fieldName)->hasRelation()
675
-            ) {
676
-                $isSuitable = false;
677
-            }
678
-        }
679
-
680
-        return $isSuitable;
681
-    }
682
-
683
-    /**
684
-     * Computes the constraint for matches and returns it.
685
-     *
686
-     * @param Query $query
687
-     * @param Matcher $matcher
688
-     * @param string $operator
689
-     * @return ConstraintInterface|null
690
-     */
691
-    protected function computeConstraint(Query $query, Matcher $matcher, $operator)
692
-    {
693
-        $result = null;
694
-
695
-        $operatorName = ucfirst($operator);
696
-        $getCriteria = sprintf('get%s', $operatorName);
697
-        $criteria = $matcher->$getCriteria();
698
-
699
-        if (!empty($criteria)) {
700
-            $constraints = array();
701
-
702
-            foreach ($criteria as $criterion) {
703
-
704
-                $fieldNameAndPath = $criterion['fieldNameAndPath'];
705
-                $operand = $criterion['operand'];
706
-
707
-                // Compute a few variables...
708
-                // $dataType is generally equals to $this->dataType but not always... if fieldName is a path.
709
-                $dataType = $this->getFieldPathResolver()->getDataType($fieldNameAndPath, $this->dataType);
710
-                $fieldName = $this->getFieldPathResolver()->stripFieldPath($fieldNameAndPath, $this->dataType);
711
-                $fieldPath = $this->getFieldPathResolver()->stripFieldName($fieldNameAndPath, $this->dataType);
712
-
713
-                if (Tca::table($dataType)->field($fieldName)->hasRelation()) {
714
-                    if (MathUtility::canBeInterpretedAsInteger($operand)) {
715
-                        $fieldNameAndPath = $fieldName . '.uid';
716
-                    } else {
717
-                        $foreignTableName = Tca::table($dataType)->field($fieldName)->getForeignTable();
718
-                        $foreignTable = Tca::table($foreignTableName);
719
-                        $fieldNameAndPath = $fieldName . '.' . $foreignTable->getLabelField();
720
-                    }
721
-
722
-                    // If different means we should restore the prepended path segment for proper SQL parser.
723
-                    // This is true for a composite field, e.g items.sys_file_metadata for categories.
724
-                    if ($fieldName !== $fieldPath) {
725
-                        $fieldNameAndPath = $fieldPath . '.' . $fieldNameAndPath;
726
-                    }
727
-                }
728
-
729
-                $constraints[] = $query->$operator($fieldNameAndPath, $criterion['operand']);
730
-            }
731
-
732
-            $getLogicalSeparator = sprintf('getLogicalSeparatorFor%s', $operatorName);
733
-            $logical = $matcher->$getLogicalSeparator();
734
-            $result = $query->$logical($constraints);
735
-        }
736
-
737
-        return $result;
738
-    }
739
-
740
-    /**
741
-     * @return DataHandler
742
-     */
743
-    protected function getDataHandler()
744
-    {
745
-        if (!$this->dataHandler) {
746
-            $this->dataHandler = GeneralUtility::makeInstance(DataHandler::class);
747
-        }
748
-        return $this->dataHandler;
749
-    }
750
-
751
-    /**
752
-     * Handle the magic call by properly creating a Query object and returning its result.
753
-     *
754
-     * @param string $propertyName
755
-     * @param string $value
756
-     * @param string $flag
757
-     * @return array
758
-     */
759
-    protected function processMagicCall($propertyName, $value, $flag = '')
760
-    {
761
-
762
-        $fieldName = Property::name($propertyName)->of($this->dataType)->toFieldName();
763
-
764
-        /** @var $matcher Matcher */
765
-        $matcher = GeneralUtility::makeInstance(Matcher::class, array(), $this->getDataType());
766
-
767
-        $table = Tca::table($this->dataType);
768
-        if ($table->field($fieldName)->isGroup()) {
769
-
770
-            $valueParts = explode('.', $value, 2);
771
-            $fieldName = $fieldName . '.' . $valueParts[0];
772
-            $value = $valueParts[1];
773
-        }
774
-
775
-        $matcher->equals($fieldName, $value);
776
-
777
-        if ($flag == 'count') {
778
-            $result = $this->countBy($matcher);
779
-        } else {
780
-            $result = $this->findBy($matcher);
781
-        }
782
-        return $flag == 'one' && !empty($result) ? reset($result) : $result;
783
-    }
784
-
785
-    /**
786
-     * @return DataHandlerFactory
787
-     */
788
-    protected function getDataHandlerFactory()
789
-    {
790
-        return GeneralUtility::makeInstance(DataHandlerFactory::class);
791
-    }
792
-
793
-    /**
794
-     * Returns whether the current mode is Backend
795
-     *
796
-     * @return bool
797
-     */
798
-    protected function isBackendMode()
799
-    {
800
-        return TYPO3_MODE == 'BE';
801
-    }
802
-
803
-    /**
804
-     * @return FieldPathResolver
805
-     */
806
-    protected function getFieldPathResolver()
807
-    {
808
-        return GeneralUtility::makeInstance(FieldPathResolver::class);
809
-    }
810
-
811
-    /**
812
-     * @return ObjectManager
813
-     */
814
-    protected function getObjectManager()
815
-    {
816
-        return GeneralUtility::makeInstance(ObjectManager::class);
817
-    }
818
-
819
-    /**
820
-     * @return ContentValidator
821
-     */
822
-    protected function getContentValidator()
823
-    {
824
-        return GeneralUtility::makeInstance(ContentValidator::class);
825
-    }
826
-
827
-    /**
828
-     * @return LanguageValidator
829
-     */
830
-    protected function getLanguageValidator()
831
-    {
832
-        return GeneralUtility::makeInstance(LanguageValidator::class);
833
-    }
834
-
835
-    /**
836
-     * Signal that is called for post-processing the computed constraints object.
837
-     *
838
-     * @param Query $query
839
-     * @param ConstraintInterface|null $constraints
840
-     * @return ConstraintInterface|null $constraints
841
-     * @signal
842
-     */
843
-    protected function emitPostProcessConstraintsSignal(Query $query, $constraints)
844
-    {
845
-        $result = $this->getSignalSlotDispatcher()->dispatch(
846
-            self::class,
847
-            'postProcessConstraintsObject',
848
-            array(
849
-                $query,
850
-                $constraints
851
-            )
852
-        );
853
-
854
-        return $result[1];
855
-    }
856
-
857
-    /**
858
-     * @return \TYPO3\CMS\Extbase\SignalSlot\Dispatcher
859
-     */
860
-    protected function getSignalSlotDispatcher()
861
-    {
862
-        return $this->getObjectManager()->get(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class);
863
-    }
44
+	/**
45
+	 * Tell whether it is a raw result (array) or object being returned.
46
+	 *
47
+	 * @var bool
48
+	 */
49
+	protected $rawResult = false;
50
+
51
+	/**
52
+	 * The data type to be returned, e.g fe_users, fe_groups, tt_content, etc...
53
+	 *
54
+	 * @var string
55
+	 */
56
+	protected $dataType;
57
+
58
+	/**
59
+	 * The source field is useful in the context of MM relations to know who is the caller
60
+	 * e.g findByItems which eventually corresponds to a field name.
61
+	 *
62
+	 * @var string
63
+	 */
64
+	protected $sourceFieldName = '';
65
+
66
+	/**
67
+	 * @var array
68
+	 */
69
+	protected $errorMessages = array();
70
+
71
+	/**
72
+	 * @var QuerySettingsInterface
73
+	 */
74
+	protected $defaultQuerySettings;
75
+
76
+	/**
77
+	 * Constructor
78
+	 *
79
+	 * @param string $dataType
80
+	 */
81
+	public function __construct($dataType)
82
+	{
83
+		$this->dataType = $dataType;
84
+	}
85
+
86
+	/**
87
+	 * Returns all objects of this repository.
88
+	 *
89
+	 * @return Content[]
90
+	 */
91
+	public function findAll()
92
+	{
93
+		$query = $this->createQuery();
94
+		return $query->execute();
95
+	}
96
+
97
+	/**
98
+	 * Returns all "distinct" values for a given property.
99
+	 *
100
+	 * @param string $propertyName
101
+	 * @param Matcher $matcher
102
+	 * @return Content[]
103
+	 */
104
+	public function findDistinctValues($propertyName, Matcher $matcher = null)
105
+	{
106
+		$query = $this->createQuery();
107
+		$query->setDistinct($propertyName);
108
+
109
+		// Remove empty values from selection.
110
+		$constraint = $query->logicalNot($query->equals($propertyName, ''));
111
+
112
+		// Add some additional constraints from the Matcher object.
113
+		$matcherConstraint = null;
114
+		if (!is_null($matcher)) {
115
+			$matcherConstraint = $this->computeConstraints($query, $matcher);
116
+		}
117
+
118
+		// Assemble the final constraints or not.
119
+		if ($matcherConstraint) {
120
+			$query->logicalAnd($matcherConstraint, $constraint);
121
+			$query->matching($query->logicalAnd($matcherConstraint, $constraint));
122
+		} else {
123
+			$query->matching($constraint);
124
+		}
125
+
126
+		return $query->execute();
127
+	}
128
+
129
+	/**
130
+	 * Returns all "distinct" values for a given property.
131
+	 *
132
+	 * @param string $propertyName
133
+	 * @param Matcher $matcher
134
+	 * @return int
135
+	 */
136
+	public function countDistinctValues($propertyName, Matcher $matcher = null)
137
+	{
138
+		$query = $this->createQuery();
139
+		$query->setDistinct($propertyName);
140
+
141
+		// Remove empty values from selection.
142
+		$constraint = $query->logicalNot($query->equals($propertyName, ''));
143
+
144
+		// Add some additional constraints from the Matcher object.
145
+		$matcherConstraint = null;
146
+		if (!is_null($matcher)) {
147
+			$matcherConstraint = $this->computeConstraints($query, $matcher);
148
+		}
149
+
150
+		// Assemble the final constraints or not.
151
+		if ($matcherConstraint) {
152
+			$query->logicalAnd($matcherConstraint, $constraint);
153
+			$query->matching($query->logicalAnd($matcherConstraint, $constraint));
154
+		} else {
155
+			$query->matching($constraint);
156
+		}
157
+
158
+		return $query->count();
159
+	}
160
+
161
+	/**
162
+	 * Finds an object matching the given identifier.
163
+	 *
164
+	 * @param int $uid The identifier of the object to find
165
+	 * @return Content|null
166
+	 * @api
167
+	 */
168
+	public function findByUid($uid)
169
+	{
170
+		return $this->findByIdentifier($uid);
171
+	}
172
+
173
+	/**
174
+	 * Finds all Contents given specified matches.
175
+	 *
176
+	 * @param string $propertyName
177
+	 * @param array $values
178
+	 * @return Content[]
179
+	 */
180
+	public function findIn($propertyName, array $values)
181
+	{
182
+		$query = $this->createQuery();
183
+		$query->matching($query->in($propertyName, $values));
184
+		return $query->execute();
185
+	}
186
+
187
+	/**
188
+	 * Finds all Contents given specified matches.
189
+	 *
190
+	 * @param Matcher $matcher
191
+	 * @param Order $order The order
192
+	 * @param int $limit
193
+	 * @param int $offset
194
+	 * @return Content[]
195
+	 */
196
+	public function findBy(Matcher $matcher, Order $order = null, $limit = null, $offset = null)
197
+	{
198
+
199
+		$query = $this->createQuery();
200
+
201
+		$limit = (int)$limit; // make sure to cast
202
+		if ($limit > 0) {
203
+			$query->setLimit($limit);
204
+		}
205
+
206
+		if ($order) {
207
+			$query->setOrderings($order->getOrderings());
208
+
209
+			// Loops around the orderings adding if necessary a dummy condition
210
+			// to make sure the relations can be resolved when transforming the query to plain SQL.
211
+			foreach ($order->getOrderings() as $ordering => $direction) {
212
+				if ($this->hasForeignRelationIn($ordering)) {
213
+					$relationalField = $this->getForeignRelationFrom($ordering);
214
+					$matcher->like($relationalField . '.uid', '');
215
+				}
216
+			}
217
+		}
218
+
219
+		if ($offset) {
220
+			$query->setOffset($offset);
221
+		}
222
+
223
+		$constraints = $this->computeConstraints($query, $matcher);
224
+
225
+		if ($constraints) {
226
+			$query->matching($constraints);
227
+		}
228
+
229
+		return $query->execute();
230
+	}
231
+
232
+	/**
233
+	 * Find one Content object given specified matches.
234
+	 *
235
+	 * @param Matcher $matcher
236
+	 * @return Content
237
+	 */
238
+	public function findOneBy(Matcher $matcher)
239
+	{
240
+
241
+		$query = $this->createQuery();
242
+
243
+		$constraints = $this->computeConstraints($query, $matcher);
244
+
245
+		if ($constraints) {
246
+			$query->matching($constraints);
247
+		}
248
+
249
+		$query->setLimit(1); // only take one!
250
+
251
+		$resultSet = $query->execute();
252
+		if ($resultSet) {
253
+			$resultSet = current($resultSet);
254
+		}
255
+		return $resultSet;
256
+	}
257
+
258
+	/**
259
+	 * Count all Contents given specified matches.
260
+	 *
261
+	 * @param Matcher $matcher
262
+	 * @return int
263
+	 */
264
+	public function countBy(Matcher $matcher)
265
+	{
266
+
267
+		$query = $this->createQuery();
268
+
269
+		$constraints = $this->computeConstraints($query, $matcher);
270
+
271
+		if ($constraints) {
272
+			$query->matching($constraints);
273
+		}
274
+
275
+		return $query->count();
276
+	}
277
+
278
+	/**
279
+	 * Update a content with new information.
280
+	 *
281
+	 * @param Content $content
282
+	 * @param $language
283
+	 * @return bool
284
+	 */
285
+	public function localize($content, $language)
286
+	{
287
+
288
+		// Security check
289
+		$this->getContentValidator()->validate($content);
290
+		$this->getLanguageValidator()->validate($language);
291
+
292
+		$dataType = $content->getDataType();
293
+		$handler = $this->getDataHandlerFactory()->action(ProcessAction::LOCALIZE)->forType($dataType)->getDataHandler();
294
+
295
+		$handlerResult = $handler->processLocalize($content, $language);
296
+		$this->errorMessages = $handler->getErrorMessages();
297
+		return $handlerResult;
298
+	}
299
+
300
+	/**
301
+	 * Update a content with new information.
302
+	 *
303
+	 * @param Content $content
304
+	 * @return bool
305
+	 */
306
+	public function update($content)
307
+	{
308
+
309
+		// Security check.
310
+		$this->getContentValidator()->validate($content);
311
+
312
+		$dataType = $content->getDataType();
313
+		$handler = $this->getDataHandlerFactory()->action(ProcessAction::UPDATE)->forType($dataType)->getDataHandler();
314
+
315
+		$handlerResult = $handler->processUpdate($content);
316
+		$this->errorMessages = $handler->getErrorMessages();
317
+		return $handlerResult;
318
+	}
319
+
320
+	/**
321
+	 * Removes an object from this repository.
322
+	 *
323
+	 * @param Content $content
324
+	 * @return boolean
325
+	 */
326
+	public function remove($content)
327
+	{
328
+		$dataType = $content->getDataType();
329
+		$handler = $this->getDataHandlerFactory()->action(ProcessAction::REMOVE)->forType($dataType)->getDataHandler();
330
+
331
+		$handlerResult = $handler->processRemove($content);
332
+		$this->errorMessages = $handler->getErrorMessages();
333
+		return $handlerResult;
334
+	}
335
+
336
+	/**
337
+	 * Move a content within this repository.
338
+	 * The $target corresponds to the pid to move the records to.
339
+	 * It can also be a negative value in case of sorting. The negative value would be the uid of its predecessor.
340
+	 *
341
+	 * @param Content $content
342
+	 * @param string $target
343
+	 * @return bool
344
+	 */
345
+	public function move($content, $target)
346
+	{
347
+
348
+		// Security check.
349
+		$this->getContentValidator()->validate($content);
350
+
351
+		$dataType = $content->getDataType();
352
+		$handler = $this->getDataHandlerFactory()->action(ProcessAction::MOVE)->forType($dataType)->getDataHandler();
353
+
354
+		$handlerResult = $handler->processMove($content, $target);
355
+		$this->errorMessages = $handler->getErrorMessages();
356
+		return $handlerResult;
357
+	}
358
+
359
+	/**
360
+	 * Copy a content within this repository.
361
+	 *
362
+	 * @param Content $content
363
+	 * @return bool
364
+	 */
365
+	public function copy($content, $target)
366
+	{
367
+
368
+		// Security check.
369
+		$this->getContentValidator()->validate($content);
370
+
371
+		$dataType = $content->getDataType();
372
+		$handler = $this->getDataHandlerFactory()->action(ProcessAction::COPY)->forType($dataType)->getDataHandler();
373
+
374
+		$handlerResult = $handler->processCopy($content, $target);
375
+		$this->errorMessages = $handler->getErrorMessages();
376
+		return $handlerResult;
377
+	}
378
+
379
+	/**
380
+	 * Adds an object to this repository.
381
+	 *
382
+	 * @param object $object The object to add
383
+	 * @throws \BadMethodCallException
384
+	 * @return void
385
+	 * @api
386
+	 */
387
+	public function add($object)
388
+	{
389
+		throw new \BadMethodCallException('Repository does not support the add() method.', 1375805599);
390
+	}
391
+
392
+	/**
393
+	 * Returns the total number objects of this repository.
394
+	 *
395
+	 * @return integer The object count
396
+	 * @api
397
+	 */
398
+	public function countAll()
399
+	{
400
+		$query = $this->createQuery();
401
+		return $query->count();
402
+	}
403
+
404
+	/**
405
+	 * Removes all objects of this repository as if remove() was called for
406
+	 * all of them.
407
+	 *
408
+	 * @return void
409
+	 * @api
410
+	 */
411
+	public function removeAll()
412
+	{
413
+		// TODO: Implement removeAll() method.
414
+	}
415
+
416
+	/**
417
+	 * Finds an object matching the given identifier.
418
+	 *
419
+	 * @param mixed $identifier The identifier of the object to find
420
+	 * @return Content|null
421
+	 * @api
422
+	 */
423
+	public function findByIdentifier($identifier)
424
+	{
425
+		$query = $this->createQuery();
426
+
427
+		$result = $query->matching($query->equals('uid', $identifier))
428
+			->execute();
429
+
430
+		if (is_array($result)) {
431
+			$result = current($result);
432
+		}
433
+
434
+		return $result;
435
+	}
436
+
437
+	/**
438
+	 * Dispatches magic methods (findBy[Property]())
439
+	 *
440
+	 * @param string $methodName The name of the magic method
441
+	 * @param string $arguments The arguments of the magic method
442
+	 * @throws UnsupportedMethodException
443
+	 * @return mixed
444
+	 * @api
445
+	 */
446
+	public function __call($methodName, $arguments)
447
+	{
448
+		if (substr($methodName, 0, 6) === 'findBy' && strlen($methodName) > 7) {
449
+			$propertyName = strtolower(substr(substr($methodName, 6), 0, 1)) . substr(substr($methodName, 6), 1);
450
+			$result = $this->processMagicCall($propertyName, $arguments[0]);
451
+		} elseif (substr($methodName, 0, 9) === 'findOneBy' && strlen($methodName) > 10) {
452
+			$propertyName = strtolower(substr(substr($methodName, 9), 0, 1)) . substr(substr($methodName, 9), 1);
453
+			$result = $this->processMagicCall($propertyName, $arguments[0], 'one');
454
+		} elseif (substr($methodName, 0, 7) === 'countBy' && strlen($methodName) > 8) {
455
+			$propertyName = strtolower(substr(substr($methodName, 7), 0, 1)) . substr(substr($methodName, 7), 1);
456
+			$result = $this->processMagicCall($propertyName, $arguments[0], 'count');
457
+		} else {
458
+			throw new UnsupportedMethodException('The method "' . $methodName . '" is not supported by the repository.', 1360838010);
459
+		}
460
+		return $result;
461
+	}
462
+
463
+	/**
464
+	 * Returns a query for objects of this repository
465
+	 *
466
+	 * @return Query
467
+	 * @api
468
+	 */
469
+	public function createQuery()
470
+	{
471
+		/** @var Query $query */
472
+		$query = $this->getObjectManager()->get(Query::class, $this->dataType);
473
+		$query->setSourceFieldName($this->sourceFieldName);
474
+
475
+		if ($this->defaultQuerySettings) {
476
+			$query->setQuerySettings($this->defaultQuerySettings);
477
+		} else {
478
+
479
+			// Initialize and pass the query settings at this level.
480
+			/** @var QuerySettings $querySettings */
481
+			$querySettings = $this->getObjectManager()->get(QuerySettings::class);
482
+
483
+			// Default choice for the BE.
484
+			if ($this->isBackendMode()) {
485
+				$querySettings->setIgnoreEnableFields(true);
486
+			}
487
+
488
+			$query->setQuerySettings($querySettings);
489
+		}
490
+
491
+		return $query;
492
+	}
493
+
494
+	/**
495
+	 * Sets the property names to order the result by per default.
496
+	 * Expected like this:
497
+	 * array(
498
+	 * 'foo' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_ASCENDING,
499
+	 * 'bar' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_DESCENDING
500
+	 * )
501
+	 *
502
+	 * @param array $defaultOrderings The property names to order by
503
+	 * @throws \BadMethodCallException
504
+	 * @return void
505
+	 * @api
506
+	 */
507
+	public function setDefaultOrderings(array $defaultOrderings)
508
+	{
509
+		throw new \BadMethodCallException('Repository does not support the setDefaultOrderings() method.', 1375805598);
510
+	}
511
+
512
+	/**
513
+	 * Sets the default query settings to be used in this repository
514
+	 *
515
+	 * @param QuerySettingsInterface $defaultQuerySettings The query settings to be used by default
516
+	 * @throws \BadMethodCallException
517
+	 * @return void
518
+	 * @api
519
+	 */
520
+	public function setDefaultQuerySettings(QuerySettingsInterface $defaultQuerySettings)
521
+	{
522
+		$this->defaultQuerySettings = $defaultQuerySettings;
523
+	}
524
+
525
+	/**
526
+	 * @return array
527
+	 */
528
+	public function getErrorMessages()
529
+	{
530
+		return $this->errorMessages;
531
+	}
532
+
533
+	/**
534
+	 * @param string $sourceFieldName
535
+	 * @return $this
536
+	 */
537
+	public function setSourceFieldName($sourceFieldName)
538
+	{
539
+		$this->sourceFieldName = $sourceFieldName;
540
+		return $this;
541
+	}
542
+
543
+	/**
544
+	 * @return string
545
+	 */
546
+	public function getDataType()
547
+	{
548
+		return $this->dataType;
549
+	}
550
+
551
+	/**
552
+	 * Tell whether the order has a foreign table in its expression, e.g. "metadata.title".
553
+	 *
554
+	 * @param string $ordering
555
+	 * @return bool
556
+	 */
557
+	protected function hasForeignRelationIn($ordering)
558
+	{
559
+		return strpos($ordering, '.') !== false;
560
+	}
561
+
562
+	/**
563
+	 * Extract the foreign relation of the ordering "metadata.title" -> "metadata"
564
+	 *
565
+	 * @param string $ordering
566
+	 * @return string
567
+	 */
568
+	protected function getForeignRelationFrom($ordering)
569
+	{
570
+		$parts = explode('.', $ordering);
571
+		return $parts[0];
572
+	}
573
+
574
+	/**
575
+	 * Get the constraints
576
+	 *
577
+	 * @param Query $query
578
+	 * @param Matcher $matcher
579
+	 * @return ConstraintInterface|null
580
+	 */
581
+	protected function computeConstraints(Query $query, Matcher $matcher)
582
+	{
583
+
584
+		$constraints = null;
585
+
586
+		$collectedConstraints = array();
587
+
588
+		// Search term
589
+		$constraint = $this->computeSearchTermConstraint($query, $matcher);
590
+		if ($constraint) {
591
+			$collectedConstraints[] = $constraint;
592
+		}
593
+
594
+		foreach ($matcher->getSupportedOperators() as $operator) {
595
+			$constraint = $this->computeConstraint($query, $matcher, $operator);
596
+			if ($constraint) {
597
+				$collectedConstraints[] = $constraint;
598
+			}
599
+		}
600
+
601
+		if (count($collectedConstraints) > 1) {
602
+			$logical = $matcher->getDefaultLogicalSeparator();
603
+			$constraints = $query->$logical($collectedConstraints);
604
+		} elseif (!empty($collectedConstraints)) {
605
+
606
+			// true means there is one constraint only and should become the result
607
+			$constraints = current($collectedConstraints);
608
+		}
609
+
610
+		// Trigger signal for post processing the computed constraints object.
611
+		$constraints = $this->emitPostProcessConstraintsSignal($query, $constraints);
612
+
613
+		return $constraints;
614
+	}
615
+
616
+	/**
617
+	 * Computes the search constraint and returns it.
618
+	 *
619
+	 * @param Query $query
620
+	 * @param Matcher $matcher
621
+	 * @return ConstraintInterface|null
622
+	 */
623
+	protected function computeSearchTermConstraint(Query $query, Matcher $matcher)
624
+	{
625
+
626
+		$result = null;
627
+
628
+		// Search term case
629
+		if ($matcher->getSearchTerm()) {
630
+
631
+			$fields = GeneralUtility::trimExplode(',', Tca::table($this->dataType)->getSearchFields(), true);
632
+
633
+			$constraints = array();
634
+			$likeClause = sprintf('%%%s%%', $matcher->getSearchTerm());
635
+			foreach ($fields as $fieldNameAndPath) {
636
+				if ($this->isSuitableForLike($fieldNameAndPath, $matcher->getSearchTerm())) {
637
+
638
+					$dataType = $this->getFieldPathResolver()->getDataType($fieldNameAndPath, $this->dataType);
639
+					$fieldName = $this->getFieldPathResolver()->stripFieldPath($fieldNameAndPath, $this->dataType);
640
+
641
+					if (Tca::table($dataType)->hasField($fieldName) && Tca::table($dataType)->field($fieldName)->hasRelation()) {
642
+						$foreignTable = Tca::table($dataType)->field($fieldName)->getForeignTable();
643
+						$fieldNameAndPath = $fieldNameAndPath . '.' . Tca::table($foreignTable)->getLabelField();
644
+					}
645
+					$constraints[] = $query->like($fieldNameAndPath, $likeClause);
646
+				}
647
+			}
648
+			$logical = $matcher->getLogicalSeparatorForSearchTerm();
649
+			$result = $query->$logical($constraints);
650
+		}
651
+
652
+		return $result;
653
+	}
654
+
655
+	/**
656
+	 * It does not make sense to have a "like" in presence of numerical field, e.g "uid".
657
+	 * Tell whether the given value makes sense for a "like" clause.
658
+	 *
659
+	 * @param string $fieldNameAndPath
660
+	 * @param string $value
661
+	 * @return bool
662
+	 */
663
+	protected function isSuitableForLike($fieldNameAndPath, $value)
664
+	{
665
+		$isSuitable = true;
666
+
667
+		// true means it is a string
668
+		if (!MathUtility::canBeInterpretedAsInteger($value)) {
669
+
670
+			$dataType = $this->getFieldPathResolver()->getDataType($fieldNameAndPath, $this->dataType);
671
+			$fieldName = $this->getFieldPathResolver()->stripFieldPath($fieldNameAndPath, $this->dataType);
672
+
673
+			if (Tca::table($dataType)->field($fieldName)->isNumerical()
674
+				&& !Tca::table($dataType)->field($fieldName)->hasRelation()
675
+			) {
676
+				$isSuitable = false;
677
+			}
678
+		}
679
+
680
+		return $isSuitable;
681
+	}
682
+
683
+	/**
684
+	 * Computes the constraint for matches and returns it.
685
+	 *
686
+	 * @param Query $query
687
+	 * @param Matcher $matcher
688
+	 * @param string $operator
689
+	 * @return ConstraintInterface|null
690
+	 */
691
+	protected function computeConstraint(Query $query, Matcher $matcher, $operator)
692
+	{
693
+		$result = null;
694
+
695
+		$operatorName = ucfirst($operator);
696
+		$getCriteria = sprintf('get%s', $operatorName);
697
+		$criteria = $matcher->$getCriteria();
698
+
699
+		if (!empty($criteria)) {
700
+			$constraints = array();
701
+
702
+			foreach ($criteria as $criterion) {
703
+
704
+				$fieldNameAndPath = $criterion['fieldNameAndPath'];
705
+				$operand = $criterion['operand'];
706
+
707
+				// Compute a few variables...
708
+				// $dataType is generally equals to $this->dataType but not always... if fieldName is a path.
709
+				$dataType = $this->getFieldPathResolver()->getDataType($fieldNameAndPath, $this->dataType);
710
+				$fieldName = $this->getFieldPathResolver()->stripFieldPath($fieldNameAndPath, $this->dataType);
711
+				$fieldPath = $this->getFieldPathResolver()->stripFieldName($fieldNameAndPath, $this->dataType);
712
+
713
+				if (Tca::table($dataType)->field($fieldName)->hasRelation()) {
714
+					if (MathUtility::canBeInterpretedAsInteger($operand)) {
715
+						$fieldNameAndPath = $fieldName . '.uid';
716
+					} else {
717
+						$foreignTableName = Tca::table($dataType)->field($fieldName)->getForeignTable();
718
+						$foreignTable = Tca::table($foreignTableName);
719
+						$fieldNameAndPath = $fieldName . '.' . $foreignTable->getLabelField();
720
+					}
721
+
722
+					// If different means we should restore the prepended path segment for proper SQL parser.
723
+					// This is true for a composite field, e.g items.sys_file_metadata for categories.
724
+					if ($fieldName !== $fieldPath) {
725
+						$fieldNameAndPath = $fieldPath . '.' . $fieldNameAndPath;
726
+					}
727
+				}
728
+
729
+				$constraints[] = $query->$operator($fieldNameAndPath, $criterion['operand']);
730
+			}
731
+
732
+			$getLogicalSeparator = sprintf('getLogicalSeparatorFor%s', $operatorName);
733
+			$logical = $matcher->$getLogicalSeparator();
734
+			$result = $query->$logical($constraints);
735
+		}
736
+
737
+		return $result;
738
+	}
739
+
740
+	/**
741
+	 * @return DataHandler
742
+	 */
743
+	protected function getDataHandler()
744
+	{
745
+		if (!$this->dataHandler) {
746
+			$this->dataHandler = GeneralUtility::makeInstance(DataHandler::class);
747
+		}
748
+		return $this->dataHandler;
749
+	}
750
+
751
+	/**
752
+	 * Handle the magic call by properly creating a Query object and returning its result.
753
+	 *
754
+	 * @param string $propertyName
755
+	 * @param string $value
756
+	 * @param string $flag
757
+	 * @return array
758
+	 */
759
+	protected function processMagicCall($propertyName, $value, $flag = '')
760
+	{
761
+
762
+		$fieldName = Property::name($propertyName)->of($this->dataType)->toFieldName();
763
+
764
+		/** @var $matcher Matcher */
765
+		$matcher = GeneralUtility::makeInstance(Matcher::class, array(), $this->getDataType());
766
+
767
+		$table = Tca::table($this->dataType);
768
+		if ($table->field($fieldName)->isGroup()) {
769
+
770
+			$valueParts = explode('.', $value, 2);
771
+			$fieldName = $fieldName . '.' . $valueParts[0];
772
+			$value = $valueParts[1];
773
+		}
774
+
775
+		$matcher->equals($fieldName, $value);
776
+
777
+		if ($flag == 'count') {
778
+			$result = $this->countBy($matcher);
779
+		} else {
780
+			$result = $this->findBy($matcher);
781
+		}
782
+		return $flag == 'one' && !empty($result) ? reset($result) : $result;
783
+	}
784
+
785
+	/**
786
+	 * @return DataHandlerFactory
787
+	 */
788
+	protected function getDataHandlerFactory()
789
+	{
790
+		return GeneralUtility::makeInstance(DataHandlerFactory::class);
791
+	}
792
+
793
+	/**
794
+	 * Returns whether the current mode is Backend
795
+	 *
796
+	 * @return bool
797
+	 */
798
+	protected function isBackendMode()
799
+	{
800
+		return TYPO3_MODE == 'BE';
801
+	}
802
+
803
+	/**
804
+	 * @return FieldPathResolver
805
+	 */
806
+	protected function getFieldPathResolver()
807
+	{
808
+		return GeneralUtility::makeInstance(FieldPathResolver::class);
809
+	}
810
+
811
+	/**
812
+	 * @return ObjectManager
813
+	 */
814
+	protected function getObjectManager()
815
+	{
816
+		return GeneralUtility::makeInstance(ObjectManager::class);
817
+	}
818
+
819
+	/**
820
+	 * @return ContentValidator
821
+	 */
822
+	protected function getContentValidator()
823
+	{
824
+		return GeneralUtility::makeInstance(ContentValidator::class);
825
+	}
826
+
827
+	/**
828
+	 * @return LanguageValidator
829
+	 */
830
+	protected function getLanguageValidator()
831
+	{
832
+		return GeneralUtility::makeInstance(LanguageValidator::class);
833
+	}
834
+
835
+	/**
836
+	 * Signal that is called for post-processing the computed constraints object.
837
+	 *
838
+	 * @param Query $query
839
+	 * @param ConstraintInterface|null $constraints
840
+	 * @return ConstraintInterface|null $constraints
841
+	 * @signal
842
+	 */
843
+	protected function emitPostProcessConstraintsSignal(Query $query, $constraints)
844
+	{
845
+		$result = $this->getSignalSlotDispatcher()->dispatch(
846
+			self::class,
847
+			'postProcessConstraintsObject',
848
+			array(
849
+				$query,
850
+				$constraints
851
+			)
852
+		);
853
+
854
+		return $result[1];
855
+	}
856
+
857
+	/**
858
+	 * @return \TYPO3\CMS\Extbase\SignalSlot\Dispatcher
859
+	 */
860
+	protected function getSignalSlotDispatcher()
861
+	{
862
+		return $this->getObjectManager()->get(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class);
863
+	}
864 864
 
865 865
 }
Please login to merge, or discard this patch.
Classes/Service/ContentService.php 1 patch
Indentation   +125 added lines, -125 removed lines patch added patch discarded remove patch
@@ -30,129 +30,129 @@
 block discarded – undo
30 30
 class ContentService
31 31
 {
32 32
 
33
-    /**
34
-     * @var string
35
-     */
36
-    protected $dataType;
37
-
38
-    /**
39
-     * @var \Fab\Vidi\Domain\Model\Content[]
40
-     */
41
-    protected $objects = array();
42
-
43
-    /**
44
-     * @var int
45
-     */
46
-    protected $numberOfObjects = 0;
47
-
48
-    /**
49
-     * Constructor
50
-     *
51
-     * @param string $dataType
52
-     * @return ContentService
53
-     */
54
-    public function __construct($dataType = '')
55
-    {
56
-        if (empty($dataType)) {
57
-            $dataType = $this->getModuleLoader()->getDataType();
58
-        }
59
-        $this->dataType = $dataType;
60
-    }
61
-
62
-    /**
63
-     * Fetch the files given an object assuming
64
-     *
65
-     * @param Matcher $matcher
66
-     * @param Order $order The order
67
-     * @param int $limit
68
-     * @param int $offset
69
-     * @return $this
70
-     */
71
-    public function findBy(Matcher $matcher, Order $order = NULL, $limit = NULL, $offset = NULL)
72
-    {
73
-
74
-        // Query the repository.
75
-        $objects = ContentRepositoryFactory::getInstance($this->dataType)->findBy($matcher, $order, $limit, $offset);
76
-        $signalResult = $this->emitAfterFindContentObjectsSignal($objects, $matcher, $order, $limit, $offset);
77
-
78
-        // Reset objects variable after possible signal / slot processing.
79
-        $this->objects = $signalResult->getContentObjects();
80
-
81
-        // Count number of content objects.
82
-        if ($signalResult->getHasBeenProcessed()) {
83
-            $this->numberOfObjects = $signalResult->getNumberOfObjects();
84
-        } else {
85
-            $this->numberOfObjects = ContentRepositoryFactory::getInstance($this->dataType)->countBy($matcher);
86
-        }
87
-
88
-        return $this;
89
-    }
90
-
91
-    /**
92
-     * Signal that is called after the content objects have been found.
93
-     *
94
-     * @param array $contentObjects
95
-     * @param \Fab\Vidi\Persistence\Matcher $matcher
96
-     * @param Order $order
97
-     * @param int $limit
98
-     * @param int $offset
99
-     * @return AfterFindContentObjectsSignalArguments
100
-     * @throws \TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotException
101
-     * @throws \TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotReturnException
102
-     * @signal
103
-     */
104
-    protected function emitAfterFindContentObjectsSignal($contentObjects, Matcher $matcher, Order $order = NULL, $limit = 0, $offset = 0)
105
-    {
106
-
107
-        /** @var AfterFindContentObjectsSignalArguments $signalArguments */
108
-        $signalArguments = GeneralUtility::makeInstance(AfterFindContentObjectsSignalArguments::class);
109
-        $signalArguments->setDataType($this->dataType)
110
-            ->setContentObjects($contentObjects)
111
-            ->setMatcher($matcher)
112
-            ->setOrder($order)
113
-            ->setLimit($limit)
114
-            ->setOffset($offset)
115
-            ->setHasBeenProcessed(FALSE);
116
-
117
-        $signalResult = $this->getSignalSlotDispatcher()->dispatch(ContentService::class, 'afterFindContentObjects', array($signalArguments));
118
-        return $signalResult[0];
119
-    }
120
-
121
-    /**
122
-     * Get the Vidi Module Loader.
123
-     *
124
-     * @return ModuleLoader
125
-     */
126
-    protected function getModuleLoader()
127
-    {
128
-        return GeneralUtility::makeInstance(ModuleLoader::class);
129
-    }
130
-
131
-    /**
132
-     * Get the SignalSlot dispatcher.
133
-     *
134
-     * @return Dispatcher
135
-     */
136
-    protected function getSignalSlotDispatcher()
137
-    {
138
-        /** @var ObjectManager $objectManager */
139
-        $objectManager = GeneralUtility::makeInstance(ObjectManager::class);
140
-        return $objectManager->get(Dispatcher::class);
141
-    }
142
-
143
-    /**
144
-     * @return \Fab\Vidi\Domain\Model\Content[]
145
-     */
146
-    public function getObjects()
147
-    {
148
-        return $this->objects;
149
-    }
150
-
151
-    /**
152
-     * @return int
153
-     */
154
-    public function getNumberOfObjects()
155
-    {
156
-        return $this->numberOfObjects;
157
-    }
33
+	/**
34
+	 * @var string
35
+	 */
36
+	protected $dataType;
37
+
38
+	/**
39
+	 * @var \Fab\Vidi\Domain\Model\Content[]
40
+	 */
41
+	protected $objects = array();
42
+
43
+	/**
44
+	 * @var int
45
+	 */
46
+	protected $numberOfObjects = 0;
47
+
48
+	/**
49
+	 * Constructor
50
+	 *
51
+	 * @param string $dataType
52
+	 * @return ContentService
53
+	 */
54
+	public function __construct($dataType = '')
55
+	{
56
+		if (empty($dataType)) {
57
+			$dataType = $this->getModuleLoader()->getDataType();
58
+		}
59
+		$this->dataType = $dataType;
60
+	}
61
+
62
+	/**
63
+	 * Fetch the files given an object assuming
64
+	 *
65
+	 * @param Matcher $matcher
66
+	 * @param Order $order The order
67
+	 * @param int $limit
68
+	 * @param int $offset
69
+	 * @return $this
70
+	 */
71
+	public function findBy(Matcher $matcher, Order $order = NULL, $limit = NULL, $offset = NULL)
72
+	{
73
+
74
+		// Query the repository.
75
+		$objects = ContentRepositoryFactory::getInstance($this->dataType)->findBy($matcher, $order, $limit, $offset);
76
+		$signalResult = $this->emitAfterFindContentObjectsSignal($objects, $matcher, $order, $limit, $offset);
77
+
78
+		// Reset objects variable after possible signal / slot processing.
79
+		$this->objects = $signalResult->getContentObjects();
80
+
81
+		// Count number of content objects.
82
+		if ($signalResult->getHasBeenProcessed()) {
83
+			$this->numberOfObjects = $signalResult->getNumberOfObjects();
84
+		} else {
85
+			$this->numberOfObjects = ContentRepositoryFactory::getInstance($this->dataType)->countBy($matcher);
86
+		}
87
+
88
+		return $this;
89
+	}
90
+
91
+	/**
92
+	 * Signal that is called after the content objects have been found.
93
+	 *
94
+	 * @param array $contentObjects
95
+	 * @param \Fab\Vidi\Persistence\Matcher $matcher
96
+	 * @param Order $order
97
+	 * @param int $limit
98
+	 * @param int $offset
99
+	 * @return AfterFindContentObjectsSignalArguments
100
+	 * @throws \TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotException
101
+	 * @throws \TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotReturnException
102
+	 * @signal
103
+	 */
104
+	protected function emitAfterFindContentObjectsSignal($contentObjects, Matcher $matcher, Order $order = NULL, $limit = 0, $offset = 0)
105
+	{
106
+
107
+		/** @var AfterFindContentObjectsSignalArguments $signalArguments */
108
+		$signalArguments = GeneralUtility::makeInstance(AfterFindContentObjectsSignalArguments::class);
109
+		$signalArguments->setDataType($this->dataType)
110
+			->setContentObjects($contentObjects)
111
+			->setMatcher($matcher)
112
+			->setOrder($order)
113
+			->setLimit($limit)
114
+			->setOffset($offset)
115
+			->setHasBeenProcessed(FALSE);
116
+
117
+		$signalResult = $this->getSignalSlotDispatcher()->dispatch(ContentService::class, 'afterFindContentObjects', array($signalArguments));
118
+		return $signalResult[0];
119
+	}
120
+
121
+	/**
122
+	 * Get the Vidi Module Loader.
123
+	 *
124
+	 * @return ModuleLoader
125
+	 */
126
+	protected function getModuleLoader()
127
+	{
128
+		return GeneralUtility::makeInstance(ModuleLoader::class);
129
+	}
130
+
131
+	/**
132
+	 * Get the SignalSlot dispatcher.
133
+	 *
134
+	 * @return Dispatcher
135
+	 */
136
+	protected function getSignalSlotDispatcher()
137
+	{
138
+		/** @var ObjectManager $objectManager */
139
+		$objectManager = GeneralUtility::makeInstance(ObjectManager::class);
140
+		return $objectManager->get(Dispatcher::class);
141
+	}
142
+
143
+	/**
144
+	 * @return \Fab\Vidi\Domain\Model\Content[]
145
+	 */
146
+	public function getObjects()
147
+	{
148
+		return $this->objects;
149
+	}
150
+
151
+	/**
152
+	 * @return int
153
+	 */
154
+	public function getNumberOfObjects()
155
+	{
156
+		return $this->numberOfObjects;
157
+	}
158 158
 }
Please login to merge, or discard this patch.
Classes/Processor/MarkerProcessor.php 1 patch
Indentation   +109 added lines, -109 removed lines patch added patch discarded remove patch
@@ -26,114 +26,114 @@
 block discarded – undo
26 26
 class MarkerProcessor implements SingletonInterface
27 27
 {
28 28
 
29
-    /**
30
-     * @var array
31
-     */
32
-    protected $wellKnownMarkers = array(
33
-        '{*}',
34
-        '{counter}',
35
-        '{date}',
36
-        '{creation_date}'
37
-    );
38
-
39
-    /**
40
-     * @param ProcessContentDataSignalArguments $signalArguments
41
-     * @return array
42
-     */
43
-    public function processMarkers(ProcessContentDataSignalArguments $signalArguments)
44
-    {
45
-
46
-        $contentData = $signalArguments->getContentData();
47
-        $creationTime = $this->getCreationTime($signalArguments);
48
-
49
-        // Process markers
50
-        foreach ($signalArguments->getContentData() as $fieldName => $updateValue) {
51
-            if (is_scalar($updateValue)) {
52
-
53
-                $currentValue = $this->getContentObjectResolver()->getValue(
54
-                    $signalArguments->getContentObject(),
55
-                    $signalArguments->getFieldNameAndPath(),
56
-                    $fieldName,
57
-                    $signalArguments->getLanguage()
58
-                );
59
-                $counter = $signalArguments->getCounter();
60
-
61
-                $updateValue = $this->searchAndReplace($updateValue, $currentValue);
62
-                $updateValue = $this->replaceWellKnownMarkers($updateValue, $currentValue, $counter, $creationTime);
63
-
64
-                $contentData[$fieldName] = $updateValue;
65
-            }
66
-        }
67
-
68
-        $signalArguments->setContentData($contentData);
69
-        return array($signalArguments);
70
-    }
71
-
72
-    /**
73
-     * @param string $updateValue
74
-     * @param string $currentValue
75
-     * @param int $counter
76
-     * @param $creationTime
77
-     * @return string
78
-     */
79
-    protected function replaceWellKnownMarkers($updateValue, $currentValue, $counter, $creationTime)
80
-    {
81
-
82
-        // Replaces values.
83
-        $replaces = array(
84
-            $currentValue,
85
-            $counter,
86
-            date($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy']),
87
-            date($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'], $creationTime),
88
-        );
89
-
90
-        // Replace me!
91
-        return str_replace($this->wellKnownMarkers, $replaces, $updateValue);
92
-    }
93
-
94
-    /**
95
-     * @param string $updateValue
96
-     * @param string $currentValue
97
-     * @return string
98
-     */
99
-    protected function searchAndReplace($updateValue, $currentValue)
100
-    {
101
-
102
-        if (strpos($updateValue, 's/') !== FALSE) {
103
-            $structure = explode('/', $updateValue);
104
-            $search = $structure[1];
105
-            $replace = $structure[2];
106
-
107
-            // Perhaps needs to be improved here if $search contains "/" precisely.
108
-            $updateValue = preg_replace('/' . $search . '/isU', $replace, $currentValue);
109
-        }
110
-        return $updateValue;
111
-    }
112
-
113
-    /**
114
-     * @param ProcessContentDataSignalArguments $signalArguments
115
-     * @return int
116
-     */
117
-    protected function getCreationTime(ProcessContentDataSignalArguments $signalArguments)
118
-    {
119
-        $creationTime = 0;
120
-        $creationTimeField = Tca::table($signalArguments->getContentObject()->getDataType())->getTimeCreationField();
121
-        if ($creationTimeField) {
122
-            $creationTime = $this->getContentObjectResolver()->getValue(
123
-                $signalArguments->getContentObject(),
124
-                $signalArguments->getFieldNameAndPath(),
125
-                $creationTimeField
126
-            );
127
-        }
128
-        return $creationTime;
129
-    }
130
-
131
-    /**
132
-     * @return ContentObjectResolver
133
-     */
134
-    protected function getContentObjectResolver()
135
-    {
136
-        return GeneralUtility::makeInstance(ContentObjectResolver::class);
137
-    }
29
+	/**
30
+	 * @var array
31
+	 */
32
+	protected $wellKnownMarkers = array(
33
+		'{*}',
34
+		'{counter}',
35
+		'{date}',
36
+		'{creation_date}'
37
+	);
38
+
39
+	/**
40
+	 * @param ProcessContentDataSignalArguments $signalArguments
41
+	 * @return array
42
+	 */
43
+	public function processMarkers(ProcessContentDataSignalArguments $signalArguments)
44
+	{
45
+
46
+		$contentData = $signalArguments->getContentData();
47
+		$creationTime = $this->getCreationTime($signalArguments);
48
+
49
+		// Process markers
50
+		foreach ($signalArguments->getContentData() as $fieldName => $updateValue) {
51
+			if (is_scalar($updateValue)) {
52
+
53
+				$currentValue = $this->getContentObjectResolver()->getValue(
54
+					$signalArguments->getContentObject(),
55
+					$signalArguments->getFieldNameAndPath(),
56
+					$fieldName,
57
+					$signalArguments->getLanguage()
58
+				);
59
+				$counter = $signalArguments->getCounter();
60
+
61
+				$updateValue = $this->searchAndReplace($updateValue, $currentValue);
62
+				$updateValue = $this->replaceWellKnownMarkers($updateValue, $currentValue, $counter, $creationTime);
63
+
64
+				$contentData[$fieldName] = $updateValue;
65
+			}
66
+		}
67
+
68
+		$signalArguments->setContentData($contentData);
69
+		return array($signalArguments);
70
+	}
71
+
72
+	/**
73
+	 * @param string $updateValue
74
+	 * @param string $currentValue
75
+	 * @param int $counter
76
+	 * @param $creationTime
77
+	 * @return string
78
+	 */
79
+	protected function replaceWellKnownMarkers($updateValue, $currentValue, $counter, $creationTime)
80
+	{
81
+
82
+		// Replaces values.
83
+		$replaces = array(
84
+			$currentValue,
85
+			$counter,
86
+			date($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy']),
87
+			date($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'], $creationTime),
88
+		);
89
+
90
+		// Replace me!
91
+		return str_replace($this->wellKnownMarkers, $replaces, $updateValue);
92
+	}
93
+
94
+	/**
95
+	 * @param string $updateValue
96
+	 * @param string $currentValue
97
+	 * @return string
98
+	 */
99
+	protected function searchAndReplace($updateValue, $currentValue)
100
+	{
101
+
102
+		if (strpos($updateValue, 's/') !== FALSE) {
103
+			$structure = explode('/', $updateValue);
104
+			$search = $structure[1];
105
+			$replace = $structure[2];
106
+
107
+			// Perhaps needs to be improved here if $search contains "/" precisely.
108
+			$updateValue = preg_replace('/' . $search . '/isU', $replace, $currentValue);
109
+		}
110
+		return $updateValue;
111
+	}
112
+
113
+	/**
114
+	 * @param ProcessContentDataSignalArguments $signalArguments
115
+	 * @return int
116
+	 */
117
+	protected function getCreationTime(ProcessContentDataSignalArguments $signalArguments)
118
+	{
119
+		$creationTime = 0;
120
+		$creationTimeField = Tca::table($signalArguments->getContentObject()->getDataType())->getTimeCreationField();
121
+		if ($creationTimeField) {
122
+			$creationTime = $this->getContentObjectResolver()->getValue(
123
+				$signalArguments->getContentObject(),
124
+				$signalArguments->getFieldNameAndPath(),
125
+				$creationTimeField
126
+			);
127
+		}
128
+		return $creationTime;
129
+	}
130
+
131
+	/**
132
+	 * @return ContentObjectResolver
133
+	 */
134
+	protected function getContentObjectResolver()
135
+	{
136
+		return GeneralUtility::makeInstance(ContentObjectResolver::class);
137
+	}
138 138
 
139 139
 }
Please login to merge, or discard this patch.
Classes/Persistence/MatcherObjectFactory.php 1 patch
Indentation   +218 added lines, -218 removed lines patch added patch discarded remove patch
@@ -30,222 +30,222 @@
 block discarded – undo
30 30
 class MatcherObjectFactory implements SingletonInterface
31 31
 {
32 32
 
33
-    /**
34
-     * Gets a singleton instance of this class.
35
-     *
36
-     * @return $this
37
-     */
38
-    static public function getInstance()
39
-    {
40
-        return GeneralUtility::makeInstance(self::class);
41
-    }
42
-
43
-    /**
44
-     * Returns a matcher object.
45
-     *
46
-     * @param array $matches
47
-     * @param string $dataType
48
-     * @return Matcher
49
-     */
50
-    public function getMatcher(array $matches = array(), $dataType = '')
51
-    {
52
-
53
-        if (empty($dataType)) {
54
-            $dataType = $this->getModuleLoader()->getDataType();
55
-        }
56
-
57
-        /** @var $matcher Matcher */
58
-        $matcher = GeneralUtility::makeInstance(Matcher::class, array(), $dataType);
59
-
60
-        $matcher = $this->applyCriteriaFromDataTables($matcher, $dataType);
61
-        $matcher = $this->applyCriteriaFromMatchesArgument($matcher, $matches);
62
-
63
-        if ($this->isBackendMode()) {
64
-            $matcher = $this->applyCriteriaFromUrl($matcher);
65
-        }
66
-
67
-        // Trigger signal for post processing Matcher Object.
68
-        $this->emitPostProcessMatcherObjectSignal($matcher);
69
-
70
-        return $matcher;
71
-    }
72
-
73
-    /**
74
-     * Get a possible id from the URL and apply as filter criteria.
75
-     * Except if the main module belongs to the File. The id would be a combined identifier
76
-     * including the storage and a mount point.
77
-     *
78
-     * @param Matcher $matcher
79
-     * @return Matcher $matcher
80
-     */
81
-    protected function applyCriteriaFromUrl(Matcher $matcher)
82
-    {
83
-
84
-        if (GeneralUtility::_GP('id') && $this->getModuleLoader()->getMainModule() !== ModuleName::FILE) {
85
-            $matcher->equals('pid', GeneralUtility::_GP('id'));
86
-        }
87
-
88
-        return $matcher;
89
-    }
90
-
91
-    /**
92
-     * Apply criteria specific to jQuery plugin Datatable.
93
-     *
94
-     * @param Matcher $matcher
95
-     * @param array $matches
96
-     * @return Matcher $matcher
97
-     */
98
-    protected function applyCriteriaFromMatchesArgument(Matcher $matcher, $matches)
99
-    {
100
-        foreach ($matches as $fieldNameAndPath => $value) {
101
-            // CSV values should be considered as "in" operator in Query, otherwise "equals".
102
-            $explodedValues = GeneralUtility::trimExplode(',', $value, TRUE);
103
-            if (count($explodedValues) > 1) {
104
-                $matcher->in($fieldNameAndPath, $explodedValues);
105
-            } else {
106
-                $matcher->equals($fieldNameAndPath, $explodedValues[0]);
107
-            }
108
-        }
109
-
110
-        return $matcher;
111
-    }
112
-
113
-    /**
114
-     * Apply criteria specific to jQuery plugin DataTable.
115
-     *
116
-     * @param Matcher $matcher
117
-     * @param string $dataType
118
-     * @return Matcher $matcher
119
-     */
120
-    protected function applyCriteriaFromDataTables(Matcher $matcher, $dataType)
121
-    {
122
-
123
-        // Special case for Grid in the BE using jQuery DataTables plugin.
124
-        // Retrieve a possible search term from GP.
125
-        $query = GeneralUtility::_GP('search');
126
-        if (is_array($query)) {
127
-            if (!empty($query['value'])) {
128
-                $query = $query['value'];
129
-            } else {
130
-                $query = '';
131
-            }
132
-        }
133
-
134
-        if (strlen($query) > 0) {
135
-
136
-            // Parse the json query coming from the Visual Search.
137
-            $query = rawurldecode($query);
138
-            $queryParts = json_decode($query, TRUE);
139
-
140
-            if (is_array($queryParts)) {
141
-                foreach ($queryParts as $term) {
142
-                    $fieldNameAndPath = key($term);
143
-
144
-                    $resolvedDataType = $this->getFieldPathResolver()->getDataType($fieldNameAndPath, $dataType);
145
-                    $fieldName = $this->getFieldPathResolver()->stripFieldPath($fieldNameAndPath, $dataType);
146
-
147
-                    // Retrieve the value.
148
-                    $value = current($term);
149
-
150
-                    if (Tca::grid($resolvedDataType)->hasFacet($fieldName) && Tca::grid($resolvedDataType)->facet($fieldName)->canModifyMatcher()) {
151
-                        $matcher = Tca::grid($resolvedDataType)->facet($fieldName)->modifyMatcher($matcher, $value);
152
-                    } elseif (Tca::table($resolvedDataType)->hasField($fieldName)) {
153
-                        // Check whether the field exists and set it as "equal" or "like".
154
-                        if ($this->isOperatorEquals($fieldNameAndPath, $dataType, $value)) {
155
-                            $matcher->equals($fieldNameAndPath, $value);
156
-                        } else {
157
-                            $matcher->like($fieldNameAndPath, $value);
158
-                        }
159
-                    } elseif ($fieldNameAndPath === 'text') {
160
-                        // Special case if field is "text" which is a pseudo field in this case.
161
-                        // Set the search term which means Vidi will
162
-                        // search in various fields with operator "like". The fields come from key "searchFields" in the TCA.
163
-                        $matcher->setSearchTerm($value);
164
-                    }
165
-                }
166
-            } else {
167
-                $matcher->setSearchTerm($query);
168
-            }
169
-        }
170
-        return $matcher;
171
-    }
172
-
173
-    /**
174
-     * Tell whether the operator should be equals instead of like for a search, e.g. if the value is numerical.
175
-     *
176
-     * @param string $fieldName
177
-     * @param string $dataType
178
-     * @param string $value
179
-     * @return bool
180
-     */
181
-    protected function isOperatorEquals($fieldName, $dataType, $value)
182
-    {
183
-        return (Tca::table($dataType)->field($fieldName)->hasRelation() && MathUtility::canBeInterpretedAsInteger($value))
184
-        || Tca::table($dataType)->field($fieldName)->isNumerical();
185
-    }
186
-
187
-    /**
188
-     * Signal that is called for post-processing a matcher object.
189
-     *
190
-     * @param Matcher $matcher
191
-     * @signal
192
-     */
193
-    protected function emitPostProcessMatcherObjectSignal(Matcher $matcher)
194
-    {
195
-
196
-        if (strlen($matcher->getDataType()) <= 0) {
197
-
198
-            /** @var ModuleLoader $moduleLoader */
199
-            $moduleLoader = $this->getObjectManager()->get(ModuleLoader::class);
200
-            $matcher->setDataType($moduleLoader->getDataType());
201
-        }
202
-
203
-        $this->getSignalSlotDispatcher()->dispatch('Fab\Vidi\Controller\Backend\ContentController', 'postProcessMatcherObject', array($matcher, $matcher->getDataType()));
204
-    }
205
-
206
-    /**
207
-     * Get the SignalSlot dispatcher
208
-     *
209
-     * @return Dispatcher
210
-     */
211
-    protected function getSignalSlotDispatcher()
212
-    {
213
-        return $this->getObjectManager()->get(Dispatcher::class);
214
-    }
215
-
216
-    /**
217
-     * @return ObjectManager
218
-     */
219
-    protected function getObjectManager()
220
-    {
221
-        return GeneralUtility::makeInstance(ObjectManager::class);
222
-    }
223
-
224
-    /**
225
-     * Get the Vidi Module Loader.
226
-     *
227
-     * @return ModuleLoader
228
-     */
229
-    protected function getModuleLoader()
230
-    {
231
-        return GeneralUtility::makeInstance(ModuleLoader::class);
232
-    }
233
-
234
-    /**
235
-     * @return FieldPathResolver
236
-     */
237
-    protected function getFieldPathResolver()
238
-    {
239
-        return GeneralUtility::makeInstance(FieldPathResolver::class);
240
-    }
241
-
242
-    /**
243
-     * Returns whether the current mode is Backend
244
-     *
245
-     * @return bool
246
-     */
247
-    protected function isBackendMode()
248
-    {
249
-        return TYPO3_MODE === 'BE';
250
-    }
33
+	/**
34
+	 * Gets a singleton instance of this class.
35
+	 *
36
+	 * @return $this
37
+	 */
38
+	static public function getInstance()
39
+	{
40
+		return GeneralUtility::makeInstance(self::class);
41
+	}
42
+
43
+	/**
44
+	 * Returns a matcher object.
45
+	 *
46
+	 * @param array $matches
47
+	 * @param string $dataType
48
+	 * @return Matcher
49
+	 */
50
+	public function getMatcher(array $matches = array(), $dataType = '')
51
+	{
52
+
53
+		if (empty($dataType)) {
54
+			$dataType = $this->getModuleLoader()->getDataType();
55
+		}
56
+
57
+		/** @var $matcher Matcher */
58
+		$matcher = GeneralUtility::makeInstance(Matcher::class, array(), $dataType);
59
+
60
+		$matcher = $this->applyCriteriaFromDataTables($matcher, $dataType);
61
+		$matcher = $this->applyCriteriaFromMatchesArgument($matcher, $matches);
62
+
63
+		if ($this->isBackendMode()) {
64
+			$matcher = $this->applyCriteriaFromUrl($matcher);
65
+		}
66
+
67
+		// Trigger signal for post processing Matcher Object.
68
+		$this->emitPostProcessMatcherObjectSignal($matcher);
69
+
70
+		return $matcher;
71
+	}
72
+
73
+	/**
74
+	 * Get a possible id from the URL and apply as filter criteria.
75
+	 * Except if the main module belongs to the File. The id would be a combined identifier
76
+	 * including the storage and a mount point.
77
+	 *
78
+	 * @param Matcher $matcher
79
+	 * @return Matcher $matcher
80
+	 */
81
+	protected function applyCriteriaFromUrl(Matcher $matcher)
82
+	{
83
+
84
+		if (GeneralUtility::_GP('id') && $this->getModuleLoader()->getMainModule() !== ModuleName::FILE) {
85
+			$matcher->equals('pid', GeneralUtility::_GP('id'));
86
+		}
87
+
88
+		return $matcher;
89
+	}
90
+
91
+	/**
92
+	 * Apply criteria specific to jQuery plugin Datatable.
93
+	 *
94
+	 * @param Matcher $matcher
95
+	 * @param array $matches
96
+	 * @return Matcher $matcher
97
+	 */
98
+	protected function applyCriteriaFromMatchesArgument(Matcher $matcher, $matches)
99
+	{
100
+		foreach ($matches as $fieldNameAndPath => $value) {
101
+			// CSV values should be considered as "in" operator in Query, otherwise "equals".
102
+			$explodedValues = GeneralUtility::trimExplode(',', $value, TRUE);
103
+			if (count($explodedValues) > 1) {
104
+				$matcher->in($fieldNameAndPath, $explodedValues);
105
+			} else {
106
+				$matcher->equals($fieldNameAndPath, $explodedValues[0]);
107
+			}
108
+		}
109
+
110
+		return $matcher;
111
+	}
112
+
113
+	/**
114
+	 * Apply criteria specific to jQuery plugin DataTable.
115
+	 *
116
+	 * @param Matcher $matcher
117
+	 * @param string $dataType
118
+	 * @return Matcher $matcher
119
+	 */
120
+	protected function applyCriteriaFromDataTables(Matcher $matcher, $dataType)
121
+	{
122
+
123
+		// Special case for Grid in the BE using jQuery DataTables plugin.
124
+		// Retrieve a possible search term from GP.
125
+		$query = GeneralUtility::_GP('search');
126
+		if (is_array($query)) {
127
+			if (!empty($query['value'])) {
128
+				$query = $query['value'];
129
+			} else {
130
+				$query = '';
131
+			}
132
+		}
133
+
134
+		if (strlen($query) > 0) {
135
+
136
+			// Parse the json query coming from the Visual Search.
137
+			$query = rawurldecode($query);
138
+			$queryParts = json_decode($query, TRUE);
139
+
140
+			if (is_array($queryParts)) {
141
+				foreach ($queryParts as $term) {
142
+					$fieldNameAndPath = key($term);
143
+
144
+					$resolvedDataType = $this->getFieldPathResolver()->getDataType($fieldNameAndPath, $dataType);
145
+					$fieldName = $this->getFieldPathResolver()->stripFieldPath($fieldNameAndPath, $dataType);
146
+
147
+					// Retrieve the value.
148
+					$value = current($term);
149
+
150
+					if (Tca::grid($resolvedDataType)->hasFacet($fieldName) && Tca::grid($resolvedDataType)->facet($fieldName)->canModifyMatcher()) {
151
+						$matcher = Tca::grid($resolvedDataType)->facet($fieldName)->modifyMatcher($matcher, $value);
152
+					} elseif (Tca::table($resolvedDataType)->hasField($fieldName)) {
153
+						// Check whether the field exists and set it as "equal" or "like".
154
+						if ($this->isOperatorEquals($fieldNameAndPath, $dataType, $value)) {
155
+							$matcher->equals($fieldNameAndPath, $value);
156
+						} else {
157
+							$matcher->like($fieldNameAndPath, $value);
158
+						}
159
+					} elseif ($fieldNameAndPath === 'text') {
160
+						// Special case if field is "text" which is a pseudo field in this case.
161
+						// Set the search term which means Vidi will
162
+						// search in various fields with operator "like". The fields come from key "searchFields" in the TCA.
163
+						$matcher->setSearchTerm($value);
164
+					}
165
+				}
166
+			} else {
167
+				$matcher->setSearchTerm($query);
168
+			}
169
+		}
170
+		return $matcher;
171
+	}
172
+
173
+	/**
174
+	 * Tell whether the operator should be equals instead of like for a search, e.g. if the value is numerical.
175
+	 *
176
+	 * @param string $fieldName
177
+	 * @param string $dataType
178
+	 * @param string $value
179
+	 * @return bool
180
+	 */
181
+	protected function isOperatorEquals($fieldName, $dataType, $value)
182
+	{
183
+		return (Tca::table($dataType)->field($fieldName)->hasRelation() && MathUtility::canBeInterpretedAsInteger($value))
184
+		|| Tca::table($dataType)->field($fieldName)->isNumerical();
185
+	}
186
+
187
+	/**
188
+	 * Signal that is called for post-processing a matcher object.
189
+	 *
190
+	 * @param Matcher $matcher
191
+	 * @signal
192
+	 */
193
+	protected function emitPostProcessMatcherObjectSignal(Matcher $matcher)
194
+	{
195
+
196
+		if (strlen($matcher->getDataType()) <= 0) {
197
+
198
+			/** @var ModuleLoader $moduleLoader */
199
+			$moduleLoader = $this->getObjectManager()->get(ModuleLoader::class);
200
+			$matcher->setDataType($moduleLoader->getDataType());
201
+		}
202
+
203
+		$this->getSignalSlotDispatcher()->dispatch('Fab\Vidi\Controller\Backend\ContentController', 'postProcessMatcherObject', array($matcher, $matcher->getDataType()));
204
+	}
205
+
206
+	/**
207
+	 * Get the SignalSlot dispatcher
208
+	 *
209
+	 * @return Dispatcher
210
+	 */
211
+	protected function getSignalSlotDispatcher()
212
+	{
213
+		return $this->getObjectManager()->get(Dispatcher::class);
214
+	}
215
+
216
+	/**
217
+	 * @return ObjectManager
218
+	 */
219
+	protected function getObjectManager()
220
+	{
221
+		return GeneralUtility::makeInstance(ObjectManager::class);
222
+	}
223
+
224
+	/**
225
+	 * Get the Vidi Module Loader.
226
+	 *
227
+	 * @return ModuleLoader
228
+	 */
229
+	protected function getModuleLoader()
230
+	{
231
+		return GeneralUtility::makeInstance(ModuleLoader::class);
232
+	}
233
+
234
+	/**
235
+	 * @return FieldPathResolver
236
+	 */
237
+	protected function getFieldPathResolver()
238
+	{
239
+		return GeneralUtility::makeInstance(FieldPathResolver::class);
240
+	}
241
+
242
+	/**
243
+	 * Returns whether the current mode is Backend
244
+	 *
245
+	 * @return bool
246
+	 */
247
+	protected function isBackendMode()
248
+	{
249
+		return TYPO3_MODE === 'BE';
250
+	}
251 251
 }
Please login to merge, or discard this patch.
Classes/ViewHelpers/Result/ToXmlViewHelper.php 1 patch
Indentation   +104 added lines, -104 removed lines patch added patch discarded remove patch
@@ -22,118 +22,118 @@
 block discarded – undo
22 22
 class ToXmlViewHelper extends AbstractToFormatViewHelper
23 23
 {
24 24
 
25
-    /**
26
-     * Render an XML export.
27
-     *
28
-     * @return boolean
29
-     */
30
-    public function render()
31
-    {
32
-
33
-        $objects = $this->templateVariableContainer->get('objects');
34
-
35
-        // Make sure we have something to process...
36
-        if (!empty($objects)) {
37
-
38
-            // Initialization step.
39
-            $this->initializeEnvironment($objects);
40
-            $this->exportFileNameAndPath .= '.xml'; // add extension to the file.
41
-
42
-            // Write the exported data to a XML file.
43
-            $this->writeXmlFile($objects);
44
-
45
-            // We must generate a zip archive since there are files included.
46
-            if ($this->hasCollectedFiles()) {
47
-
48
-                $this->writeZipFile();
49
-                $this->sendZipHttpHeaders();
50
-
51
-                readfile($this->zipFileNameAndPath);
52
-            } else {
53
-                $this->sendXmlHttpHeaders();
54
-                readfile($this->exportFileNameAndPath);
55
-            }
56
-
57
-            GeneralUtility::rmdir($this->temporaryDirectory, TRUE);
58
-        }
59
-    }
60
-
61
-    /**
62
-     * Write the XML file to a temporary location.
63
-     *
64
-     * @param array $objects
65
-     * @return void
66
-     */
67
-    protected function writeXmlFile(array $objects)
68
-    {
69
-
70
-        // Get first object of $objects to check whether it contains possible files to include.
71
-        /** @var \Fab\Vidi\Domain\Model\Content $object */
72
-        $object = reset($objects);
73
-        $this->checkWhetherObjectMayIncludeFiles($object);
74
-
75
-        $items = array();
76
-        foreach ($objects as $object) {
77
-            if ($this->hasFileFields()) {
78
-                $this->collectFiles($object);
79
-            }
80
-            $items[] = $object->toValues();
81
-        }
82
-
83
-        $xml = new \SimpleXMLElement('<items/>');
84
-        $xml = $this->arrayToXml($items, $xml);
85
-        file_put_contents($this->exportFileNameAndPath, $this->formatXml($xml->asXML()));
86
-    }
87
-
88
-    /*
25
+	/**
26
+	 * Render an XML export.
27
+	 *
28
+	 * @return boolean
29
+	 */
30
+	public function render()
31
+	{
32
+
33
+		$objects = $this->templateVariableContainer->get('objects');
34
+
35
+		// Make sure we have something to process...
36
+		if (!empty($objects)) {
37
+
38
+			// Initialization step.
39
+			$this->initializeEnvironment($objects);
40
+			$this->exportFileNameAndPath .= '.xml'; // add extension to the file.
41
+
42
+			// Write the exported data to a XML file.
43
+			$this->writeXmlFile($objects);
44
+
45
+			// We must generate a zip archive since there are files included.
46
+			if ($this->hasCollectedFiles()) {
47
+
48
+				$this->writeZipFile();
49
+				$this->sendZipHttpHeaders();
50
+
51
+				readfile($this->zipFileNameAndPath);
52
+			} else {
53
+				$this->sendXmlHttpHeaders();
54
+				readfile($this->exportFileNameAndPath);
55
+			}
56
+
57
+			GeneralUtility::rmdir($this->temporaryDirectory, TRUE);
58
+		}
59
+	}
60
+
61
+	/**
62
+	 * Write the XML file to a temporary location.
63
+	 *
64
+	 * @param array $objects
65
+	 * @return void
66
+	 */
67
+	protected function writeXmlFile(array $objects)
68
+	{
69
+
70
+		// Get first object of $objects to check whether it contains possible files to include.
71
+		/** @var \Fab\Vidi\Domain\Model\Content $object */
72
+		$object = reset($objects);
73
+		$this->checkWhetherObjectMayIncludeFiles($object);
74
+
75
+		$items = array();
76
+		foreach ($objects as $object) {
77
+			if ($this->hasFileFields()) {
78
+				$this->collectFiles($object);
79
+			}
80
+			$items[] = $object->toValues();
81
+		}
82
+
83
+		$xml = new \SimpleXMLElement('<items/>');
84
+		$xml = $this->arrayToXml($items, $xml);
85
+		file_put_contents($this->exportFileNameAndPath, $this->formatXml($xml->asXML()));
86
+	}
87
+
88
+	/*
89 89
      * Convert an array to xml
90 90
      *
91 91
      * @return \SimpleXMLElement
92 92
      */
93
-    protected function arrayToXml($array, \SimpleXMLElement $xml)
94
-    {
95
-        foreach ($array as $key => $value) {
96
-            if (is_array($value)) {
97
-                $key = is_numeric($key) ? 'item' : $key;
98
-                $subNode = $xml->addChild($key);
99
-                $this->arrayToXml($value, $subNode);
100
-            } else {
101
-                $key = is_numeric($key) ? 'item' : $key;
102
-                $xml->addChild($key, "$value");
103
-            }
104
-        }
105
-        return $xml;
106
-    }
107
-
108
-    /*
93
+	protected function arrayToXml($array, \SimpleXMLElement $xml)
94
+	{
95
+		foreach ($array as $key => $value) {
96
+			if (is_array($value)) {
97
+				$key = is_numeric($key) ? 'item' : $key;
98
+				$subNode = $xml->addChild($key);
99
+				$this->arrayToXml($value, $subNode);
100
+			} else {
101
+				$key = is_numeric($key) ? 'item' : $key;
102
+				$xml->addChild($key, "$value");
103
+			}
104
+		}
105
+		return $xml;
106
+	}
107
+
108
+	/*
109 109
      * Format the XML so that is looks human friendly.
110 110
      *
111 111
      * @param string $xml
112 112
      * @return string
113 113
      */
114
-    protected function formatXml($xml)
115
-    {
116
-        $dom = new \DOMDocument("1.0");
117
-        $dom->preserveWhiteSpace = false;
118
-        $dom->formatOutput = true;
119
-        $dom->loadXML($xml);
120
-        return $dom->saveXML();
121
-    }
122
-
123
-    /**
124
-     * @return void
125
-     */
126
-    protected function sendXmlHttpHeaders()
127
-    {
128
-
129
-        /** @var \TYPO3\CMS\Extbase\Mvc\Web\Response $response */
130
-        $response = $this->templateVariableContainer->get('response');
131
-        $response->setHeader('Content-Type', 'application/xml');
132
-        $response->setHeader('Content-Disposition', 'attachment; filename="' . basename($this->exportFileNameAndPath) . '"');
133
-        $response->setHeader('Content-Length', filesize($this->exportFileNameAndPath));
134
-        $response->setHeader('Content-Description', 'File Transfer');
135
-
136
-        $response->sendHeaders();
137
-    }
114
+	protected function formatXml($xml)
115
+	{
116
+		$dom = new \DOMDocument("1.0");
117
+		$dom->preserveWhiteSpace = false;
118
+		$dom->formatOutput = true;
119
+		$dom->loadXML($xml);
120
+		return $dom->saveXML();
121
+	}
122
+
123
+	/**
124
+	 * @return void
125
+	 */
126
+	protected function sendXmlHttpHeaders()
127
+	{
128
+
129
+		/** @var \TYPO3\CMS\Extbase\Mvc\Web\Response $response */
130
+		$response = $this->templateVariableContainer->get('response');
131
+		$response->setHeader('Content-Type', 'application/xml');
132
+		$response->setHeader('Content-Disposition', 'attachment; filename="' . basename($this->exportFileNameAndPath) . '"');
133
+		$response->setHeader('Content-Length', filesize($this->exportFileNameAndPath));
134
+		$response->setHeader('Content-Description', 'File Transfer');
135
+
136
+		$response->sendHeaders();
137
+	}
138 138
 
139 139
 }
Please login to merge, or discard this patch.
Classes/ViewHelpers/Result/ToCsvViewHelper.php 1 patch
Indentation   +91 added lines, -91 removed lines patch added patch discarded remove patch
@@ -22,96 +22,96 @@
 block discarded – undo
22 22
 class ToCsvViewHelper extends AbstractToFormatViewHelper
23 23
 {
24 24
 
25
-    /**
26
-     * Render a CSV export request.
27
-     *
28
-     * @return boolean
29
-     */
30
-    public function render()
31
-    {
32
-
33
-        $objects = $this->templateVariableContainer->get('objects');
34
-
35
-        // Make sure we have something to process...
36
-        if (!empty($objects)) {
37
-
38
-            // Initialization step.
39
-            $this->initializeEnvironment($objects);
40
-            $this->exportFileNameAndPath .= '.csv'; // add extension to the file.
41
-
42
-            // Write the exported data to a CSV file.
43
-            $this->writeCsvFile($objects);
44
-
45
-            // We must generate a zip archive since there are files included.
46
-            if ($this->hasCollectedFiles()) {
47
-
48
-                $this->writeZipFile();
49
-                $this->sendZipHttpHeaders();
50
-
51
-                readfile($this->zipFileNameAndPath);
52
-            } else {
53
-                $this->sendCsvHttpHeaders();
54
-                readfile($this->exportFileNameAndPath);
55
-            }
56
-
57
-            GeneralUtility::rmdir($this->temporaryDirectory, TRUE);
58
-        }
59
-    }
60
-
61
-    /**
62
-     * Write the CSV file to a temporary location.
63
-     *
64
-     * @param array $objects
65
-     * @return void
66
-     */
67
-    protected function writeCsvFile(array $objects)
68
-    {
69
-
70
-        // Create a file pointer
71
-        $output = fopen($this->exportFileNameAndPath, 'w');
72
-
73
-        // Handle CSV header, get the first object and get the list of fields.
74
-        /** @var \Fab\Vidi\Domain\Model\Content $object */
75
-        $object = reset($objects);
76
-        fputcsv($output, $object->toFields());
77
-        $this->checkWhetherObjectMayIncludeFiles($object);
78
-
79
-        foreach ($objects as $object) {
80
-            if ($this->hasFileFields()) {
81
-                $this->collectFiles($object);
82
-            }
83
-
84
-            // Make sure we have a flat array of values for the CSV purpose.
85
-            $flattenValues = array();
86
-            foreach ($object->toValues() as $fieldName => $value) {
87
-                if (is_array($value)) {
88
-                    $flattenValues[$fieldName] = implode(', ', $value);
89
-                } else {
90
-                    $flattenValues[$fieldName] = str_replace("\n", "\r", $value); // for Excel purpose.
91
-                }
92
-            }
93
-
94
-            fputcsv($output, $flattenValues);
95
-        }
96
-
97
-        // close file handler
98
-        fclose($output);
99
-    }
100
-
101
-    /**
102
-     * @return void
103
-     */
104
-    protected function sendCsvHttpHeaders()
105
-    {
106
-
107
-        /** @var \TYPO3\CMS\Extbase\Mvc\Web\Response $response */
108
-        $response = $this->templateVariableContainer->get('response');
109
-        $response->setHeader('Content-Type', 'application/csv');
110
-        $response->setHeader('Content-Disposition', 'attachment; filename="' . basename($this->exportFileNameAndPath) . '"');
111
-        $response->setHeader('Content-Length', filesize($this->exportFileNameAndPath));
112
-        $response->setHeader('Content-Description', 'File Transfer');
113
-
114
-        $response->sendHeaders();
115
-    }
25
+	/**
26
+	 * Render a CSV export request.
27
+	 *
28
+	 * @return boolean
29
+	 */
30
+	public function render()
31
+	{
32
+
33
+		$objects = $this->templateVariableContainer->get('objects');
34
+
35
+		// Make sure we have something to process...
36
+		if (!empty($objects)) {
37
+
38
+			// Initialization step.
39
+			$this->initializeEnvironment($objects);
40
+			$this->exportFileNameAndPath .= '.csv'; // add extension to the file.
41
+
42
+			// Write the exported data to a CSV file.
43
+			$this->writeCsvFile($objects);
44
+
45
+			// We must generate a zip archive since there are files included.
46
+			if ($this->hasCollectedFiles()) {
47
+
48
+				$this->writeZipFile();
49
+				$this->sendZipHttpHeaders();
50
+
51
+				readfile($this->zipFileNameAndPath);
52
+			} else {
53
+				$this->sendCsvHttpHeaders();
54
+				readfile($this->exportFileNameAndPath);
55
+			}
56
+
57
+			GeneralUtility::rmdir($this->temporaryDirectory, TRUE);
58
+		}
59
+	}
60
+
61
+	/**
62
+	 * Write the CSV file to a temporary location.
63
+	 *
64
+	 * @param array $objects
65
+	 * @return void
66
+	 */
67
+	protected function writeCsvFile(array $objects)
68
+	{
69
+
70
+		// Create a file pointer
71
+		$output = fopen($this->exportFileNameAndPath, 'w');
72
+
73
+		// Handle CSV header, get the first object and get the list of fields.
74
+		/** @var \Fab\Vidi\Domain\Model\Content $object */
75
+		$object = reset($objects);
76
+		fputcsv($output, $object->toFields());
77
+		$this->checkWhetherObjectMayIncludeFiles($object);
78
+
79
+		foreach ($objects as $object) {
80
+			if ($this->hasFileFields()) {
81
+				$this->collectFiles($object);
82
+			}
83
+
84
+			// Make sure we have a flat array of values for the CSV purpose.
85
+			$flattenValues = array();
86
+			foreach ($object->toValues() as $fieldName => $value) {
87
+				if (is_array($value)) {
88
+					$flattenValues[$fieldName] = implode(', ', $value);
89
+				} else {
90
+					$flattenValues[$fieldName] = str_replace("\n", "\r", $value); // for Excel purpose.
91
+				}
92
+			}
93
+
94
+			fputcsv($output, $flattenValues);
95
+		}
96
+
97
+		// close file handler
98
+		fclose($output);
99
+	}
100
+
101
+	/**
102
+	 * @return void
103
+	 */
104
+	protected function sendCsvHttpHeaders()
105
+	{
106
+
107
+		/** @var \TYPO3\CMS\Extbase\Mvc\Web\Response $response */
108
+		$response = $this->templateVariableContainer->get('response');
109
+		$response->setHeader('Content-Type', 'application/csv');
110
+		$response->setHeader('Content-Disposition', 'attachment; filename="' . basename($this->exportFileNameAndPath) . '"');
111
+		$response->setHeader('Content-Length', filesize($this->exportFileNameAndPath));
112
+		$response->setHeader('Content-Description', 'File Transfer');
113
+
114
+		$response->sendHeaders();
115
+	}
116 116
 
117 117
 }
Please login to merge, or discard this patch.
Classes/ViewHelpers/Content/AbstractContentViewHelper.php 1 patch
Indentation   +210 added lines, -210 removed lines patch added patch discarded remove patch
@@ -31,215 +31,215 @@
 block discarded – undo
31 31
 abstract class AbstractContentViewHelper extends AbstractViewHelper
32 32
 {
33 33
 
34
-    /**
35
-     * @return void
36
-     */
37
-    public function initializeArguments()
38
-    {
39
-        $this->registerArgument('type', 'string', 'Corresponds to the type of data to be fetched. It will basically be a table name e.g. fe_users.', FALSE, '');
40
-        $this->registerArgument('matches', 'array', 'Key / value array to be used as filter. The key corresponds to a field name.', FALSE, array());
41
-        $this->registerArgument('selection', 'int', 'A possible selection defined in the BE and stored in the database.', FALSE, 0);
42
-        $this->registerArgument('ignoreEnableFields', 'bool', 'Whether to ignore enable fields or not (AKA hidden, deleted, starttime, ...).', FALSE, FALSE);
43
-        $this->registerArgument('aliases', 'array', 'Attribute "matches" does not support certain character such as "." in field name. Use this to create aliases.', FALSE, array());
44
-    }
45
-
46
-    /**
47
-     * Generate a signature to be used for storing the result set.
48
-     *
49
-     * @param string $dataType
50
-     * @param array $matches
51
-     * @param array $orderings
52
-     * @param $limit
53
-     * @param $offset
54
-     * @return string
55
-     */
56
-    protected function getQuerySignature($dataType, array $matches, array $orderings, $limit, $offset)
57
-    {
58
-        $serializedMatches = serialize($matches);
59
-        $serializedOrderings = serialize($orderings);
60
-        return md5($dataType . $serializedMatches . $serializedOrderings . $limit . $offset);
61
-    }
62
-
63
-    /**
64
-     * Returns a matcher object.
65
-     *
66
-     * @param string $dataType
67
-     * @param array $matches
68
-     * @return Matcher
69
-     */
70
-    protected function getMatcher($dataType, $matches = array())
71
-    {
72
-
73
-        /** @var $matcher Matcher */
74
-        $matcher = GeneralUtility::makeInstance('Fab\Vidi\Persistence\Matcher', array(), $dataType);
75
-
76
-        // @todo implement advanced selection parsing {or: {usergroup.title: {like: foo}}, {tstamp: {greaterThan: 1234}}}
77
-        foreach ($matches as $fieldNameAndPath => $value) {
78
-
79
-            // CSV values should be considered as "in" operator in Query, otherwise "equals".
80
-            $explodedValues = GeneralUtility::trimExplode(',', $value, TRUE);
81
-
82
-            // The matching value contains a "1,2" as example
83
-            if (count($explodedValues) > 1) {
84
-
85
-                $resolvedDataType = $this->getFieldPathResolver()->getDataType($fieldNameAndPath, $dataType);
86
-                $resolvedFieldName = $this->getFieldPathResolver()->stripFieldPath($fieldNameAndPath, $dataType);
87
-
88
-                // "equals" if in presence of a relation.
89
-                // "in" if not a relation.
90
-                if (Tca::table($resolvedDataType)->field($resolvedFieldName)->hasRelation()) {
91
-                    foreach ($explodedValues as $explodedValue) {
92
-                        $matcher->equals($fieldNameAndPath, $explodedValue);
93
-                    }
94
-                } else {
95
-                    $matcher->in($fieldNameAndPath, $explodedValues);
96
-                }
97
-            } else {
98
-                $matcher->equals($fieldNameAndPath, $explodedValues[0]);
99
-            }
100
-        }
101
-
102
-        // Trigger signal for post processing Matcher Object.
103
-        $this->emitPostProcessMatcherObjectSignal($matcher->getDataType(), $matcher);
104
-
105
-        return $matcher;
106
-    }
107
-
108
-    /**
109
-     * Replace possible aliases.
110
-     *
111
-     * @param array $values
112
-     * @return array
113
-     */
114
-    protected function replacesAliases(array $values)
115
-    {
116
-
117
-        $aliases = $this->arguments['aliases'];
118
-
119
-        foreach ($aliases as $aliasName => $aliasValue) {
120
-            if (isset($values[$aliasName])) {
121
-                $values[$aliasValue] = $values[$aliasName];
122
-                unset($values[$aliasName]); // remove the alias.
123
-            }
124
-        }
125
-
126
-        return $values;
127
-    }
128
-
129
-    /**
130
-     * Returns an order object.
131
-     *
132
-     * @param string $dataType
133
-     * @param array $order
134
-     * @return Order
135
-     */
136
-    public function getOrder($dataType, array $order = array())
137
-    {
138
-        // Default orderings in case order is empty.
139
-        if (empty($order)) {
140
-            $order = Tca::table($dataType)->getDefaultOrderings();
141
-        }
142
-
143
-        $order = GeneralUtility::makeInstance(Order::class, $order);
144
-
145
-        // Trigger signal for post processing Order Object.
146
-        $this->emitPostProcessOrderObjectSignal($dataType, $order);
147
-
148
-        return $order;
149
-    }
150
-
151
-    /**
152
-     * @return ResultSetStorage
153
-     */
154
-    public function getResultSetStorage()
155
-    {
156
-        return GeneralUtility::makeInstance(ResultSetStorage::class);
157
-    }
158
-
159
-    /**
160
-     * Signal that is called for post-processing a "order" object.
161
-     *
162
-     * @param string $dataType
163
-     * @param Order $order
164
-     * @signal
165
-     */
166
-    protected function emitPostProcessOrderObjectSignal($dataType, Order $order)
167
-    {
168
-        $this->getSignalSlotDispatcher()->dispatch('Fab\Vidi\ViewHelper\Content\AbstractContentViewHelper', 'postProcessOrderObject', array($order, $dataType));
169
-    }
170
-
171
-    /**
172
-     * Signal that is called for post-processing a "matcher" object.
173
-     *
174
-     * @param string $dataType
175
-     * @param Matcher $matcher
176
-     * @signal
177
-     */
178
-    protected function emitPostProcessMatcherObjectSignal($dataType, Matcher $matcher)
179
-    {
180
-        $this->getSignalSlotDispatcher()->dispatch('Fab\Vidi\ViewHelper\Content\AbstractContentViewHelper', 'postProcessMatcherObject', array($matcher, $dataType));
181
-    }
182
-
183
-    /**
184
-     * Signal that is called for post-processing a "limit".
185
-     *
186
-     * @param string $dataType
187
-     * @param int $limit
188
-     * @signal
189
-     */
190
-    protected function emitPostProcessLimitSignal($dataType, $limit)
191
-    {
192
-        $this->getSignalSlotDispatcher()->dispatch('Fab\Vidi\ViewHelper\Content\AbstractContentViewHelper', 'postProcessLimit', array($limit, $dataType));
193
-    }
194
-
195
-    /**
196
-     * Signal that is called for post-processing a "offset".
197
-     *
198
-     * @param string $dataType
199
-     * @param int $offset
200
-     * @signal
201
-     */
202
-    protected function emitPostProcessOffsetSignal($dataType, $offset)
203
-    {
204
-        $this->getSignalSlotDispatcher()->dispatch('Fab\Vidi\ViewHelper\Content\AbstractContentViewHelper', 'postProcessLimit', array($offset, $dataType));
205
-    }
206
-
207
-    /**
208
-     * Get the SignalSlot dispatcher
209
-     *
210
-     * @return Dispatcher
211
-     */
212
-    protected function getSignalSlotDispatcher()
213
-    {
214
-        return $this->getObjectManager()->get(Dispatcher::class);
215
-    }
216
-
217
-    /**
218
-     * @return ObjectManager
219
-     */
220
-    protected function getObjectManager()
221
-    {
222
-        return GeneralUtility::makeInstance(ObjectManager::class);
223
-    }
224
-
225
-    /**
226
-     * @param $ignoreEnableFields
227
-     * @return \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface
228
-     */
229
-    protected function getDefaultQuerySettings($ignoreEnableFields)
230
-    {
231
-        /** @var QuerySettings $defaultQuerySettings */
232
-        $defaultQuerySettings = GeneralUtility::makeInstance(QuerySettings::class);
233
-        $defaultQuerySettings->setIgnoreEnableFields($ignoreEnableFields);
234
-        return $defaultQuerySettings;
235
-    }
236
-
237
-    /**
238
-     * @return FieldPathResolver
239
-     */
240
-    protected function getFieldPathResolver()
241
-    {
242
-        return GeneralUtility::makeInstance(FieldPathResolver::class);
243
-    }
34
+	/**
35
+	 * @return void
36
+	 */
37
+	public function initializeArguments()
38
+	{
39
+		$this->registerArgument('type', 'string', 'Corresponds to the type of data to be fetched. It will basically be a table name e.g. fe_users.', FALSE, '');
40
+		$this->registerArgument('matches', 'array', 'Key / value array to be used as filter. The key corresponds to a field name.', FALSE, array());
41
+		$this->registerArgument('selection', 'int', 'A possible selection defined in the BE and stored in the database.', FALSE, 0);
42
+		$this->registerArgument('ignoreEnableFields', 'bool', 'Whether to ignore enable fields or not (AKA hidden, deleted, starttime, ...).', FALSE, FALSE);
43
+		$this->registerArgument('aliases', 'array', 'Attribute "matches" does not support certain character such as "." in field name. Use this to create aliases.', FALSE, array());
44
+	}
45
+
46
+	/**
47
+	 * Generate a signature to be used for storing the result set.
48
+	 *
49
+	 * @param string $dataType
50
+	 * @param array $matches
51
+	 * @param array $orderings
52
+	 * @param $limit
53
+	 * @param $offset
54
+	 * @return string
55
+	 */
56
+	protected function getQuerySignature($dataType, array $matches, array $orderings, $limit, $offset)
57
+	{
58
+		$serializedMatches = serialize($matches);
59
+		$serializedOrderings = serialize($orderings);
60
+		return md5($dataType . $serializedMatches . $serializedOrderings . $limit . $offset);
61
+	}
62
+
63
+	/**
64
+	 * Returns a matcher object.
65
+	 *
66
+	 * @param string $dataType
67
+	 * @param array $matches
68
+	 * @return Matcher
69
+	 */
70
+	protected function getMatcher($dataType, $matches = array())
71
+	{
72
+
73
+		/** @var $matcher Matcher */
74
+		$matcher = GeneralUtility::makeInstance('Fab\Vidi\Persistence\Matcher', array(), $dataType);
75
+
76
+		// @todo implement advanced selection parsing {or: {usergroup.title: {like: foo}}, {tstamp: {greaterThan: 1234}}}
77
+		foreach ($matches as $fieldNameAndPath => $value) {
78
+
79
+			// CSV values should be considered as "in" operator in Query, otherwise "equals".
80
+			$explodedValues = GeneralUtility::trimExplode(',', $value, TRUE);
81
+
82
+			// The matching value contains a "1,2" as example
83
+			if (count($explodedValues) > 1) {
84
+
85
+				$resolvedDataType = $this->getFieldPathResolver()->getDataType($fieldNameAndPath, $dataType);
86
+				$resolvedFieldName = $this->getFieldPathResolver()->stripFieldPath($fieldNameAndPath, $dataType);
87
+
88
+				// "equals" if in presence of a relation.
89
+				// "in" if not a relation.
90
+				if (Tca::table($resolvedDataType)->field($resolvedFieldName)->hasRelation()) {
91
+					foreach ($explodedValues as $explodedValue) {
92
+						$matcher->equals($fieldNameAndPath, $explodedValue);
93
+					}
94
+				} else {
95
+					$matcher->in($fieldNameAndPath, $explodedValues);
96
+				}
97
+			} else {
98
+				$matcher->equals($fieldNameAndPath, $explodedValues[0]);
99
+			}
100
+		}
101
+
102
+		// Trigger signal for post processing Matcher Object.
103
+		$this->emitPostProcessMatcherObjectSignal($matcher->getDataType(), $matcher);
104
+
105
+		return $matcher;
106
+	}
107
+
108
+	/**
109
+	 * Replace possible aliases.
110
+	 *
111
+	 * @param array $values
112
+	 * @return array
113
+	 */
114
+	protected function replacesAliases(array $values)
115
+	{
116
+
117
+		$aliases = $this->arguments['aliases'];
118
+
119
+		foreach ($aliases as $aliasName => $aliasValue) {
120
+			if (isset($values[$aliasName])) {
121
+				$values[$aliasValue] = $values[$aliasName];
122
+				unset($values[$aliasName]); // remove the alias.
123
+			}
124
+		}
125
+
126
+		return $values;
127
+	}
128
+
129
+	/**
130
+	 * Returns an order object.
131
+	 *
132
+	 * @param string $dataType
133
+	 * @param array $order
134
+	 * @return Order
135
+	 */
136
+	public function getOrder($dataType, array $order = array())
137
+	{
138
+		// Default orderings in case order is empty.
139
+		if (empty($order)) {
140
+			$order = Tca::table($dataType)->getDefaultOrderings();
141
+		}
142
+
143
+		$order = GeneralUtility::makeInstance(Order::class, $order);
144
+
145
+		// Trigger signal for post processing Order Object.
146
+		$this->emitPostProcessOrderObjectSignal($dataType, $order);
147
+
148
+		return $order;
149
+	}
150
+
151
+	/**
152
+	 * @return ResultSetStorage
153
+	 */
154
+	public function getResultSetStorage()
155
+	{
156
+		return GeneralUtility::makeInstance(ResultSetStorage::class);
157
+	}
158
+
159
+	/**
160
+	 * Signal that is called for post-processing a "order" object.
161
+	 *
162
+	 * @param string $dataType
163
+	 * @param Order $order
164
+	 * @signal
165
+	 */
166
+	protected function emitPostProcessOrderObjectSignal($dataType, Order $order)
167
+	{
168
+		$this->getSignalSlotDispatcher()->dispatch('Fab\Vidi\ViewHelper\Content\AbstractContentViewHelper', 'postProcessOrderObject', array($order, $dataType));
169
+	}
170
+
171
+	/**
172
+	 * Signal that is called for post-processing a "matcher" object.
173
+	 *
174
+	 * @param string $dataType
175
+	 * @param Matcher $matcher
176
+	 * @signal
177
+	 */
178
+	protected function emitPostProcessMatcherObjectSignal($dataType, Matcher $matcher)
179
+	{
180
+		$this->getSignalSlotDispatcher()->dispatch('Fab\Vidi\ViewHelper\Content\AbstractContentViewHelper', 'postProcessMatcherObject', array($matcher, $dataType));
181
+	}
182
+
183
+	/**
184
+	 * Signal that is called for post-processing a "limit".
185
+	 *
186
+	 * @param string $dataType
187
+	 * @param int $limit
188
+	 * @signal
189
+	 */
190
+	protected function emitPostProcessLimitSignal($dataType, $limit)
191
+	{
192
+		$this->getSignalSlotDispatcher()->dispatch('Fab\Vidi\ViewHelper\Content\AbstractContentViewHelper', 'postProcessLimit', array($limit, $dataType));
193
+	}
194
+
195
+	/**
196
+	 * Signal that is called for post-processing a "offset".
197
+	 *
198
+	 * @param string $dataType
199
+	 * @param int $offset
200
+	 * @signal
201
+	 */
202
+	protected function emitPostProcessOffsetSignal($dataType, $offset)
203
+	{
204
+		$this->getSignalSlotDispatcher()->dispatch('Fab\Vidi\ViewHelper\Content\AbstractContentViewHelper', 'postProcessLimit', array($offset, $dataType));
205
+	}
206
+
207
+	/**
208
+	 * Get the SignalSlot dispatcher
209
+	 *
210
+	 * @return Dispatcher
211
+	 */
212
+	protected function getSignalSlotDispatcher()
213
+	{
214
+		return $this->getObjectManager()->get(Dispatcher::class);
215
+	}
216
+
217
+	/**
218
+	 * @return ObjectManager
219
+	 */
220
+	protected function getObjectManager()
221
+	{
222
+		return GeneralUtility::makeInstance(ObjectManager::class);
223
+	}
224
+
225
+	/**
226
+	 * @param $ignoreEnableFields
227
+	 * @return \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface
228
+	 */
229
+	protected function getDefaultQuerySettings($ignoreEnableFields)
230
+	{
231
+		/** @var QuerySettings $defaultQuerySettings */
232
+		$defaultQuerySettings = GeneralUtility::makeInstance(QuerySettings::class);
233
+		$defaultQuerySettings->setIgnoreEnableFields($ignoreEnableFields);
234
+		return $defaultQuerySettings;
235
+	}
236
+
237
+	/**
238
+	 * @return FieldPathResolver
239
+	 */
240
+	protected function getFieldPathResolver()
241
+	{
242
+		return GeneralUtility::makeInstance(FieldPathResolver::class);
243
+	}
244 244
 
245 245
 }
Please login to merge, or discard this patch.
Classes/Resolver/FieldPathResolver.php 1 patch
Indentation   +107 added lines, -107 removed lines patch added patch discarded remove patch
@@ -25,111 +25,111 @@
 block discarded – undo
25 25
 class FieldPathResolver implements SingletonInterface
26 26
 {
27 27
 
28
-    /**
29
-     * Remove the prefixing path from the file name.
30
-     *
31
-     * @param string $fieldNameAndPath
32
-     * @param string $dataType
33
-     * @return string
34
-     */
35
-    public function stripFieldPath($fieldNameAndPath, $dataType = '')
36
-    {
37
-
38
-        $dataType = $this->getContextualDataType($dataType);
39
-
40
-        if ($this->containsPath($fieldNameAndPath, $dataType)) {
41
-
42
-            // Corresponds to the field name of the foreign table.
43
-            $fieldParts = GeneralUtility::trimExplode('.', $fieldNameAndPath);
44
-            $fieldName = $fieldParts[1];
45
-        } else {
46
-            $fieldName = $fieldNameAndPath;
47
-        }
48
-        return $fieldName;
49
-    }
50
-
51
-    /**
52
-     * Remove the suffixing field name
53
-     *
54
-     * @param string $fieldNameAndPath
55
-     * @param string $dataType
56
-     * @return string
57
-     */
58
-    public function stripFieldName($fieldNameAndPath, $dataType = '')
59
-    {
60
-
61
-        $dataType = $this->getContextualDataType($dataType);
62
-
63
-        if ($this->containsPath($fieldNameAndPath, $dataType)) {
64
-
65
-            // Corresponds to the field name of the foreign table.
66
-            $fieldParts = GeneralUtility::trimExplode('.', $fieldNameAndPath);
67
-            $fieldName = $fieldParts[0];
68
-        } else {
69
-            $fieldName = $fieldNameAndPath;
70
-        }
71
-        return $fieldName;
72
-    }
73
-
74
-    /**
75
-     * Returns the class names to be applied to a cell ("td").
76
-     *
77
-     * @param string $fieldNameAndPath
78
-     * @param string $dataType
79
-     * @return string
80
-     */
81
-    public function getDataType($fieldNameAndPath, $dataType = '')
82
-    {
83
-
84
-        $dataType = $this->getContextualDataType($dataType);
85
-
86
-        if ($this->containsPath($fieldNameAndPath, $dataType)) {
87
-
88
-            // Compute the foreign data type.
89
-            $fieldParts = GeneralUtility::trimExplode('.', $fieldNameAndPath);
90
-            $fieldNameAndPath = $fieldParts[0];
91
-            $dataType = Tca::table($dataType)->field($fieldNameAndPath)->getForeignTable();
92
-        }
93
-        return $dataType;
94
-    }
95
-
96
-    /**
97
-     * Return the data type according to the context.
98
-     *
99
-     * @param $dataType
100
-     * @return string
101
-     */
102
-    public function getContextualDataType($dataType)
103
-    {
104
-
105
-        if (!$dataType) {
106
-            $dataType = $this->getModuleLoader()->getDataType();
107
-        }
108
-        return $dataType;
109
-    }
110
-
111
-    /**
112
-     * Tell whether the field name contains a path, e.g. metadata.title
113
-     * But resolves the case when the field is composite e.g "items.sys_file_metadata" and looks as field path but is not!
114
-     * A composite field = a field for a MM relation  of type "group" where the table name is appended.
115
-     *
116
-     * @param string $fieldNameAndPath
117
-     * @param string $dataType
118
-     * @return boolean
119
-     */
120
-    public function containsPath($fieldNameAndPath, $dataType)
121
-    {
122
-        $doesContainPath = strpos($fieldNameAndPath, '.') > 0 && !Tca::table($dataType)->hasField($fieldNameAndPath); // -> will make sure it is not a composite field name.
123
-        return $doesContainPath;
124
-    }
125
-
126
-    /**
127
-     * Get the Vidi Module Loader.
128
-     *
129
-     * @return ModuleLoader
130
-     */
131
-    protected function getModuleLoader()
132
-    {
133
-        return GeneralUtility::makeInstance(ModuleLoader::class);
134
-    }
28
+	/**
29
+	 * Remove the prefixing path from the file name.
30
+	 *
31
+	 * @param string $fieldNameAndPath
32
+	 * @param string $dataType
33
+	 * @return string
34
+	 */
35
+	public function stripFieldPath($fieldNameAndPath, $dataType = '')
36
+	{
37
+
38
+		$dataType = $this->getContextualDataType($dataType);
39
+
40
+		if ($this->containsPath($fieldNameAndPath, $dataType)) {
41
+
42
+			// Corresponds to the field name of the foreign table.
43
+			$fieldParts = GeneralUtility::trimExplode('.', $fieldNameAndPath);
44
+			$fieldName = $fieldParts[1];
45
+		} else {
46
+			$fieldName = $fieldNameAndPath;
47
+		}
48
+		return $fieldName;
49
+	}
50
+
51
+	/**
52
+	 * Remove the suffixing field name
53
+	 *
54
+	 * @param string $fieldNameAndPath
55
+	 * @param string $dataType
56
+	 * @return string
57
+	 */
58
+	public function stripFieldName($fieldNameAndPath, $dataType = '')
59
+	{
60
+
61
+		$dataType = $this->getContextualDataType($dataType);
62
+
63
+		if ($this->containsPath($fieldNameAndPath, $dataType)) {
64
+
65
+			// Corresponds to the field name of the foreign table.
66
+			$fieldParts = GeneralUtility::trimExplode('.', $fieldNameAndPath);
67
+			$fieldName = $fieldParts[0];
68
+		} else {
69
+			$fieldName = $fieldNameAndPath;
70
+		}
71
+		return $fieldName;
72
+	}
73
+
74
+	/**
75
+	 * Returns the class names to be applied to a cell ("td").
76
+	 *
77
+	 * @param string $fieldNameAndPath
78
+	 * @param string $dataType
79
+	 * @return string
80
+	 */
81
+	public function getDataType($fieldNameAndPath, $dataType = '')
82
+	{
83
+
84
+		$dataType = $this->getContextualDataType($dataType);
85
+
86
+		if ($this->containsPath($fieldNameAndPath, $dataType)) {
87
+
88
+			// Compute the foreign data type.
89
+			$fieldParts = GeneralUtility::trimExplode('.', $fieldNameAndPath);
90
+			$fieldNameAndPath = $fieldParts[0];
91
+			$dataType = Tca::table($dataType)->field($fieldNameAndPath)->getForeignTable();
92
+		}
93
+		return $dataType;
94
+	}
95
+
96
+	/**
97
+	 * Return the data type according to the context.
98
+	 *
99
+	 * @param $dataType
100
+	 * @return string
101
+	 */
102
+	public function getContextualDataType($dataType)
103
+	{
104
+
105
+		if (!$dataType) {
106
+			$dataType = $this->getModuleLoader()->getDataType();
107
+		}
108
+		return $dataType;
109
+	}
110
+
111
+	/**
112
+	 * Tell whether the field name contains a path, e.g. metadata.title
113
+	 * But resolves the case when the field is composite e.g "items.sys_file_metadata" and looks as field path but is not!
114
+	 * A composite field = a field for a MM relation  of type "group" where the table name is appended.
115
+	 *
116
+	 * @param string $fieldNameAndPath
117
+	 * @param string $dataType
118
+	 * @return boolean
119
+	 */
120
+	public function containsPath($fieldNameAndPath, $dataType)
121
+	{
122
+		$doesContainPath = strpos($fieldNameAndPath, '.') > 0 && !Tca::table($dataType)->hasField($fieldNameAndPath); // -> will make sure it is not a composite field name.
123
+		return $doesContainPath;
124
+	}
125
+
126
+	/**
127
+	 * Get the Vidi Module Loader.
128
+	 *
129
+	 * @return ModuleLoader
130
+	 */
131
+	protected function getModuleLoader()
132
+	{
133
+		return GeneralUtility::makeInstance(ModuleLoader::class);
134
+	}
135 135
 }
Please login to merge, or discard this patch.
Classes/Tca/GridService.php 1 patch
Indentation   +645 added lines, -645 removed lines patch added patch discarded remove patch
@@ -31,650 +31,650 @@
 block discarded – undo
31 31
 class GridService extends AbstractTca
32 32
 {
33 33
 
34
-    /**
35
-     * @var array
36
-     */
37
-    protected $tca;
38
-
39
-    /**
40
-     * @var string
41
-     */
42
-    protected $tableName;
43
-
44
-    /**
45
-     * All fields available in the Grid.
46
-     *
47
-     * @var array
48
-     */
49
-    protected $fields;
50
-
51
-    /**
52
-     * All fields regardless whether they have been excluded or not.
53
-     *
54
-     * @var array
55
-     */
56
-    protected $allFields;
57
-
58
-    /**
59
-     * @var array
60
-     */
61
-    protected $instances;
62
-
63
-    /**
64
-     * @var array
65
-     */
66
-    protected $facets;
67
-
68
-    /**
69
-     * __construct
70
-     *
71
-     * @throws InvalidKeyInArrayException
72
-     * @param string $tableName
73
-     * @return \Fab\Vidi\Tca\GridService
74
-     */
75
-    public function __construct($tableName)
76
-    {
77
-
78
-        $this->tableName = $tableName;
79
-
80
-        if (empty($GLOBALS['TCA'][$this->tableName])) {
81
-            throw new InvalidKeyInArrayException('No TCA existence for table name: ' . $this->tableName, 1356945108);
82
-        }
83
-
84
-        $this->tca = $GLOBALS['TCA'][$this->tableName]['grid'];
85
-    }
86
-
87
-    /**
88
-     * Returns an array containing column names.
89
-     *
90
-     * @return array
91
-     */
92
-    public function getFieldNames()
93
-    {
94
-        $fields = $this->getFields();
95
-        return array_keys($fields);
96
-    }
97
-
98
-    /**
99
-     * Returns an array containing column names.
100
-     *
101
-     * @return array
102
-     */
103
-    public function getAllFieldNames()
104
-    {
105
-        $allFields = $this->getAllFields();
106
-        return array_keys($allFields);
107
-    }
108
-
109
-    /**
110
-     * Get the label key.
111
-     *
112
-     * @param string $fieldNameAndPath
113
-     * @return string
114
-     */
115
-    public function getLabelKey($fieldNameAndPath)
116
-    {
117
-
118
-        $field = $this->getField($fieldNameAndPath);
119
-
120
-        // First option is to get the label from the Grid TCA.
121
-        $rawLabel = '';
122
-        if (isset($field['label'])) {
123
-            $rawLabel = $field['label'];
124
-        }
125
-
126
-        // Second option is to fetch the label from the Column Renderer object.
127
-        if (!$rawLabel && $this->hasRenderers($fieldNameAndPath)) {
128
-            $renderers = $this->getRenderers($fieldNameAndPath);
129
-            /** @var $renderer ColumnRendererInterface */
130
-            foreach ($renderers as $renderer) {
131
-                if (isset($renderer['label'])) {
132
-                    $rawLabel = $renderer['label'];
133
-                    break;
134
-                }
135
-            }
136
-        }
137
-        return $rawLabel;
138
-    }
139
-
140
-    /**
141
-     * Get the translation of a label given a column name.
142
-     *
143
-     * @param string $fieldNameAndPath
144
-     * @return string
145
-     */
146
-    public function getLabel($fieldNameAndPath)
147
-    {
148
-        $label = '';
149
-        if ($this->hasLabel($fieldNameAndPath)) {
150
-            $labelKey = $this->getLabelKey($fieldNameAndPath);
151
-            $label = LocalizationUtility::translate($labelKey, '');
152
-            if (is_null($label)) {
153
-                $label = $labelKey;
154
-            }
155
-        } else {
156
-
157
-            // Important to notice the label can contains a path, e.g. metadata.categories and must be resolved.
158
-            $dataType = $this->getFieldPathResolver()->getDataType($fieldNameAndPath, $this->tableName);
159
-            $fieldName = $this->getFieldPathResolver()->stripFieldPath($fieldNameAndPath, $this->tableName);
160
-            $table = Tca::table($dataType);
161
-
162
-            if ($table->hasField($fieldName) && $table->field($fieldName)->hasLabel()) {
163
-                $label = $table->field($fieldName)->getLabel();
164
-            }
165
-        }
166
-
167
-        return $label;
168
-    }
169
-
170
-    /**
171
-     * Returns the field name given its position.
172
-     *
173
-     * @param string $position the position of the field in the grid
174
-     * @throws InvalidKeyInArrayException
175
-     * @return int
176
-     */
177
-    public function getFieldNameByPosition($position)
178
-    {
179
-        $fields = array_keys($this->getFields());
180
-        if (empty($fields[$position])) {
181
-            throw new InvalidKeyInArrayException('No field exist for position: ' . $position, 1356945119);
182
-        }
183
-
184
-        return $fields[$position];
185
-    }
186
-
187
-    /**
188
-     * Returns a field name.
189
-     *
190
-     * @param string $fieldName
191
-     * @return array
192
-     * @throws InvalidKeyInArrayException
193
-     */
194
-    public function getField($fieldName)
195
-    {
196
-        $fields = $this->getFields();
197
-        return $fields[$fieldName];
198
-    }
199
-
200
-    /**
201
-     * Returns an array containing column names for the Grid.
202
-     *
203
-     * @return array
204
-     */
205
-    public function getFields()
206
-    {
207
-        // Cache this operation since it can take some time.
208
-        if (is_null($this->fields)) {
209
-
210
-            // Fetch all available fields first.
211
-            $fields = $this->getAllFields();
212
-
213
-            if ($this->isBackendMode()) {
214
-                // Then remove the not allowed.
215
-                $fields = $this->filterForBackendUser($fields);
216
-                $fields = $this->filterForConfiguration($fields);
217
-            }
218
-
219
-            $this->fields = $fields;
220
-        }
221
-
222
-        return $this->fields;
223
-    }
224
-
225
-    /**
226
-     * Remove fields according to BE User permission.
227
-     *
228
-     * @param $fields
229
-     * @return array
230
-     * @throws \Exception
231
-     */
232
-    protected function filterForBackendUser($fields)
233
-    {
234
-        if (!$this->getBackendUser()->isAdmin()) {
235
-            foreach ($fields as $fieldName => $field) {
236
-                if (Tca::table($this->tableName)->hasField($fieldName) && !Tca::table($this->tableName)->field($fieldName)->hasAccess()) {
237
-                    unset($fields[$fieldName]);
238
-                }
239
-            }
240
-        }
241
-        return $fields;
242
-    }
243
-
244
-    /**
245
-     * Remove fields according to Grid configuration.
246
-     *
247
-     * @param $fields
248
-     * @return array
249
-     */
250
-    protected function filterForConfiguration($fields)
251
-    {
252
-
253
-        // Unset excluded fields.
254
-        foreach ($this->getExcludedFields() as $excludedField) {
255
-            if (isset($fields[$excludedField])) {
256
-                unset($fields[$excludedField]);
257
-            }
258
-        }
259
-
260
-        return $fields;
261
-    }
262
-
263
-    /**
264
-     * Returns an array containing column names for the Grid.
265
-     *
266
-     * @return array
267
-     */
268
-    public function getAllFields()
269
-    {
270
-
271
-        // Cache this operation since it can take some time.
272
-        if (is_null($this->allFields)) {
273
-
274
-            $fields = is_array($this->tca['columns']) ? $this->tca['columns'] : array();
275
-            $gridFieldNames = array_keys($fields);
276
-
277
-            // Fetch all fields of the TCA and merge it back to the fields configured for Grid.
278
-            $tableFieldNames = Tca::table($this->tableName)->getFields();
279
-
280
-            // Just remove system fields from the Grid.
281
-            foreach ($tableFieldNames as $key => $fieldName) {
282
-                if (in_array($fieldName, Tca::getSystemFields())) {
283
-                    unset($tableFieldNames[$key]);
284
-                }
285
-            }
286
-
287
-            $additionalFields = array_diff($tableFieldNames, $gridFieldNames);
288
-
289
-            if (!empty($additionalFields)) {
290
-
291
-                // Pop out last element of the key
292
-                // Idea is to place new un-configured columns in between. By default, they will be hidden.
293
-                end($fields);
294
-                $lastColumnKey = key($fields);
295
-                $lastColumn = array_pop($fields);
296
-
297
-                // Feed up the grid fields with un configured elements
298
-                foreach ($additionalFields as $additionalField) {
299
-                    $fields[$additionalField] = array(
300
-                        'visible' => FALSE
301
-                    );
302
-
303
-                    // Try to guess the format of the field.
304
-                    $fieldType = Tca::table($this->tableName)->field($additionalField)->getType();
305
-                    if ($fieldType === FieldType::DATE) {
306
-                        $fields[$additionalField]['format'] = 'Fab\Vidi\Formatter\Date';
307
-                    } elseif ($fieldType === FieldType::DATETIME) {
308
-                        $fields[$additionalField]['format'] = 'Fab\Vidi\Formatter\Datetime';
309
-                    }
310
-                }
311
-                $fields[$lastColumnKey] = $lastColumn;
312
-            }
313
-
314
-            $this->allFields = $fields;
315
-        }
316
-
317
-        return $this->allFields;
318
-    }
319
-
320
-    /**
321
-     * Tell whether the field exists in the grid or not.
322
-     *
323
-     * @param string $fieldName
324
-     * @return bool
325
-     */
326
-    public function hasField($fieldName)
327
-    {
328
-        $fields = $this->getFields();
329
-        return isset($fields[$fieldName]);
330
-    }
331
-
332
-    /**
333
-     * Tell whether the facet exists in the grid or not.
334
-     *
335
-     * @param string $facetName
336
-     * @return bool
337
-     */
338
-    public function hasFacet($facetName)
339
-    {
340
-        $facets = $this->getFacets();
341
-        return isset($facets[$facetName]);
342
-    }
343
-
344
-    /**
345
-     * Returns an array containing facets fields.
346
-     *
347
-     * @return FacetInterface[]
348
-     */
349
-    public function getFacets()
350
-    {
351
-        if (is_null($this->facets)) {
352
-            $this->facets = array();
353
-
354
-            if (is_array($this->tca['facets'])) {
355
-                foreach ($this->tca['facets'] as $facetNameOrObject) {
356
-                    if ($facetNameOrObject instanceof FacetInterface) {
357
-                        $this->facets[$facetNameOrObject->getName()] = $facetNameOrObject;
358
-                    } else {
359
-                        $this->facets[$facetNameOrObject] = $this->instantiateStandardFacet($facetNameOrObject);
360
-                    }
361
-                }
362
-            }
363
-        }
364
-        return $this->facets;
365
-    }
366
-
367
-    /**
368
-     * Returns the "sortable" value of the column.
369
-     *
370
-     * @param string $fieldName
371
-     * @return int|string
372
-     */
373
-    public function isSortable($fieldName)
374
-    {
375
-        $defaultValue = true;
376
-        $hasSortableField = Tca::table($this->tableName)->hasSortableField();
377
-        if ($hasSortableField) {
378
-            $isSortable = false;
379
-        } else {
380
-            $isSortable = $this->get($fieldName, 'sortable', $defaultValue);
381
-        }
382
-        return $isSortable;
383
-    }
384
-
385
-    /**
386
-     * Returns the "canBeHidden" value of the column.
387
-     *
388
-     * @param string $fieldName
389
-     * @return bool
390
-     */
391
-    public function canBeHidden($fieldName)
392
-    {
393
-        $defaultValue = TRUE;
394
-        return $this->get($fieldName, 'canBeHidden', $defaultValue);
395
-    }
396
-
397
-    /**
398
-     * Returns the "width" value of the column.
399
-     *
400
-     * @param string $fieldName
401
-     * @return int|string
402
-     */
403
-    public function getWidth($fieldName)
404
-    {
405
-        $defaultValue = 'auto';
406
-        return $this->get($fieldName, 'width', $defaultValue);
407
-    }
408
-
409
-    /**
410
-     * Returns the "visible" value of the column.
411
-     *
412
-     * @param string $fieldName
413
-     * @return bool
414
-     */
415
-    public function isVisible($fieldName)
416
-    {
417
-        $defaultValue = TRUE;
418
-        return $this->get($fieldName, 'visible', $defaultValue);
419
-    }
420
-
421
-    /**
422
-     * Returns the "editable" value of the column.
423
-     *
424
-     * @param string $columnName
425
-     * @return bool
426
-     */
427
-    public function isEditable($columnName)
428
-    {
429
-        $defaultValue = FALSE;
430
-        return $this->get($columnName, 'editable', $defaultValue);
431
-    }
432
-
433
-    /**
434
-     * Returns the "localized" value of the column.
435
-     *
436
-     * @param string $columnName
437
-     * @return bool
438
-     */
439
-    public function isLocalized($columnName)
440
-    {
441
-        $defaultValue = TRUE;
442
-        return $this->get($columnName, 'localized', $defaultValue);
443
-    }
444
-
445
-    /**
446
-     *
447
-     * Returns the "html" value of the column.
448
-     *
449
-     * @param string $fieldName
450
-     * @return string
451
-     */
452
-    public function getHeader($fieldName)
453
-    {
454
-        $defaultValue = '';
455
-        return $this->get($fieldName, 'html', $defaultValue);
456
-    }
457
-
458
-    /**
459
-     * Fetch a possible from a Grid Renderer. If no value is found, returns NULL
460
-     *
461
-     * @param string $fieldName
462
-     * @param string $key
463
-     * @param mixed $defaultValue
464
-     * @return NULL|mixed
465
-     */
466
-    public function get($fieldName, $key, $defaultValue = NULL)
467
-    {
468
-        $value = $defaultValue;
469
-
470
-        $field = $this->getField($fieldName);
471
-        if (isset($field[$key])) {
472
-            $value = $field[$key];
473
-        } elseif ($this->hasRenderers($fieldName)) {
474
-            $renderers = $this->getRenderers($fieldName);
475
-            foreach ($renderers as $rendererConfiguration) {
476
-                if (isset($rendererConfiguration[$key])) {
477
-                    $value = $rendererConfiguration[$key];
478
-                }
479
-            }
480
-        }
481
-        return $value;
482
-    }
483
-
484
-    /**
485
-     * Returns whether the column has a renderer.
486
-     *
487
-     * @param string $fieldName
488
-     * @return bool
489
-     */
490
-    public function hasRenderers($fieldName)
491
-    {
492
-        $field = $this->getField($fieldName);
493
-        return empty($field['renderer']) && empty($field['renderers']) ? FALSE : TRUE;
494
-    }
495
-
496
-    /**
497
-     * Returns a renderer.
498
-     *
499
-     * @param string $fieldName
500
-     * @return array
501
-     */
502
-    public function getRenderers($fieldName)
503
-    {
504
-        $field = $this->getField($fieldName);
505
-        $renderers = array();
506
-        if (!empty($field['renderer'])) {
507
-            $renderers = $this->convertRendererToArray($field['renderer']);
508
-        } elseif (!empty($field['renderers']) && is_array($field['renderers'])) {
509
-            foreach ($field['renderers'] as $renderer) {
510
-                $rendererNameAndConfiguration = $this->convertRendererToArray($renderer);
511
-                $renderers = array_merge($renderers, $rendererNameAndConfiguration);
512
-            }
513
-        }
514
-
515
-        return $renderers;
516
-    }
517
-
518
-    /**
519
-     * @param string|GenericColumn $renderer
520
-     * @return array
521
-     */
522
-    public function convertRendererToArray($renderer)
523
-    {
524
-        $result = array();
525
-        if (is_string($renderer)) {
526
-            $result[$renderer] = array();
527
-        } elseif ($renderer instanceof ColumnInterface || $renderer instanceof ColumnRendererInterface) {
528
-            /** @var GenericColumn $renderer */
529
-            $result[get_class($renderer)] = $renderer->getConfiguration();
530
-        }
531
-        return $result;
532
-    }
533
-
534
-    /**
535
-     * Returns the class names applied to a cell
536
-     *
537
-     * @param string $fieldName
538
-     * @return bool
539
-     */
540
-    public function getClass($fieldName)
541
-    {
542
-        $field = $this->getField($fieldName);
543
-        return isset($field['class']) ? $field['class'] : '';
544
-    }
545
-
546
-    /**
547
-     * Returns whether the column has a label.
548
-     *
549
-     * @param string $fieldNameAndPath
550
-     * @return bool
551
-     */
552
-    public function hasLabel($fieldNameAndPath)
553
-    {
554
-        $field = $this->getField($fieldNameAndPath);
555
-
556
-        $hasLabel = empty($field['label']) ? FALSE : TRUE;
557
-
558
-        if (!$hasLabel && $this->hasRenderers($fieldNameAndPath)) {
559
-            $renderers = $this->getRenderers($fieldNameAndPath);
560
-            /** @var $renderer ColumnRendererInterface */
561
-            foreach ($renderers as $renderer) {
562
-                if (isset($renderer['label'])) {
563
-                    $hasLabel = TRUE;
564
-                    break;
565
-                }
566
-            }
567
-        }
568
-        return $hasLabel;
569
-    }
570
-
571
-    /**
572
-     * @return array
573
-     */
574
-    public function getTca()
575
-    {
576
-        return $this->tca;
577
-    }
578
-
579
-    /**
580
-     * Return excluded fields from configuration + preferences.
581
-     *
582
-     * @return array
583
-     */
584
-    public function getExcludedFields()
585
-    {
586
-        $configurationFields = $this->getExcludedFieldsFromConfiguration();
587
-        $preferencesFields = $this->getExcludedFieldsFromPreferences();
588
-
589
-        return array_merge($configurationFields, $preferencesFields);
590
-    }
591
-
592
-    /**
593
-     * Fetch excluded fields from configuration.
594
-     *
595
-     * @return array
596
-     */
597
-    protected function getExcludedFieldsFromConfiguration()
598
-    {
599
-        $excludedFields = array();
600
-        if (!empty($this->tca['excluded_fields'])) {
601
-            $excludedFields = GeneralUtility::trimExplode(',', $this->tca['excluded_fields'], TRUE);
602
-        } elseif (!empty($this->tca['export']['excluded_fields'])) { // only for export for legacy reason.
603
-            $excludedFields = GeneralUtility::trimExplode(',', $this->tca['export']['excluded_fields'], TRUE);
604
-        }
605
-        return $excludedFields;
606
-
607
-    }
608
-
609
-    /**
610
-     * Fetch excluded fields from preferences.
611
-     *
612
-     * @return array
613
-     */
614
-    protected function getExcludedFieldsFromPreferences()
615
-    {
616
-        $excludedFields = $this->getModulePreferences()->get(ConfigurablePart::EXCLUDED_FIELDS, $this->tableName);
617
-        return is_array($excludedFields) ? $excludedFields : array();
618
-    }
619
-
620
-    /**
621
-     * @return array
622
-     */
623
-    public function areFilesIncludedInExport()
624
-    {
625
-        $isIncluded = TRUE;
626
-
627
-        if (isset($this->tca['export']['include_files'])) {
628
-            $isIncluded = $this->tca['export']['include_files'];
629
-        }
630
-        return $isIncluded;
631
-    }
632
-
633
-    /**
634
-     * Returns a "facet" service instance.
635
-     *
636
-     * @param string|FacetInterface $facetName
637
-     * @return StandardFacet
638
-     */
639
-    protected function instantiateStandardFacet($facetName)
640
-    {
641
-        $label = $this->getLabel($facetName);
642
-
643
-        /** @var StandardFacet $facetName */
644
-        $facet = GeneralUtility::makeInstance('Fab\Vidi\Facet\StandardFacet', $facetName, $label);
645
-
646
-        if (!$facet instanceof StandardFacet) {
647
-            throw new \RuntimeException('I could not instantiate a facet for facet name "' . (string)$facet . '""', 1445856345);
648
-        }
649
-        return $facet;
650
-    }
651
-
652
-    /**
653
-     * Returns a "facet" service instance.
654
-     *
655
-     * @param string|FacetInterface $facetName
656
-     * @return FacetInterface
657
-     */
658
-    public function facet($facetName = '')
659
-    {
660
-        $facets = $this->getFacets();
661
-        return $facets[$facetName];
662
-    }
663
-
664
-    /**
665
-     * @return \Fab\Vidi\Resolver\FieldPathResolver
666
-     */
667
-    protected function getFieldPathResolver()
668
-    {
669
-        return GeneralUtility::makeInstance('Fab\Vidi\Resolver\FieldPathResolver');
670
-    }
671
-
672
-    /**
673
-     * @return ModulePreferences
674
-     */
675
-    protected function getModulePreferences()
676
-    {
677
-        return GeneralUtility::makeInstance('Fab\Vidi\Module\ModulePreferences');
678
-    }
34
+	/**
35
+	 * @var array
36
+	 */
37
+	protected $tca;
38
+
39
+	/**
40
+	 * @var string
41
+	 */
42
+	protected $tableName;
43
+
44
+	/**
45
+	 * All fields available in the Grid.
46
+	 *
47
+	 * @var array
48
+	 */
49
+	protected $fields;
50
+
51
+	/**
52
+	 * All fields regardless whether they have been excluded or not.
53
+	 *
54
+	 * @var array
55
+	 */
56
+	protected $allFields;
57
+
58
+	/**
59
+	 * @var array
60
+	 */
61
+	protected $instances;
62
+
63
+	/**
64
+	 * @var array
65
+	 */
66
+	protected $facets;
67
+
68
+	/**
69
+	 * __construct
70
+	 *
71
+	 * @throws InvalidKeyInArrayException
72
+	 * @param string $tableName
73
+	 * @return \Fab\Vidi\Tca\GridService
74
+	 */
75
+	public function __construct($tableName)
76
+	{
77
+
78
+		$this->tableName = $tableName;
79
+
80
+		if (empty($GLOBALS['TCA'][$this->tableName])) {
81
+			throw new InvalidKeyInArrayException('No TCA existence for table name: ' . $this->tableName, 1356945108);
82
+		}
83
+
84
+		$this->tca = $GLOBALS['TCA'][$this->tableName]['grid'];
85
+	}
86
+
87
+	/**
88
+	 * Returns an array containing column names.
89
+	 *
90
+	 * @return array
91
+	 */
92
+	public function getFieldNames()
93
+	{
94
+		$fields = $this->getFields();
95
+		return array_keys($fields);
96
+	}
97
+
98
+	/**
99
+	 * Returns an array containing column names.
100
+	 *
101
+	 * @return array
102
+	 */
103
+	public function getAllFieldNames()
104
+	{
105
+		$allFields = $this->getAllFields();
106
+		return array_keys($allFields);
107
+	}
108
+
109
+	/**
110
+	 * Get the label key.
111
+	 *
112
+	 * @param string $fieldNameAndPath
113
+	 * @return string
114
+	 */
115
+	public function getLabelKey($fieldNameAndPath)
116
+	{
117
+
118
+		$field = $this->getField($fieldNameAndPath);
119
+
120
+		// First option is to get the label from the Grid TCA.
121
+		$rawLabel = '';
122
+		if (isset($field['label'])) {
123
+			$rawLabel = $field['label'];
124
+		}
125
+
126
+		// Second option is to fetch the label from the Column Renderer object.
127
+		if (!$rawLabel && $this->hasRenderers($fieldNameAndPath)) {
128
+			$renderers = $this->getRenderers($fieldNameAndPath);
129
+			/** @var $renderer ColumnRendererInterface */
130
+			foreach ($renderers as $renderer) {
131
+				if (isset($renderer['label'])) {
132
+					$rawLabel = $renderer['label'];
133
+					break;
134
+				}
135
+			}
136
+		}
137
+		return $rawLabel;
138
+	}
139
+
140
+	/**
141
+	 * Get the translation of a label given a column name.
142
+	 *
143
+	 * @param string $fieldNameAndPath
144
+	 * @return string
145
+	 */
146
+	public function getLabel($fieldNameAndPath)
147
+	{
148
+		$label = '';
149
+		if ($this->hasLabel($fieldNameAndPath)) {
150
+			$labelKey = $this->getLabelKey($fieldNameAndPath);
151
+			$label = LocalizationUtility::translate($labelKey, '');
152
+			if (is_null($label)) {
153
+				$label = $labelKey;
154
+			}
155
+		} else {
156
+
157
+			// Important to notice the label can contains a path, e.g. metadata.categories and must be resolved.
158
+			$dataType = $this->getFieldPathResolver()->getDataType($fieldNameAndPath, $this->tableName);
159
+			$fieldName = $this->getFieldPathResolver()->stripFieldPath($fieldNameAndPath, $this->tableName);
160
+			$table = Tca::table($dataType);
161
+
162
+			if ($table->hasField($fieldName) && $table->field($fieldName)->hasLabel()) {
163
+				$label = $table->field($fieldName)->getLabel();
164
+			}
165
+		}
166
+
167
+		return $label;
168
+	}
169
+
170
+	/**
171
+	 * Returns the field name given its position.
172
+	 *
173
+	 * @param string $position the position of the field in the grid
174
+	 * @throws InvalidKeyInArrayException
175
+	 * @return int
176
+	 */
177
+	public function getFieldNameByPosition($position)
178
+	{
179
+		$fields = array_keys($this->getFields());
180
+		if (empty($fields[$position])) {
181
+			throw new InvalidKeyInArrayException('No field exist for position: ' . $position, 1356945119);
182
+		}
183
+
184
+		return $fields[$position];
185
+	}
186
+
187
+	/**
188
+	 * Returns a field name.
189
+	 *
190
+	 * @param string $fieldName
191
+	 * @return array
192
+	 * @throws InvalidKeyInArrayException
193
+	 */
194
+	public function getField($fieldName)
195
+	{
196
+		$fields = $this->getFields();
197
+		return $fields[$fieldName];
198
+	}
199
+
200
+	/**
201
+	 * Returns an array containing column names for the Grid.
202
+	 *
203
+	 * @return array
204
+	 */
205
+	public function getFields()
206
+	{
207
+		// Cache this operation since it can take some time.
208
+		if (is_null($this->fields)) {
209
+
210
+			// Fetch all available fields first.
211
+			$fields = $this->getAllFields();
212
+
213
+			if ($this->isBackendMode()) {
214
+				// Then remove the not allowed.
215
+				$fields = $this->filterForBackendUser($fields);
216
+				$fields = $this->filterForConfiguration($fields);
217
+			}
218
+
219
+			$this->fields = $fields;
220
+		}
221
+
222
+		return $this->fields;
223
+	}
224
+
225
+	/**
226
+	 * Remove fields according to BE User permission.
227
+	 *
228
+	 * @param $fields
229
+	 * @return array
230
+	 * @throws \Exception
231
+	 */
232
+	protected function filterForBackendUser($fields)
233
+	{
234
+		if (!$this->getBackendUser()->isAdmin()) {
235
+			foreach ($fields as $fieldName => $field) {
236
+				if (Tca::table($this->tableName)->hasField($fieldName) && !Tca::table($this->tableName)->field($fieldName)->hasAccess()) {
237
+					unset($fields[$fieldName]);
238
+				}
239
+			}
240
+		}
241
+		return $fields;
242
+	}
243
+
244
+	/**
245
+	 * Remove fields according to Grid configuration.
246
+	 *
247
+	 * @param $fields
248
+	 * @return array
249
+	 */
250
+	protected function filterForConfiguration($fields)
251
+	{
252
+
253
+		// Unset excluded fields.
254
+		foreach ($this->getExcludedFields() as $excludedField) {
255
+			if (isset($fields[$excludedField])) {
256
+				unset($fields[$excludedField]);
257
+			}
258
+		}
259
+
260
+		return $fields;
261
+	}
262
+
263
+	/**
264
+	 * Returns an array containing column names for the Grid.
265
+	 *
266
+	 * @return array
267
+	 */
268
+	public function getAllFields()
269
+	{
270
+
271
+		// Cache this operation since it can take some time.
272
+		if (is_null($this->allFields)) {
273
+
274
+			$fields = is_array($this->tca['columns']) ? $this->tca['columns'] : array();
275
+			$gridFieldNames = array_keys($fields);
276
+
277
+			// Fetch all fields of the TCA and merge it back to the fields configured for Grid.
278
+			$tableFieldNames = Tca::table($this->tableName)->getFields();
279
+
280
+			// Just remove system fields from the Grid.
281
+			foreach ($tableFieldNames as $key => $fieldName) {
282
+				if (in_array($fieldName, Tca::getSystemFields())) {
283
+					unset($tableFieldNames[$key]);
284
+				}
285
+			}
286
+
287
+			$additionalFields = array_diff($tableFieldNames, $gridFieldNames);
288
+
289
+			if (!empty($additionalFields)) {
290
+
291
+				// Pop out last element of the key
292
+				// Idea is to place new un-configured columns in between. By default, they will be hidden.
293
+				end($fields);
294
+				$lastColumnKey = key($fields);
295
+				$lastColumn = array_pop($fields);
296
+
297
+				// Feed up the grid fields with un configured elements
298
+				foreach ($additionalFields as $additionalField) {
299
+					$fields[$additionalField] = array(
300
+						'visible' => FALSE
301
+					);
302
+
303
+					// Try to guess the format of the field.
304
+					$fieldType = Tca::table($this->tableName)->field($additionalField)->getType();
305
+					if ($fieldType === FieldType::DATE) {
306
+						$fields[$additionalField]['format'] = 'Fab\Vidi\Formatter\Date';
307
+					} elseif ($fieldType === FieldType::DATETIME) {
308
+						$fields[$additionalField]['format'] = 'Fab\Vidi\Formatter\Datetime';
309
+					}
310
+				}
311
+				$fields[$lastColumnKey] = $lastColumn;
312
+			}
313
+
314
+			$this->allFields = $fields;
315
+		}
316
+
317
+		return $this->allFields;
318
+	}
319
+
320
+	/**
321
+	 * Tell whether the field exists in the grid or not.
322
+	 *
323
+	 * @param string $fieldName
324
+	 * @return bool
325
+	 */
326
+	public function hasField($fieldName)
327
+	{
328
+		$fields = $this->getFields();
329
+		return isset($fields[$fieldName]);
330
+	}
331
+
332
+	/**
333
+	 * Tell whether the facet exists in the grid or not.
334
+	 *
335
+	 * @param string $facetName
336
+	 * @return bool
337
+	 */
338
+	public function hasFacet($facetName)
339
+	{
340
+		$facets = $this->getFacets();
341
+		return isset($facets[$facetName]);
342
+	}
343
+
344
+	/**
345
+	 * Returns an array containing facets fields.
346
+	 *
347
+	 * @return FacetInterface[]
348
+	 */
349
+	public function getFacets()
350
+	{
351
+		if (is_null($this->facets)) {
352
+			$this->facets = array();
353
+
354
+			if (is_array($this->tca['facets'])) {
355
+				foreach ($this->tca['facets'] as $facetNameOrObject) {
356
+					if ($facetNameOrObject instanceof FacetInterface) {
357
+						$this->facets[$facetNameOrObject->getName()] = $facetNameOrObject;
358
+					} else {
359
+						$this->facets[$facetNameOrObject] = $this->instantiateStandardFacet($facetNameOrObject);
360
+					}
361
+				}
362
+			}
363
+		}
364
+		return $this->facets;
365
+	}
366
+
367
+	/**
368
+	 * Returns the "sortable" value of the column.
369
+	 *
370
+	 * @param string $fieldName
371
+	 * @return int|string
372
+	 */
373
+	public function isSortable($fieldName)
374
+	{
375
+		$defaultValue = true;
376
+		$hasSortableField = Tca::table($this->tableName)->hasSortableField();
377
+		if ($hasSortableField) {
378
+			$isSortable = false;
379
+		} else {
380
+			$isSortable = $this->get($fieldName, 'sortable', $defaultValue);
381
+		}
382
+		return $isSortable;
383
+	}
384
+
385
+	/**
386
+	 * Returns the "canBeHidden" value of the column.
387
+	 *
388
+	 * @param string $fieldName
389
+	 * @return bool
390
+	 */
391
+	public function canBeHidden($fieldName)
392
+	{
393
+		$defaultValue = TRUE;
394
+		return $this->get($fieldName, 'canBeHidden', $defaultValue);
395
+	}
396
+
397
+	/**
398
+	 * Returns the "width" value of the column.
399
+	 *
400
+	 * @param string $fieldName
401
+	 * @return int|string
402
+	 */
403
+	public function getWidth($fieldName)
404
+	{
405
+		$defaultValue = 'auto';
406
+		return $this->get($fieldName, 'width', $defaultValue);
407
+	}
408
+
409
+	/**
410
+	 * Returns the "visible" value of the column.
411
+	 *
412
+	 * @param string $fieldName
413
+	 * @return bool
414
+	 */
415
+	public function isVisible($fieldName)
416
+	{
417
+		$defaultValue = TRUE;
418
+		return $this->get($fieldName, 'visible', $defaultValue);
419
+	}
420
+
421
+	/**
422
+	 * Returns the "editable" value of the column.
423
+	 *
424
+	 * @param string $columnName
425
+	 * @return bool
426
+	 */
427
+	public function isEditable($columnName)
428
+	{
429
+		$defaultValue = FALSE;
430
+		return $this->get($columnName, 'editable', $defaultValue);
431
+	}
432
+
433
+	/**
434
+	 * Returns the "localized" value of the column.
435
+	 *
436
+	 * @param string $columnName
437
+	 * @return bool
438
+	 */
439
+	public function isLocalized($columnName)
440
+	{
441
+		$defaultValue = TRUE;
442
+		return $this->get($columnName, 'localized', $defaultValue);
443
+	}
444
+
445
+	/**
446
+	 *
447
+	 * Returns the "html" value of the column.
448
+	 *
449
+	 * @param string $fieldName
450
+	 * @return string
451
+	 */
452
+	public function getHeader($fieldName)
453
+	{
454
+		$defaultValue = '';
455
+		return $this->get($fieldName, 'html', $defaultValue);
456
+	}
457
+
458
+	/**
459
+	 * Fetch a possible from a Grid Renderer. If no value is found, returns NULL
460
+	 *
461
+	 * @param string $fieldName
462
+	 * @param string $key
463
+	 * @param mixed $defaultValue
464
+	 * @return NULL|mixed
465
+	 */
466
+	public function get($fieldName, $key, $defaultValue = NULL)
467
+	{
468
+		$value = $defaultValue;
469
+
470
+		$field = $this->getField($fieldName);
471
+		if (isset($field[$key])) {
472
+			$value = $field[$key];
473
+		} elseif ($this->hasRenderers($fieldName)) {
474
+			$renderers = $this->getRenderers($fieldName);
475
+			foreach ($renderers as $rendererConfiguration) {
476
+				if (isset($rendererConfiguration[$key])) {
477
+					$value = $rendererConfiguration[$key];
478
+				}
479
+			}
480
+		}
481
+		return $value;
482
+	}
483
+
484
+	/**
485
+	 * Returns whether the column has a renderer.
486
+	 *
487
+	 * @param string $fieldName
488
+	 * @return bool
489
+	 */
490
+	public function hasRenderers($fieldName)
491
+	{
492
+		$field = $this->getField($fieldName);
493
+		return empty($field['renderer']) && empty($field['renderers']) ? FALSE : TRUE;
494
+	}
495
+
496
+	/**
497
+	 * Returns a renderer.
498
+	 *
499
+	 * @param string $fieldName
500
+	 * @return array
501
+	 */
502
+	public function getRenderers($fieldName)
503
+	{
504
+		$field = $this->getField($fieldName);
505
+		$renderers = array();
506
+		if (!empty($field['renderer'])) {
507
+			$renderers = $this->convertRendererToArray($field['renderer']);
508
+		} elseif (!empty($field['renderers']) && is_array($field['renderers'])) {
509
+			foreach ($field['renderers'] as $renderer) {
510
+				$rendererNameAndConfiguration = $this->convertRendererToArray($renderer);
511
+				$renderers = array_merge($renderers, $rendererNameAndConfiguration);
512
+			}
513
+		}
514
+
515
+		return $renderers;
516
+	}
517
+
518
+	/**
519
+	 * @param string|GenericColumn $renderer
520
+	 * @return array
521
+	 */
522
+	public function convertRendererToArray($renderer)
523
+	{
524
+		$result = array();
525
+		if (is_string($renderer)) {
526
+			$result[$renderer] = array();
527
+		} elseif ($renderer instanceof ColumnInterface || $renderer instanceof ColumnRendererInterface) {
528
+			/** @var GenericColumn $renderer */
529
+			$result[get_class($renderer)] = $renderer->getConfiguration();
530
+		}
531
+		return $result;
532
+	}
533
+
534
+	/**
535
+	 * Returns the class names applied to a cell
536
+	 *
537
+	 * @param string $fieldName
538
+	 * @return bool
539
+	 */
540
+	public function getClass($fieldName)
541
+	{
542
+		$field = $this->getField($fieldName);
543
+		return isset($field['class']) ? $field['class'] : '';
544
+	}
545
+
546
+	/**
547
+	 * Returns whether the column has a label.
548
+	 *
549
+	 * @param string $fieldNameAndPath
550
+	 * @return bool
551
+	 */
552
+	public function hasLabel($fieldNameAndPath)
553
+	{
554
+		$field = $this->getField($fieldNameAndPath);
555
+
556
+		$hasLabel = empty($field['label']) ? FALSE : TRUE;
557
+
558
+		if (!$hasLabel && $this->hasRenderers($fieldNameAndPath)) {
559
+			$renderers = $this->getRenderers($fieldNameAndPath);
560
+			/** @var $renderer ColumnRendererInterface */
561
+			foreach ($renderers as $renderer) {
562
+				if (isset($renderer['label'])) {
563
+					$hasLabel = TRUE;
564
+					break;
565
+				}
566
+			}
567
+		}
568
+		return $hasLabel;
569
+	}
570
+
571
+	/**
572
+	 * @return array
573
+	 */
574
+	public function getTca()
575
+	{
576
+		return $this->tca;
577
+	}
578
+
579
+	/**
580
+	 * Return excluded fields from configuration + preferences.
581
+	 *
582
+	 * @return array
583
+	 */
584
+	public function getExcludedFields()
585
+	{
586
+		$configurationFields = $this->getExcludedFieldsFromConfiguration();
587
+		$preferencesFields = $this->getExcludedFieldsFromPreferences();
588
+
589
+		return array_merge($configurationFields, $preferencesFields);
590
+	}
591
+
592
+	/**
593
+	 * Fetch excluded fields from configuration.
594
+	 *
595
+	 * @return array
596
+	 */
597
+	protected function getExcludedFieldsFromConfiguration()
598
+	{
599
+		$excludedFields = array();
600
+		if (!empty($this->tca['excluded_fields'])) {
601
+			$excludedFields = GeneralUtility::trimExplode(',', $this->tca['excluded_fields'], TRUE);
602
+		} elseif (!empty($this->tca['export']['excluded_fields'])) { // only for export for legacy reason.
603
+			$excludedFields = GeneralUtility::trimExplode(',', $this->tca['export']['excluded_fields'], TRUE);
604
+		}
605
+		return $excludedFields;
606
+
607
+	}
608
+
609
+	/**
610
+	 * Fetch excluded fields from preferences.
611
+	 *
612
+	 * @return array
613
+	 */
614
+	protected function getExcludedFieldsFromPreferences()
615
+	{
616
+		$excludedFields = $this->getModulePreferences()->get(ConfigurablePart::EXCLUDED_FIELDS, $this->tableName);
617
+		return is_array($excludedFields) ? $excludedFields : array();
618
+	}
619
+
620
+	/**
621
+	 * @return array
622
+	 */
623
+	public function areFilesIncludedInExport()
624
+	{
625
+		$isIncluded = TRUE;
626
+
627
+		if (isset($this->tca['export']['include_files'])) {
628
+			$isIncluded = $this->tca['export']['include_files'];
629
+		}
630
+		return $isIncluded;
631
+	}
632
+
633
+	/**
634
+	 * Returns a "facet" service instance.
635
+	 *
636
+	 * @param string|FacetInterface $facetName
637
+	 * @return StandardFacet
638
+	 */
639
+	protected function instantiateStandardFacet($facetName)
640
+	{
641
+		$label = $this->getLabel($facetName);
642
+
643
+		/** @var StandardFacet $facetName */
644
+		$facet = GeneralUtility::makeInstance('Fab\Vidi\Facet\StandardFacet', $facetName, $label);
645
+
646
+		if (!$facet instanceof StandardFacet) {
647
+			throw new \RuntimeException('I could not instantiate a facet for facet name "' . (string)$facet . '""', 1445856345);
648
+		}
649
+		return $facet;
650
+	}
651
+
652
+	/**
653
+	 * Returns a "facet" service instance.
654
+	 *
655
+	 * @param string|FacetInterface $facetName
656
+	 * @return FacetInterface
657
+	 */
658
+	public function facet($facetName = '')
659
+	{
660
+		$facets = $this->getFacets();
661
+		return $facets[$facetName];
662
+	}
663
+
664
+	/**
665
+	 * @return \Fab\Vidi\Resolver\FieldPathResolver
666
+	 */
667
+	protected function getFieldPathResolver()
668
+	{
669
+		return GeneralUtility::makeInstance('Fab\Vidi\Resolver\FieldPathResolver');
670
+	}
671
+
672
+	/**
673
+	 * @return ModulePreferences
674
+	 */
675
+	protected function getModulePreferences()
676
+	{
677
+		return GeneralUtility::makeInstance('Fab\Vidi\Module\ModulePreferences');
678
+	}
679 679
 
680 680
 }
Please login to merge, or discard this patch.