|
1
|
|
|
<?php |
|
2
|
|
|
namespace Fab\Vidi\ViewHelpers\Content; |
|
3
|
|
|
|
|
4
|
|
|
/* |
|
5
|
|
|
* This file is part of the Fab/Vidi project under GPLv2 or later. |
|
6
|
|
|
* |
|
7
|
|
|
* For the full copyright and license information, please read the |
|
8
|
|
|
* LICENSE.md file that was distributed with this source code. |
|
9
|
|
|
*/ |
|
10
|
|
|
|
|
11
|
|
|
use Fab\Vidi\Domain\Repository\ContentRepositoryFactory; |
|
12
|
|
|
use Fab\Vidi\Persistence\Matcher; |
|
13
|
|
|
use Fab\Vidi\Resolver\FieldPathResolver; |
|
14
|
|
|
use Fab\Vidi\Tca\Tca; |
|
15
|
|
|
use TYPO3\CMS\Core\Utility\ArrayUtility; |
|
16
|
|
|
use TYPO3\CMS\Core\Utility\GeneralUtility; |
|
17
|
|
|
use TYPO3\CMS\Fluid\Core\Rendering\RenderingContextInterface; |
|
18
|
|
|
use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper; |
|
19
|
|
|
use TYPO3\CMS\Fluid\Core\ViewHelper\Facets\CompilableInterface; |
|
20
|
|
|
|
|
21
|
|
|
/** |
|
22
|
|
|
* Class FindOneViewHelper |
|
23
|
|
|
*/ |
|
24
|
|
|
class FindOneViewHelper extends AbstractViewHelper implements CompilableInterface |
|
25
|
|
|
{ |
|
26
|
|
|
|
|
27
|
|
|
/** |
|
28
|
|
|
* @return void |
|
29
|
|
|
* @throws \TYPO3\CMS\Fluid\Core\ViewHelper\Exception |
|
30
|
|
|
*/ |
|
31
|
|
View Code Duplication |
public function initializeArguments() |
|
|
|
|
|
|
32
|
|
|
{ |
|
33
|
|
|
parent::initializeArguments(); |
|
34
|
|
|
|
|
35
|
|
|
$this->registerArgument('type', 'string', 'The content type', true, ''); |
|
36
|
|
|
$this->registerArgument('matches', 'array', 'Key / value array to be used as filter. The key corresponds to a field name.', false, []); |
|
37
|
|
|
$this->registerArgument('identifier', 'int', 'The identifier of the object to be fetched.', false, 0); |
|
38
|
|
|
$this->registerArgument('argumentName', 'string', 'The parameter name where to retrieve the identifier', false, 'tx_vidifrontend_pi1|uid'); |
|
39
|
|
|
$this->registerArgument('as', 'string', 'The alias object', false, 'object'); |
|
40
|
|
|
} |
|
41
|
|
|
|
|
42
|
|
|
/** |
|
43
|
|
|
* @return string Rendered string |
|
44
|
|
|
* @throws \Fab\Vidi\Exception\NotExistingClassException |
|
45
|
|
|
* @throws \TYPO3\CMS\Fluid\Core\ViewHelper\Exception\InvalidVariableException |
|
46
|
|
|
* @throws \InvalidArgumentException |
|
47
|
|
|
* @api |
|
48
|
|
|
*/ |
|
49
|
|
|
public function render() |
|
50
|
|
|
{ |
|
51
|
|
|
return static::renderStatic( |
|
52
|
|
|
$this->arguments, |
|
53
|
|
|
$this->buildRenderChildrenClosure(), |
|
54
|
|
|
$this->renderingContext |
|
55
|
|
|
); |
|
56
|
|
|
} |
|
57
|
|
|
|
|
58
|
|
|
/** |
|
59
|
|
|
* @param array $arguments |
|
60
|
|
|
* @param \Closure $renderChildrenClosure |
|
61
|
|
|
* @param RenderingContextInterface $renderingContext |
|
62
|
|
|
* |
|
63
|
|
|
* @return string |
|
64
|
|
|
* @throws \Fab\Vidi\Exception\NotExistingClassException |
|
65
|
|
|
* @throws \TYPO3\CMS\Fluid\Core\ViewHelper\Exception\InvalidVariableException |
|
66
|
|
|
* @throws \InvalidArgumentException |
|
67
|
|
|
*/ |
|
68
|
|
|
public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext) |
|
69
|
|
|
{ |
|
70
|
|
|
|
|
71
|
|
|
// Fetch the object |
|
72
|
|
|
$matches = self::computeMatches($arguments); |
|
73
|
|
|
$matcher = self::getMatcher($arguments['type'], $matches); |
|
74
|
|
|
|
|
75
|
|
|
$contentRepository = ContentRepositoryFactory::getInstance($arguments['type']); |
|
76
|
|
|
$object = $contentRepository->findOneBy($matcher); |
|
77
|
|
|
|
|
78
|
|
|
$output = ''; |
|
79
|
|
|
if ($object) { |
|
80
|
|
|
// Render children with "as" variable. |
|
81
|
|
|
$templateVariableContainer = $renderingContext->getTemplateVariableContainer(); |
|
82
|
|
|
$templateVariableContainer->add($arguments['as'], $object); |
|
83
|
|
|
$output = $renderChildrenClosure(); |
|
84
|
|
|
$templateVariableContainer->remove($arguments['as']); |
|
85
|
|
|
} |
|
86
|
|
|
|
|
87
|
|
|
return $output; |
|
88
|
|
|
} |
|
89
|
|
|
|
|
90
|
|
|
/** |
|
91
|
|
|
* @param array $arguments |
|
92
|
|
|
* @return array |
|
93
|
|
|
*/ |
|
94
|
|
|
protected static function computeMatches(array $arguments) |
|
95
|
|
|
{ |
|
96
|
|
|
|
|
97
|
|
|
$matches = []; |
|
98
|
|
|
|
|
99
|
|
|
$argumentValue = self::getArgumentValue($arguments['argumentName']); |
|
100
|
|
|
if ($argumentValue > 0) { |
|
101
|
|
|
$matches['uid'] = $argumentValue; |
|
102
|
|
|
} |
|
103
|
|
|
|
|
104
|
|
|
if ($arguments['matches']) { |
|
105
|
|
|
$matches = $arguments['matches']; |
|
106
|
|
|
} |
|
107
|
|
|
|
|
108
|
|
|
if ($arguments['identifier'] > 0) { |
|
109
|
|
|
$matches['uid'] = $arguments['identifier']; |
|
110
|
|
|
} |
|
111
|
|
|
|
|
112
|
|
|
// We want a default value in any case. |
|
113
|
|
|
if (!$matches) { |
|
114
|
|
|
$matches['uid'] = 0; |
|
115
|
|
|
} |
|
116
|
|
|
return $matches; |
|
117
|
|
|
} |
|
118
|
|
|
|
|
119
|
|
|
/** |
|
120
|
|
|
* Returns a matcher object. |
|
121
|
|
|
* |
|
122
|
|
|
* @param string $dataType |
|
123
|
|
|
* @param array $matches |
|
124
|
|
|
* @return Matcher |
|
125
|
|
|
* @throws \Fab\Vidi\Exception\NotExistingClassException |
|
126
|
|
|
* @throws \InvalidArgumentException |
|
127
|
|
|
*/ |
|
128
|
|
|
protected static function getMatcher($dataType, array $matches = []) |
|
129
|
|
|
{ |
|
130
|
|
|
|
|
131
|
|
|
/** @var $matcher Matcher */ |
|
132
|
|
|
$matcher = GeneralUtility::makeInstance(Matcher::class, [], $dataType); |
|
133
|
|
|
|
|
134
|
|
|
foreach ($matches as $fieldNameAndPath => $value) { |
|
135
|
|
|
|
|
136
|
|
|
// CSV values should be considered as "in" operator in Query, otherwise "equals". |
|
137
|
|
|
$explodedValues = GeneralUtility::trimExplode(',', $value, true); |
|
138
|
|
|
|
|
139
|
|
|
// The matching value contains a "1,2" as example |
|
140
|
|
|
if (count($explodedValues) > 1) { |
|
141
|
|
|
|
|
142
|
|
|
$resolvedDataType = self::getFieldPathResolver()->getDataType($fieldNameAndPath, $dataType); |
|
143
|
|
|
$resolvedFieldName = self::getFieldPathResolver()->stripFieldPath($fieldNameAndPath, $dataType); |
|
144
|
|
|
|
|
145
|
|
|
// "equals" if in presence of a relation. |
|
146
|
|
|
// "in" if not a relation. |
|
147
|
|
View Code Duplication |
if (Tca::table($resolvedDataType)->field($resolvedFieldName)->hasRelation()) { |
|
|
|
|
|
|
148
|
|
|
foreach ($explodedValues as $explodedValue) { |
|
149
|
|
|
$matcher->equals($fieldNameAndPath, $explodedValue); |
|
150
|
|
|
} |
|
151
|
|
|
} else { |
|
152
|
|
|
$matcher->in($fieldNameAndPath, $explodedValues); |
|
153
|
|
|
} |
|
154
|
|
|
} else { |
|
155
|
|
|
$matcher->equals($fieldNameAndPath, $explodedValues[0]); |
|
156
|
|
|
} |
|
157
|
|
|
} |
|
158
|
|
|
|
|
159
|
|
|
return $matcher; |
|
160
|
|
|
} |
|
161
|
|
|
|
|
162
|
|
|
/** |
|
163
|
|
|
* @return FieldPathResolver |
|
164
|
|
|
* @throws \InvalidArgumentException |
|
165
|
|
|
*/ |
|
166
|
|
|
protected static function getFieldPathResolver() |
|
167
|
|
|
{ |
|
168
|
|
|
return GeneralUtility::makeInstance(FieldPathResolver::class); |
|
169
|
|
|
} |
|
170
|
|
|
|
|
171
|
|
|
/** |
|
172
|
|
|
* @param string $argumentName |
|
173
|
|
|
* @return int |
|
174
|
|
|
*/ |
|
175
|
|
|
protected static function getArgumentValue($argumentName) |
|
176
|
|
|
{ |
|
177
|
|
|
|
|
178
|
|
|
$value = ''; // default value |
|
179
|
|
|
|
|
180
|
|
|
// Merge parameters |
|
181
|
|
|
$parameters = GeneralUtility::_GET(); |
|
182
|
|
|
$post = GeneralUtility::_POST(); |
|
183
|
|
|
ArrayUtility::mergeRecursiveWithOverrule($parameters, $post); |
|
184
|
|
|
|
|
185
|
|
|
// Traverse argument parts and retrieve value. |
|
186
|
|
|
$argumentParts = GeneralUtility::trimExplode('|', $argumentName); |
|
187
|
|
View Code Duplication |
foreach ($argumentParts as $argumentPart) { |
|
|
|
|
|
|
188
|
|
|
if (isset($parameters[$argumentPart])) { |
|
189
|
|
|
$value = $parameters[$argumentPart]; |
|
190
|
|
|
$parameters = $value; |
|
191
|
|
|
} |
|
192
|
|
|
} |
|
193
|
|
|
|
|
194
|
|
|
return (int)$value; |
|
195
|
|
|
} |
|
196
|
|
|
|
|
197
|
|
|
} |
|
198
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.