Completed
Push — master ( 53fe6d...24e7f8 )
by Fabien
51:26
created
Classes/ViewHelpers/Content/AbstractContentViewHelper.php 1 patch
Indentation   +209 added lines, -209 removed lines patch added patch discarded remove patch
@@ -25,214 +25,214 @@
 block discarded – undo
25 25
 abstract class AbstractContentViewHelper extends AbstractViewHelper
26 26
 {
27 27
 
28
-    /**
29
-     * @return void
30
-     * @throws \TYPO3\CMS\Fluid\Core\ViewHelper\Exception
31
-     */
32
-    public function initializeArguments()
33
-    {
34
-        $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, '');
35
-        $this->registerArgument('matches', 'array', 'Key / value array to be used as filter. The key corresponds to a field name.', false, array());
36
-        $this->registerArgument('selection', 'int', 'A possible selection defined in the BE and stored in the database.', false, 0);
37
-        $this->registerArgument('ignoreEnableFields', 'bool', 'Whether to ignore enable fields or not (AKA hidden, deleted, starttime, ...).', false, false);
38
-        $this->registerArgument('aliases', 'array', 'Attribute "matches" does not support certain character such as "." in field name. Use this to create aliases.', false, array());
39
-    }
40
-
41
-    /**
42
-     * Generate a signature to be used for storing the result set.
43
-     *
44
-     * @param string $dataType
45
-     * @param array $matches
46
-     * @param array $orderings
47
-     * @param $limit
48
-     * @param $offset
49
-     * @return string
50
-     */
51
-    protected function getQuerySignature($dataType, array $matches, array $orderings, $limit, $offset)
52
-    {
53
-        $serializedMatches = serialize($matches);
54
-        $serializedOrderings = serialize($orderings);
55
-        return md5($dataType . $serializedMatches . $serializedOrderings . $limit . $offset);
56
-    }
57
-
58
-    /**
59
-     * Returns a matcher object.
60
-     *
61
-     * @param string $dataType
62
-     * @param array $matches
63
-     * @return Matcher
64
-     * @throws \Fab\Vidi\Exception\NotExistingClassException
65
-     * @throws \InvalidArgumentException
66
-     */
67
-    protected function getMatcher($dataType, $matches = array())
68
-    {
69
-
70
-        /** @var $matcher Matcher */
71
-        $matcher = GeneralUtility::makeInstance(Matcher::class, [], $dataType);
72
-
73
-        // @todo implement advanced selection parsing {or: {usergroup.title: {like: foo}}, {tstamp: {greaterThan: 1234}}}
74
-        foreach ($matches as $fieldNameAndPath => $value) {
75
-
76
-            // CSV values should be considered as "in" operator in Query, otherwise "equals".
77
-            $explodedValues = GeneralUtility::trimExplode(',', $value, true);
78
-
79
-            // The matching value contains a "1,2" as example
80
-            if (count($explodedValues) > 1) {
81
-
82
-                $resolvedDataType = $this->getFieldPathResolver()->getDataType($fieldNameAndPath, $dataType);
83
-                $resolvedFieldName = $this->getFieldPathResolver()->stripFieldPath($fieldNameAndPath, $dataType);
84
-
85
-                // "equals" if in presence of a relation.
86
-                // "in" if not a relation.
87
-                if (Tca::table($resolvedDataType)->field($resolvedFieldName)->hasRelation()) {
88
-                    foreach ($explodedValues as $explodedValue) {
89
-                        $matcher->equals($fieldNameAndPath, $explodedValue);
90
-                    }
91
-                } else {
92
-                    $matcher->in($fieldNameAndPath, $explodedValues);
93
-                }
94
-            } else {
95
-                $matcher->equals($fieldNameAndPath, $explodedValues[0]);
96
-            }
97
-        }
98
-
99
-        // Trigger signal for post processing Matcher Object.
100
-        $this->emitPostProcessMatcherObjectSignal($matcher->getDataType(), $matcher);
101
-
102
-        return $matcher;
103
-    }
104
-
105
-    /**
106
-     * Replace possible aliases.
107
-     *
108
-     * @param array $values
109
-     * @return array
110
-     */
111
-    protected function replacesAliases(array $values)
112
-    {
113
-
114
-        $aliases = $this->arguments['aliases'];
115
-
116
-        foreach ($aliases as $aliasName => $aliasValue) {
117
-            if (isset($values[$aliasName])) {
118
-                $values[$aliasValue] = $values[$aliasName];
119
-                unset($values[$aliasName]); // remove the alias.
120
-            }
121
-        }
122
-
123
-        return $values;
124
-    }
125
-
126
-    /**
127
-     * Returns an order object.
128
-     *
129
-     * @param string $dataType
130
-     * @param array $order
131
-     * @return Order
132
-     */
133
-    public function getOrder($dataType, array $order = array())
134
-    {
135
-        // Default orderings in case order is empty.
136
-        if (empty($order)) {
137
-            $order = Tca::table($dataType)->getDefaultOrderings();
138
-        }
139
-
140
-        $order = GeneralUtility::makeInstance(Order::class, $order);
141
-
142
-        // Trigger signal for post processing Order Object.
143
-        $this->emitPostProcessOrderObjectSignal($dataType, $order);
144
-
145
-        return $order;
146
-    }
147
-
148
-    /**
149
-     * @return ResultSetStorage
150
-     */
151
-    public function getResultSetStorage()
152
-    {
153
-        return GeneralUtility::makeInstance(ResultSetStorage::class);
154
-    }
155
-
156
-    /**
157
-     * Signal that is called for post-processing a "order" object.
158
-     *
159
-     * @param string $dataType
160
-     * @param Order $order
161
-     */
162
-    protected function emitPostProcessOrderObjectSignal($dataType, Order $order)
163
-    {
164
-        $this->getSignalSlotDispatcher()->dispatch('Fab\Vidi\ViewHelper\Content\AbstractContentViewHelper', 'postProcessOrderObject', array($order, $dataType));
165
-    }
166
-
167
-    /**
168
-     * Signal that is called for post-processing a "matcher" object.
169
-     *
170
-     * @param string $dataType
171
-     * @param Matcher $matcher
172
-     */
173
-    protected function emitPostProcessMatcherObjectSignal($dataType, Matcher $matcher)
174
-    {
175
-        $this->getSignalSlotDispatcher()->dispatch('Fab\Vidi\ViewHelper\Content\AbstractContentViewHelper', 'postProcessMatcherObject', array($matcher, $dataType));
176
-    }
177
-
178
-    /**
179
-     * Signal that is called for post-processing a "limit".
180
-     *
181
-     * @param string $dataType
182
-     * @param int $limit
183
-     */
184
-    protected function emitPostProcessLimitSignal($dataType, $limit)
185
-    {
186
-        $this->getSignalSlotDispatcher()->dispatch('Fab\Vidi\ViewHelper\Content\AbstractContentViewHelper', 'postProcessLimit', array($limit, $dataType));
187
-    }
188
-
189
-    /**
190
-     * Signal that is called for post-processing a "offset".
191
-     *
192
-     * @param string $dataType
193
-     * @param int $offset
194
-     */
195
-    protected function emitPostProcessOffsetSignal($dataType, $offset)
196
-    {
197
-        $this->getSignalSlotDispatcher()->dispatch('Fab\Vidi\ViewHelper\Content\AbstractContentViewHelper', 'postProcessLimit', array($offset, $dataType));
198
-    }
199
-
200
-    /**
201
-     * Get the SignalSlot dispatcher
202
-     *
203
-     * @return Dispatcher
204
-     */
205
-    protected function getSignalSlotDispatcher()
206
-    {
207
-        return $this->getObjectManager()->get(Dispatcher::class);
208
-    }
209
-
210
-    /**
211
-     * @return ObjectManager
212
-     */
213
-    protected function getObjectManager()
214
-    {
215
-        return GeneralUtility::makeInstance(ObjectManager::class);
216
-    }
217
-
218
-    /**
219
-     * @param $ignoreEnableFields
220
-     * @return \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface
221
-     */
222
-    protected function getDefaultQuerySettings($ignoreEnableFields)
223
-    {
224
-        /** @var QuerySettings $defaultQuerySettings */
225
-        $defaultQuerySettings = GeneralUtility::makeInstance(QuerySettings::class);
226
-        $defaultQuerySettings->setIgnoreEnableFields($ignoreEnableFields);
227
-        return $defaultQuerySettings;
228
-    }
229
-
230
-    /**
231
-     * @return FieldPathResolver
232
-     */
233
-    protected function getFieldPathResolver()
234
-    {
235
-        return GeneralUtility::makeInstance(FieldPathResolver::class);
236
-    }
28
+	/**
29
+	 * @return void
30
+	 * @throws \TYPO3\CMS\Fluid\Core\ViewHelper\Exception
31
+	 */
32
+	public function initializeArguments()
33
+	{
34
+		$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, '');
35
+		$this->registerArgument('matches', 'array', 'Key / value array to be used as filter. The key corresponds to a field name.', false, array());
36
+		$this->registerArgument('selection', 'int', 'A possible selection defined in the BE and stored in the database.', false, 0);
37
+		$this->registerArgument('ignoreEnableFields', 'bool', 'Whether to ignore enable fields or not (AKA hidden, deleted, starttime, ...).', false, false);
38
+		$this->registerArgument('aliases', 'array', 'Attribute "matches" does not support certain character such as "." in field name. Use this to create aliases.', false, array());
39
+	}
40
+
41
+	/**
42
+	 * Generate a signature to be used for storing the result set.
43
+	 *
44
+	 * @param string $dataType
45
+	 * @param array $matches
46
+	 * @param array $orderings
47
+	 * @param $limit
48
+	 * @param $offset
49
+	 * @return string
50
+	 */
51
+	protected function getQuerySignature($dataType, array $matches, array $orderings, $limit, $offset)
52
+	{
53
+		$serializedMatches = serialize($matches);
54
+		$serializedOrderings = serialize($orderings);
55
+		return md5($dataType . $serializedMatches . $serializedOrderings . $limit . $offset);
56
+	}
57
+
58
+	/**
59
+	 * Returns a matcher object.
60
+	 *
61
+	 * @param string $dataType
62
+	 * @param array $matches
63
+	 * @return Matcher
64
+	 * @throws \Fab\Vidi\Exception\NotExistingClassException
65
+	 * @throws \InvalidArgumentException
66
+	 */
67
+	protected function getMatcher($dataType, $matches = array())
68
+	{
69
+
70
+		/** @var $matcher Matcher */
71
+		$matcher = GeneralUtility::makeInstance(Matcher::class, [], $dataType);
72
+
73
+		// @todo implement advanced selection parsing {or: {usergroup.title: {like: foo}}, {tstamp: {greaterThan: 1234}}}
74
+		foreach ($matches as $fieldNameAndPath => $value) {
75
+
76
+			// CSV values should be considered as "in" operator in Query, otherwise "equals".
77
+			$explodedValues = GeneralUtility::trimExplode(',', $value, true);
78
+
79
+			// The matching value contains a "1,2" as example
80
+			if (count($explodedValues) > 1) {
81
+
82
+				$resolvedDataType = $this->getFieldPathResolver()->getDataType($fieldNameAndPath, $dataType);
83
+				$resolvedFieldName = $this->getFieldPathResolver()->stripFieldPath($fieldNameAndPath, $dataType);
84
+
85
+				// "equals" if in presence of a relation.
86
+				// "in" if not a relation.
87
+				if (Tca::table($resolvedDataType)->field($resolvedFieldName)->hasRelation()) {
88
+					foreach ($explodedValues as $explodedValue) {
89
+						$matcher->equals($fieldNameAndPath, $explodedValue);
90
+					}
91
+				} else {
92
+					$matcher->in($fieldNameAndPath, $explodedValues);
93
+				}
94
+			} else {
95
+				$matcher->equals($fieldNameAndPath, $explodedValues[0]);
96
+			}
97
+		}
98
+
99
+		// Trigger signal for post processing Matcher Object.
100
+		$this->emitPostProcessMatcherObjectSignal($matcher->getDataType(), $matcher);
101
+
102
+		return $matcher;
103
+	}
104
+
105
+	/**
106
+	 * Replace possible aliases.
107
+	 *
108
+	 * @param array $values
109
+	 * @return array
110
+	 */
111
+	protected function replacesAliases(array $values)
112
+	{
113
+
114
+		$aliases = $this->arguments['aliases'];
115
+
116
+		foreach ($aliases as $aliasName => $aliasValue) {
117
+			if (isset($values[$aliasName])) {
118
+				$values[$aliasValue] = $values[$aliasName];
119
+				unset($values[$aliasName]); // remove the alias.
120
+			}
121
+		}
122
+
123
+		return $values;
124
+	}
125
+
126
+	/**
127
+	 * Returns an order object.
128
+	 *
129
+	 * @param string $dataType
130
+	 * @param array $order
131
+	 * @return Order
132
+	 */
133
+	public function getOrder($dataType, array $order = array())
134
+	{
135
+		// Default orderings in case order is empty.
136
+		if (empty($order)) {
137
+			$order = Tca::table($dataType)->getDefaultOrderings();
138
+		}
139
+
140
+		$order = GeneralUtility::makeInstance(Order::class, $order);
141
+
142
+		// Trigger signal for post processing Order Object.
143
+		$this->emitPostProcessOrderObjectSignal($dataType, $order);
144
+
145
+		return $order;
146
+	}
147
+
148
+	/**
149
+	 * @return ResultSetStorage
150
+	 */
151
+	public function getResultSetStorage()
152
+	{
153
+		return GeneralUtility::makeInstance(ResultSetStorage::class);
154
+	}
155
+
156
+	/**
157
+	 * Signal that is called for post-processing a "order" object.
158
+	 *
159
+	 * @param string $dataType
160
+	 * @param Order $order
161
+	 */
162
+	protected function emitPostProcessOrderObjectSignal($dataType, Order $order)
163
+	{
164
+		$this->getSignalSlotDispatcher()->dispatch('Fab\Vidi\ViewHelper\Content\AbstractContentViewHelper', 'postProcessOrderObject', array($order, $dataType));
165
+	}
166
+
167
+	/**
168
+	 * Signal that is called for post-processing a "matcher" object.
169
+	 *
170
+	 * @param string $dataType
171
+	 * @param Matcher $matcher
172
+	 */
173
+	protected function emitPostProcessMatcherObjectSignal($dataType, Matcher $matcher)
174
+	{
175
+		$this->getSignalSlotDispatcher()->dispatch('Fab\Vidi\ViewHelper\Content\AbstractContentViewHelper', 'postProcessMatcherObject', array($matcher, $dataType));
176
+	}
177
+
178
+	/**
179
+	 * Signal that is called for post-processing a "limit".
180
+	 *
181
+	 * @param string $dataType
182
+	 * @param int $limit
183
+	 */
184
+	protected function emitPostProcessLimitSignal($dataType, $limit)
185
+	{
186
+		$this->getSignalSlotDispatcher()->dispatch('Fab\Vidi\ViewHelper\Content\AbstractContentViewHelper', 'postProcessLimit', array($limit, $dataType));
187
+	}
188
+
189
+	/**
190
+	 * Signal that is called for post-processing a "offset".
191
+	 *
192
+	 * @param string $dataType
193
+	 * @param int $offset
194
+	 */
195
+	protected function emitPostProcessOffsetSignal($dataType, $offset)
196
+	{
197
+		$this->getSignalSlotDispatcher()->dispatch('Fab\Vidi\ViewHelper\Content\AbstractContentViewHelper', 'postProcessLimit', array($offset, $dataType));
198
+	}
199
+
200
+	/**
201
+	 * Get the SignalSlot dispatcher
202
+	 *
203
+	 * @return Dispatcher
204
+	 */
205
+	protected function getSignalSlotDispatcher()
206
+	{
207
+		return $this->getObjectManager()->get(Dispatcher::class);
208
+	}
209
+
210
+	/**
211
+	 * @return ObjectManager
212
+	 */
213
+	protected function getObjectManager()
214
+	{
215
+		return GeneralUtility::makeInstance(ObjectManager::class);
216
+	}
217
+
218
+	/**
219
+	 * @param $ignoreEnableFields
220
+	 * @return \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface
221
+	 */
222
+	protected function getDefaultQuerySettings($ignoreEnableFields)
223
+	{
224
+		/** @var QuerySettings $defaultQuerySettings */
225
+		$defaultQuerySettings = GeneralUtility::makeInstance(QuerySettings::class);
226
+		$defaultQuerySettings->setIgnoreEnableFields($ignoreEnableFields);
227
+		return $defaultQuerySettings;
228
+	}
229
+
230
+	/**
231
+	 * @return FieldPathResolver
232
+	 */
233
+	protected function getFieldPathResolver()
234
+	{
235
+		return GeneralUtility::makeInstance(FieldPathResolver::class);
236
+	}
237 237
 
238 238
 }
Please login to merge, or discard this patch.
Classes/Domain/Repository/ContentRepository.php 1 patch
Indentation   +853 added lines, -853 removed lines patch added patch discarded remove patch
@@ -38,858 +38,858 @@
 block discarded – undo
38 38
 class ContentRepository implements RepositoryInterface
39 39
 {
40 40
 
41
-    /**
42
-     * Tell whether it is a raw result (array) or object being returned.
43
-     *
44
-     * @var bool
45
-     */
46
-    protected $rawResult = false;
47
-
48
-    /**
49
-     * The data type to be returned, e.g fe_users, fe_groups, tt_content, etc...
50
-     *
51
-     * @var string
52
-     */
53
-    protected $dataType;
54
-
55
-    /**
56
-     * The source field is useful in the context of MM relations to know who is the caller
57
-     * e.g findByItems which eventually corresponds to a field name.
58
-     *
59
-     * @var string
60
-     */
61
-    protected $sourceFieldName = '';
62
-
63
-    /**
64
-     * @var array
65
-     */
66
-    protected $errorMessages = [];
67
-
68
-    /**
69
-     * @var QuerySettingsInterface
70
-     */
71
-    protected $defaultQuerySettings;
72
-
73
-    /**
74
-     * @var DataHandler
75
-     */
76
-    protected $dataHandler;
77
-
78
-    /**
79
-     * Constructor
80
-     *
81
-     * @param string $dataType
82
-     */
83
-    public function __construct($dataType)
84
-    {
85
-        $this->dataType = $dataType;
86
-    }
87
-
88
-    /**
89
-     * Returns all objects of this repository.
90
-     *
91
-     * @return Content[]
92
-     */
93
-    public function findAll()
94
-    {
95
-        $query = $this->createQuery();
96
-        return $query->execute();
97
-    }
98
-
99
-    /**
100
-     * Returns all "distinct" values for a given property.
101
-     *
102
-     * @param string $propertyName
103
-     * @param Matcher $matcher
104
-     * @param Order|null $order
105
-     * @return Content[]
106
-     */
107
-    public function findDistinctValues($propertyName, Matcher $matcher = null, Order $order = null): array
108
-    {
109
-        $query = $this->createQuery();
110
-        $query->setDistinct($propertyName);
111
-
112
-        // Remove empty values from selection.
113
-        $constraint = $query->logicalNot($query->equals($propertyName, ''));
114
-
115
-        // Add some additional constraints from the Matcher object.
116
-        $matcherConstraint = null;
117
-        if ($matcher !== null) {
118
-            $matcherConstraint = $this->computeConstraints($query, $matcher);
119
-        }
120
-
121
-        // Assemble the final constraints or not.
122
-        if ($matcherConstraint) {
123
-            $query->logicalAnd($matcherConstraint, $constraint);
124
-            $query->matching($query->logicalAnd($matcherConstraint, $constraint));
125
-        } else {
126
-            $query->matching($constraint);
127
-        }
128
-
129
-        if ($order) {
130
-            $query->setOrderings($order->getOrderings());
131
-        }
132
-
133
-        return $query->execute();
134
-    }
135
-
136
-    /**
137
-     * Returns all "distinct" values for a given property.
138
-     *
139
-     * @param string $propertyName
140
-     * @param Matcher $matcher
141
-     * @return int
142
-     */
143
-    public function countDistinctValues($propertyName, Matcher $matcher = null): int
144
-    {
145
-        $query = $this->createQuery();
146
-        $query->setDistinct($propertyName);
147
-
148
-        // Remove empty values from selection.
149
-        $constraint = $query->logicalNot($query->equals($propertyName, ''));
150
-
151
-        // Add some additional constraints from the Matcher object.
152
-        $matcherConstraint = null;
153
-        if (!is_null($matcher)) {
154
-            $matcherConstraint = $this->computeConstraints($query, $matcher);
155
-        }
156
-
157
-        // Assemble the final constraints or not.
158
-        if ($matcherConstraint) {
159
-            $query->logicalAnd($matcherConstraint, $constraint);
160
-            $query->matching($query->logicalAnd($matcherConstraint, $constraint));
161
-        } else {
162
-            $query->matching($constraint);
163
-        }
164
-
165
-        return $query->count();
166
-    }
167
-
168
-    /**
169
-     * Finds an object matching the given identifier.
170
-     *
171
-     * @param int $uid The identifier of the object to find
172
-     * @return Content|null
173
-     * @api
174
-     */
175
-    public function findByUid($uid)
176
-    {
177
-        return $this->findByIdentifier($uid);
178
-    }
179
-
180
-    /**
181
-     * Finds all Contents given specified matches.
182
-     *
183
-     * @param string $propertyName
184
-     * @param array $values
185
-     * @return Content[]
186
-     */
187
-    public function findIn($propertyName, array $values): array
188
-    {
189
-        $query = $this->createQuery();
190
-        $query->matching($query->in($propertyName, $values));
191
-        return $query->execute();
192
-    }
193
-
194
-    /**
195
-     * Finds all Contents given specified matches.
196
-     *
197
-     * @param Matcher $matcher
198
-     * @param Order $order The order
199
-     * @param int $limit
200
-     * @param int $offset
201
-     * @return Content[]
202
-     */
203
-    public function findBy(Matcher $matcher, Order $order = null, $limit = null, $offset = null): array
204
-    {
205
-
206
-        $query = $this->createQuery();
207
-
208
-        $limit = (int)$limit; // make sure to cast
209
-        if ($limit > 0) {
210
-            $query->setLimit($limit);
211
-        }
212
-
213
-        if ($order) {
214
-            $query->setOrderings($order->getOrderings());
215
-
216
-            // Loops around the orderings adding if necessary a dummy condition
217
-            // to make sure the relations can be resolved when transforming the query to plain SQL.
218
-            foreach ($order->getOrderings() as $ordering => $direction) {
219
-                if ($this->hasForeignRelationIn($ordering)) {
220
-                    $relationalField = $this->getForeignRelationFrom($ordering);
221
-                    $matcher->like($relationalField . '.uid', '');
222
-                }
223
-            }
224
-        }
225
-
226
-        if ($offset) {
227
-            $query->setOffset($offset);
228
-        }
229
-
230
-        $constraints = $this->computeConstraints($query, $matcher);
231
-
232
-        if ($constraints) {
233
-            $query->matching($constraints);
234
-        }
235
-
236
-        return $query->execute();
237
-    }
238
-
239
-    /**
240
-     * Find one Content object given specified matches.
241
-     *
242
-     * @param Matcher $matcher
243
-     * @return Content
244
-     */
245
-    public function findOneBy(Matcher $matcher): Content
246
-    {
247
-
248
-        $query = $this->createQuery();
249
-
250
-        $constraints = $this->computeConstraints($query, $matcher);
251
-
252
-        if ($constraints) {
253
-            $query->matching($constraints);
254
-        }
255
-
256
-        $query->setLimit(1); // only take one!
257
-
258
-        $resultSet = $query->execute();
259
-        if ($resultSet) {
260
-            $resultSet = current($resultSet);
261
-        }
262
-        return $resultSet;
263
-    }
264
-
265
-    /**
266
-     * Count all Contents given specified matches.
267
-     *
268
-     * @param Matcher $matcher
269
-     * @return int
270
-     */
271
-    public function countBy(Matcher $matcher): int
272
-    {
273
-
274
-        $query = $this->createQuery();
275
-
276
-        $constraints = $this->computeConstraints($query, $matcher);
277
-
278
-        if ($constraints) {
279
-            $query->matching($constraints);
280
-        }
281
-
282
-        return $query->count();
283
-    }
284
-
285
-    /**
286
-     * Update a content with new information.
287
-     *
288
-     * @param Content $content
289
-     * @param $language
290
-     * @return bool
291
-     */
292
-    public function localize($content, $language): bool
293
-    {
294
-
295
-        // Security check
296
-        $this->getContentValidator()->validate($content);
297
-        $this->getLanguageValidator()->validate($language);
298
-
299
-        $dataType = $content->getDataType();
300
-        $handler = $this->getDataHandlerFactory()->action(ProcessAction::LOCALIZE)->forType($dataType)->getDataHandler();
301
-
302
-        $handlerResult = $handler->processLocalize($content, $language);
303
-        $this->errorMessages = $handler->getErrorMessages();
304
-        return $handlerResult;
305
-    }
306
-
307
-    /**
308
-     * Update a content with new information.
309
-     *
310
-     * @param Content $content
311
-     * @return bool
312
-     */
313
-    public function update($content)
314
-    {
315
-
316
-        // Security check.
317
-        $this->getContentValidator()->validate($content);
318
-
319
-        $dataType = $content->getDataType();
320
-        $handler = $this->getDataHandlerFactory()->action(ProcessAction::UPDATE)->forType($dataType)->getDataHandler();
321
-
322
-        $handlerResult = $handler->processUpdate($content);
323
-        $this->errorMessages = $handler->getErrorMessages();
324
-        return $handlerResult;
325
-    }
326
-
327
-    /**
328
-     * Removes an object from this repository.
329
-     *
330
-     * @param Content $content
331
-     * @return boolean
332
-     */
333
-    public function remove($content)
334
-    {
335
-        $dataType = $content->getDataType();
336
-        $handler = $this->getDataHandlerFactory()->action(ProcessAction::REMOVE)->forType($dataType)->getDataHandler();
337
-
338
-        $handlerResult = $handler->processRemove($content);
339
-        $this->errorMessages = $handler->getErrorMessages();
340
-        return $handlerResult;
341
-    }
342
-
343
-    /**
344
-     * Move a content within this repository.
345
-     * The $target corresponds to the pid to move the records to.
346
-     * It can also be a negative value in case of sorting. The negative value would be the uid of its predecessor.
347
-     *
348
-     * @param Content $content
349
-     * @param string $target
350
-     * @return bool
351
-     */
352
-    public function move($content, $target): bool
353
-    {
354
-
355
-        // Security check.
356
-        $this->getContentValidator()->validate($content);
357
-
358
-        $dataType = $content->getDataType();
359
-        $handler = $this->getDataHandlerFactory()->action(ProcessAction::MOVE)->forType($dataType)->getDataHandler();
360
-
361
-        $handlerResult = $handler->processMove($content, $target);
362
-        $this->errorMessages = $handler->getErrorMessages();
363
-        return $handlerResult;
364
-    }
365
-
366
-    /**
367
-     * Copy a content within this repository.
368
-     *
369
-     * @param Content $content
370
-     * @return bool
371
-     */
372
-    public function copy($content, $target): bool
373
-    {
374
-
375
-        // Security check.
376
-        $this->getContentValidator()->validate($content);
377
-
378
-        $dataType = $content->getDataType();
379
-        $handler = $this->getDataHandlerFactory()->action(ProcessAction::COPY)->forType($dataType)->getDataHandler();
380
-
381
-        $handlerResult = $handler->processCopy($content, $target);
382
-        $this->errorMessages = $handler->getErrorMessages();
383
-        return $handlerResult;
384
-    }
385
-
386
-    /**
387
-     * Adds an object to this repository.
388
-     *
389
-     * @param object $object The object to add
390
-     * @return void
391
-     * @api
392
-     */
393
-    public function add($object)
394
-    {
395
-        throw new \BadMethodCallException('Repository does not support the add() method.', 1375805599);
396
-    }
397
-
398
-    /**
399
-     * Returns the total number objects of this repository.
400
-     *
401
-     * @return integer The object count
402
-     * @api
403
-     */
404
-    public function countAll()
405
-    {
406
-        $query = $this->createQuery();
407
-        return $query->count();
408
-    }
409
-
410
-    /**
411
-     * Removes all objects of this repository as if remove() was called for
412
-     * all of them.
413
-     *
414
-     * @return void
415
-     * @api
416
-     */
417
-    public function removeAll()
418
-    {
419
-        // TODO: Implement removeAll() method.
420
-    }
421
-
422
-    /**
423
-     * Finds an object matching the given identifier.
424
-     *
425
-     * @param mixed $identifier The identifier of the object to find
426
-     * @return Content|null
427
-     * @api
428
-     */
429
-    public function findByIdentifier($identifier)
430
-    {
431
-        $query = $this->createQuery();
432
-
433
-        $result = $query->matching(
434
-            $query->equals('uid', $identifier)
435
-        )
436
-            ->execute();
437
-
438
-        if (is_array($result)) {
439
-            $result = current($result);
440
-        }
441
-
442
-        return $result;
443
-    }
444
-
445
-    /**
446
-     * Dispatches magic methods (findBy[Property]())
447
-     *
448
-     * @param string $methodName The name of the magic method
449
-     * @param string $arguments The arguments of the magic method
450
-     * @return mixed
451
-     * @api
452
-     */
453
-    public function __call($methodName, $arguments)
454
-    {
455
-        if (substr($methodName, 0, 6) === 'findBy' && strlen($methodName) > 7) {
456
-            $propertyName = strtolower(substr(substr($methodName, 6), 0, 1)) . substr(substr($methodName, 6), 1);
457
-            $result = $this->processMagicCall($propertyName, $arguments[0]);
458
-        } elseif (substr($methodName, 0, 9) === 'findOneBy' && strlen($methodName) > 10) {
459
-            $propertyName = strtolower(substr(substr($methodName, 9), 0, 1)) . substr(substr($methodName, 9), 1);
460
-            $result = $this->processMagicCall($propertyName, $arguments[0], 'one');
461
-        } elseif (substr($methodName, 0, 7) === 'countBy' && strlen($methodName) > 8) {
462
-            $propertyName = strtolower(substr(substr($methodName, 7), 0, 1)) . substr(substr($methodName, 7), 1);
463
-            $result = $this->processMagicCall($propertyName, $arguments[0], 'count');
464
-        } else {
465
-            throw new UnsupportedMethodException('The method "' . $methodName . '" is not supported by the repository.', 1360838010);
466
-        }
467
-        return $result;
468
-    }
469
-
470
-    /**
471
-     * Returns a query for objects of this repository
472
-     *
473
-     * @return Query
474
-     * @api
475
-     */
476
-    public function createQuery()
477
-    {
478
-        /** @var Query $query */
479
-        $query = $this->getObjectManager()->get(Query::class, $this->dataType);
480
-        $query->setSourceFieldName($this->sourceFieldName);
481
-
482
-        if ($this->defaultQuerySettings) {
483
-            $query->setQuerySettings($this->defaultQuerySettings);
484
-        } else {
485
-
486
-            // Initialize and pass the query settings at this level.
487
-            /** @var QuerySettings $querySettings */
488
-            $querySettings = $this->getObjectManager()->get(QuerySettings::class);
489
-
490
-            // Default choice for the BE.
491
-            if ($this->isBackendMode()) {
492
-                $querySettings->setIgnoreEnableFields(true);
493
-            }
494
-
495
-            $query->setQuerySettings($querySettings);
496
-        }
497
-
498
-        return $query;
499
-    }
500
-
501
-    /**
502
-     * Sets the property names to order the result by per default.
503
-     * Expected like this:
504
-     * array(
505
-     * 'foo' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_ASCENDING,
506
-     * 'bar' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_DESCENDING
507
-     * )
508
-     *
509
-     * @param array $defaultOrderings The property names to order by
510
-     * @return void
511
-     * @api
512
-     */
513
-    public function setDefaultOrderings(array $defaultOrderings)
514
-    {
515
-        throw new \BadMethodCallException('Repository does not support the setDefaultOrderings() method.', 1375805598);
516
-    }
517
-
518
-    /**
519
-     * Sets the default query settings to be used in this repository
520
-     *
521
-     * @param QuerySettingsInterface $defaultQuerySettings The query settings to be used by default
522
-     * @return void
523
-     * @api
524
-     */
525
-    public function setDefaultQuerySettings(QuerySettingsInterface $defaultQuerySettings)
526
-    {
527
-        $this->defaultQuerySettings = $defaultQuerySettings;
528
-    }
529
-
530
-    /**
531
-     * @return void
532
-     */
533
-    public function resetDefaultQuerySettings(): void
534
-    {
535
-        $this->defaultQuerySettings = null;
536
-    }
537
-
538
-
539
-    /**
540
-     * @return array
541
-     */
542
-    public function getErrorMessages(): array
543
-    {
544
-        return $this->errorMessages;
545
-    }
546
-
547
-    /**
548
-     * @param string $sourceFieldName
549
-     * @return $this
550
-     */
551
-    public function setSourceFieldName($sourceFieldName): self
552
-    {
553
-        $this->sourceFieldName = $sourceFieldName;
554
-        return $this;
555
-    }
556
-
557
-    /**
558
-     * @return string
559
-     */
560
-    public function getDataType(): string
561
-    {
562
-        return $this->dataType;
563
-    }
564
-
565
-    /**
566
-     * Tell whether the order has a foreign table in its expression, e.g. "metadata.title".
567
-     *
568
-     * @param string $ordering
569
-     * @return bool
570
-     */
571
-    protected function hasForeignRelationIn($ordering): bool
572
-    {
573
-        return strpos($ordering, '.') !== false;
574
-    }
575
-
576
-    /**
577
-     * Extract the foreign relation of the ordering "metadata.title" -> "metadata"
578
-     *
579
-     * @param string $ordering
580
-     * @return string
581
-     */
582
-    protected function getForeignRelationFrom($ordering): string
583
-    {
584
-        $parts = explode('.', $ordering);
585
-        return $parts[0];
586
-    }
587
-
588
-    /**
589
-     * Get the constraints
590
-     *
591
-     * @param Query $query
592
-     * @param Matcher $matcher
593
-     * @return ConstraintInterface|null
594
-     */
595
-    protected function computeConstraints(Query $query, Matcher $matcher): ?ConstraintInterface
596
-    {
597
-        $constraints = null;
598
-
599
-        $collectedConstraints = [];
600
-
601
-        // Search term
602
-        $constraint = $this->computeSearchTermConstraint($query, $matcher);
603
-        if ($constraint) {
604
-            $collectedConstraints[] = $constraint;
605
-        }
606
-
607
-        foreach ($matcher->getSupportedOperators() as $operator) {
608
-            $constraint = $this->computeConstraint($query, $matcher, $operator);
609
-            if ($constraint) {
610
-                $collectedConstraints[] = $constraint;
611
-            }
612
-        }
613
-
614
-        if (count($collectedConstraints) > 1) {
615
-            $logical = $matcher->getDefaultLogicalSeparator();
616
-            $constraints = $query->$logical($collectedConstraints);
617
-        } elseif (!empty($collectedConstraints)) {
618
-
619
-            // true means there is one constraint only and should become the result
620
-            $constraints = current($collectedConstraints);
621
-        }
622
-
623
-        // Trigger signal for post processing the computed constraints object.
624
-        $constraints = $this->emitPostProcessConstraintsSignal($query, $constraints);
625
-
626
-        return $constraints;
627
-    }
628
-
629
-    /**
630
-     * Computes the search constraint and returns it.
631
-     *
632
-     * @param Query $query
633
-     * @param Matcher $matcher
634
-     * @return ConstraintInterface|null
635
-     */
636
-    protected function computeSearchTermConstraint(Query $query, Matcher $matcher): ?ConstraintInterface
637
-    {
638
-
639
-        $result = null;
640
-
641
-        // Search term case
642
-        if ($matcher->getSearchTerm()) {
643
-
644
-            $fields = GeneralUtility::trimExplode(',', Tca::table($this->dataType)->getSearchFields(), true);
645
-
646
-            $constraints = [];
647
-            $likeClause = sprintf('%%%s%%', $matcher->getSearchTerm());
648
-            foreach ($fields as $fieldNameAndPath) {
649
-                if ($this->isSuitableForLike($fieldNameAndPath, $matcher->getSearchTerm())) {
650
-
651
-                    $dataType = $this->getFieldPathResolver()->getDataType($fieldNameAndPath, $this->dataType);
652
-                    $fieldName = $this->getFieldPathResolver()->stripFieldPath($fieldNameAndPath, $this->dataType);
653
-
654
-                    if (Tca::table($dataType)->hasField($fieldName) && Tca::table($dataType)->field($fieldName)->hasRelation()) {
655
-                        $foreignTable = Tca::table($dataType)->field($fieldName)->getForeignTable();
656
-                        $fieldNameAndPath = $fieldNameAndPath . '.' . Tca::table($foreignTable)->getLabelField();
657
-                    }
658
-                    $constraints[] = $query->like($fieldNameAndPath, $likeClause);
659
-                }
660
-            }
661
-            $logical = $matcher->getLogicalSeparatorForSearchTerm();
662
-            $result = $query->$logical($constraints);
663
-        }
664
-
665
-        return $result;
666
-    }
667
-
668
-    /**
669
-     * It does not make sense to have a "like" in presence of numerical field, e.g "uid".
670
-     * Tell whether the given value makes sense for a "like" clause.
671
-     *
672
-     * @param string $fieldNameAndPath
673
-     * @param string $value
674
-     * @return bool
675
-     */
676
-    protected function isSuitableForLike($fieldNameAndPath, $value): bool
677
-    {
678
-        $isSuitable = true;
679
-
680
-        // true means it is a string
681
-        if (!MathUtility::canBeInterpretedAsInteger($value)) {
682
-
683
-            $dataType = $this->getFieldPathResolver()->getDataType($fieldNameAndPath, $this->dataType);
684
-            $fieldName = $this->getFieldPathResolver()->stripFieldPath($fieldNameAndPath, $this->dataType);
685
-
686
-            if (Tca::table($dataType)->field($fieldName)->isNumerical()
687
-                && !Tca::table($dataType)->field($fieldName)->hasRelation()
688
-            ) {
689
-                $isSuitable = false;
690
-            }
691
-        }
692
-
693
-        return $isSuitable;
694
-    }
695
-
696
-    /**
697
-     * Computes the constraint for matches and returns it.
698
-     *
699
-     * @param Query $query
700
-     * @param Matcher $matcher
701
-     * @param string $operator
702
-     * @return ConstraintInterface|null
703
-     */
704
-    protected function computeConstraint(Query $query, Matcher $matcher, $operator): ?ConstraintInterface
705
-    {
706
-        $result = null;
707
-
708
-        $operatorName = ucfirst($operator);
709
-        $getCriteria = sprintf('get%s', $operatorName);
710
-        $criteria = $matcher->$getCriteria();
711
-
712
-        if (!empty($criteria)) {
713
-            $constraints = [];
714
-
715
-            foreach ($criteria as $criterion) {
716
-
717
-                $fieldNameAndPath = $criterion['fieldNameAndPath'];
718
-                $operand = $criterion['operand'];
719
-
720
-                // Compute a few variables...
721
-                // $dataType is generally equals to $this->dataType but not always... if fieldName is a path.
722
-                $dataType = $this->getFieldPathResolver()->getDataType($fieldNameAndPath, $this->dataType);
723
-                $fieldName = $this->getFieldPathResolver()->stripFieldPath($fieldNameAndPath, $this->dataType);
724
-                $fieldPath = $this->getFieldPathResolver()->stripFieldName($fieldNameAndPath, $this->dataType);
725
-
726
-                if (Tca::table($dataType)->field($fieldName)->hasRelation()) {
727
-                    if (MathUtility::canBeInterpretedAsInteger($operand)) {
728
-                        $fieldNameAndPath = $fieldName . '.uid';
729
-                    } else {
730
-                        $foreignTableName = Tca::table($dataType)->field($fieldName)->getForeignTable();
731
-                        $foreignTable = Tca::table($foreignTableName);
732
-                        $fieldNameAndPath = $fieldName . '.' . $foreignTable->getLabelField();
733
-                    }
734
-
735
-                    // If different means we should restore the prepended path segment for proper SQL parser.
736
-                    // This is true for a composite field, e.g items.sys_file_metadata for categories.
737
-                    if ($fieldName !== $fieldPath) {
738
-                        $fieldNameAndPath = $fieldPath . '.' . $fieldNameAndPath;
739
-                    }
740
-                }
741
-
742
-                if (strpos($operator, 'not') === 0) {
743
-                    $strippedOperator = strtolower(substr($operator, 3));
744
-                    $constraints[] = $query->logicalNot($query->$strippedOperator($fieldNameAndPath, $criterion['operand']));
745
-                } else {
746
-                    $constraints[] = $query->$operator($fieldNameAndPath, $criterion['operand']);
747
-                }
748
-            }
749
-
750
-            $getLogicalSeparator = sprintf('getLogicalSeparatorFor%s', $operatorName);
751
-            $logical = method_exists($matcher, $getLogicalSeparator)
752
-                ? $matcher->$getLogicalSeparator()
753
-                : $matcher->getDefaultLogicalSeparator();
754
-
755
-            $result = $query->$logical($constraints);
756
-        }
757
-
758
-        return $result;
759
-    }
760
-
761
-    /**
762
-     * @return DataHandler
763
-     */
764
-    protected function getDataHandler(): DataHandler
765
-    {
766
-        if (!$this->dataHandler) {
767
-            $this->dataHandler = GeneralUtility::makeInstance(DataHandler::class);
768
-        }
769
-        return $this->dataHandler;
770
-    }
771
-
772
-    /**
773
-     * Handle the magic call by properly creating a Query object and returning its result.
774
-     *
775
-     * @param string $propertyName
776
-     * @param string $value
777
-     * @param string $flag
778
-     * @return mixed
779
-     */
780
-    protected function processMagicCall($propertyName, $value, $flag = '')
781
-    {
782
-
783
-        $fieldName = Property::name($propertyName)->of($this->dataType)->toFieldName();
784
-
785
-        /** @var $matcher Matcher */
786
-        $matcher = GeneralUtility::makeInstance(Matcher::class, [], $this->getDataType());
787
-
788
-        $table = Tca::table($this->dataType);
789
-        if ($table->field($fieldName)->isGroup()) {
790
-
791
-            $valueParts = explode('.', $value, 2);
792
-            $fieldName = $fieldName . '.' . $valueParts[0];
793
-            $value = $valueParts[1];
794
-        }
795
-
796
-        $matcher->equals($fieldName, $value);
797
-
798
-        if ($flag === 'count') {
799
-            $result = $this->countBy($matcher);
800
-        } else {
801
-            $result = $this->findBy($matcher);
802
-        }
803
-        return $flag === 'one' && !empty($result) ? reset($result) : $result;
804
-    }
805
-
806
-    /**
807
-     * @return DataHandlerFactory|object
808
-     */
809
-    protected function getDataHandlerFactory()
810
-    {
811
-        return GeneralUtility::makeInstance(DataHandlerFactory::class);
812
-    }
813
-
814
-    /**
815
-     * Returns whether the current mode is Backend
816
-     *
817
-     * @return bool
818
-     */
819
-    protected function isBackendMode(): bool
820
-    {
821
-        return TYPO3_MODE === 'BE';
822
-    }
823
-
824
-    /**
825
-     * @return FieldPathResolver|object
826
-     */
827
-    protected function getFieldPathResolver()
828
-    {
829
-        return GeneralUtility::makeInstance(FieldPathResolver::class);
830
-    }
831
-
832
-    /**
833
-     * @return ObjectManager|object
834
-     */
835
-    protected function getObjectManager(): ObjectManager
836
-    {
837
-        return GeneralUtility::makeInstance(ObjectManager::class);
838
-    }
839
-
840
-    /**
841
-     * @return ContentValidator|object
842
-     */
843
-    protected function getContentValidator(): ContentValidator
844
-    {
845
-        return GeneralUtility::makeInstance(ContentValidator::class);
846
-    }
847
-
848
-    /**
849
-     * @return LanguageValidator|object
850
-     */
851
-    protected function getLanguageValidator(): LanguageValidator
852
-    {
853
-        return GeneralUtility::makeInstance(LanguageValidator::class);
854
-    }
855
-
856
-    /**
857
-     * Signal that is called for post-processing the computed constraints object.
858
-     *
859
-     * @param Query $query
860
-     * @param ConstraintInterface|null $constraints
861
-     * @return ConstraintInterface|null $constraints
862
-     */
863
-    protected function emitPostProcessConstraintsSignal(Query $query, $constraints): ?ConstraintInterface
864
-    {
865
-        /** @var ConstraintContainer $constraintContainer */
866
-        $constraintContainer = GeneralUtility::makeInstance(ConstraintContainer::class);
867
-        $result = $this->getSignalSlotDispatcher()->dispatch(
868
-            self::class,
869
-            'postProcessConstraintsObject',
870
-            [
871
-                $query,
872
-                $constraints,
873
-                $constraintContainer
874
-            ]
875
-        );
876
-
877
-        // Backward compatibility.
878
-        $processedConstraints = $result[1];
879
-
880
-        // New way to transmit the constraints.
881
-        if ($constraintContainer->getConstraint()) {
882
-            $processedConstraints = $constraintContainer->getConstraint();
883
-        }
884
-        return $processedConstraints;
885
-    }
886
-
887
-    /**
888
-     * @return Dispatcher
889
-     */
890
-    protected function getSignalSlotDispatcher(): Dispatcher
891
-    {
892
-        return $this->getObjectManager()->get(Dispatcher::class);
893
-    }
41
+	/**
42
+	 * Tell whether it is a raw result (array) or object being returned.
43
+	 *
44
+	 * @var bool
45
+	 */
46
+	protected $rawResult = false;
47
+
48
+	/**
49
+	 * The data type to be returned, e.g fe_users, fe_groups, tt_content, etc...
50
+	 *
51
+	 * @var string
52
+	 */
53
+	protected $dataType;
54
+
55
+	/**
56
+	 * The source field is useful in the context of MM relations to know who is the caller
57
+	 * e.g findByItems which eventually corresponds to a field name.
58
+	 *
59
+	 * @var string
60
+	 */
61
+	protected $sourceFieldName = '';
62
+
63
+	/**
64
+	 * @var array
65
+	 */
66
+	protected $errorMessages = [];
67
+
68
+	/**
69
+	 * @var QuerySettingsInterface
70
+	 */
71
+	protected $defaultQuerySettings;
72
+
73
+	/**
74
+	 * @var DataHandler
75
+	 */
76
+	protected $dataHandler;
77
+
78
+	/**
79
+	 * Constructor
80
+	 *
81
+	 * @param string $dataType
82
+	 */
83
+	public function __construct($dataType)
84
+	{
85
+		$this->dataType = $dataType;
86
+	}
87
+
88
+	/**
89
+	 * Returns all objects of this repository.
90
+	 *
91
+	 * @return Content[]
92
+	 */
93
+	public function findAll()
94
+	{
95
+		$query = $this->createQuery();
96
+		return $query->execute();
97
+	}
98
+
99
+	/**
100
+	 * Returns all "distinct" values for a given property.
101
+	 *
102
+	 * @param string $propertyName
103
+	 * @param Matcher $matcher
104
+	 * @param Order|null $order
105
+	 * @return Content[]
106
+	 */
107
+	public function findDistinctValues($propertyName, Matcher $matcher = null, Order $order = null): array
108
+	{
109
+		$query = $this->createQuery();
110
+		$query->setDistinct($propertyName);
111
+
112
+		// Remove empty values from selection.
113
+		$constraint = $query->logicalNot($query->equals($propertyName, ''));
114
+
115
+		// Add some additional constraints from the Matcher object.
116
+		$matcherConstraint = null;
117
+		if ($matcher !== null) {
118
+			$matcherConstraint = $this->computeConstraints($query, $matcher);
119
+		}
120
+
121
+		// Assemble the final constraints or not.
122
+		if ($matcherConstraint) {
123
+			$query->logicalAnd($matcherConstraint, $constraint);
124
+			$query->matching($query->logicalAnd($matcherConstraint, $constraint));
125
+		} else {
126
+			$query->matching($constraint);
127
+		}
128
+
129
+		if ($order) {
130
+			$query->setOrderings($order->getOrderings());
131
+		}
132
+
133
+		return $query->execute();
134
+	}
135
+
136
+	/**
137
+	 * Returns all "distinct" values for a given property.
138
+	 *
139
+	 * @param string $propertyName
140
+	 * @param Matcher $matcher
141
+	 * @return int
142
+	 */
143
+	public function countDistinctValues($propertyName, Matcher $matcher = null): int
144
+	{
145
+		$query = $this->createQuery();
146
+		$query->setDistinct($propertyName);
147
+
148
+		// Remove empty values from selection.
149
+		$constraint = $query->logicalNot($query->equals($propertyName, ''));
150
+
151
+		// Add some additional constraints from the Matcher object.
152
+		$matcherConstraint = null;
153
+		if (!is_null($matcher)) {
154
+			$matcherConstraint = $this->computeConstraints($query, $matcher);
155
+		}
156
+
157
+		// Assemble the final constraints or not.
158
+		if ($matcherConstraint) {
159
+			$query->logicalAnd($matcherConstraint, $constraint);
160
+			$query->matching($query->logicalAnd($matcherConstraint, $constraint));
161
+		} else {
162
+			$query->matching($constraint);
163
+		}
164
+
165
+		return $query->count();
166
+	}
167
+
168
+	/**
169
+	 * Finds an object matching the given identifier.
170
+	 *
171
+	 * @param int $uid The identifier of the object to find
172
+	 * @return Content|null
173
+	 * @api
174
+	 */
175
+	public function findByUid($uid)
176
+	{
177
+		return $this->findByIdentifier($uid);
178
+	}
179
+
180
+	/**
181
+	 * Finds all Contents given specified matches.
182
+	 *
183
+	 * @param string $propertyName
184
+	 * @param array $values
185
+	 * @return Content[]
186
+	 */
187
+	public function findIn($propertyName, array $values): array
188
+	{
189
+		$query = $this->createQuery();
190
+		$query->matching($query->in($propertyName, $values));
191
+		return $query->execute();
192
+	}
193
+
194
+	/**
195
+	 * Finds all Contents given specified matches.
196
+	 *
197
+	 * @param Matcher $matcher
198
+	 * @param Order $order The order
199
+	 * @param int $limit
200
+	 * @param int $offset
201
+	 * @return Content[]
202
+	 */
203
+	public function findBy(Matcher $matcher, Order $order = null, $limit = null, $offset = null): array
204
+	{
205
+
206
+		$query = $this->createQuery();
207
+
208
+		$limit = (int)$limit; // make sure to cast
209
+		if ($limit > 0) {
210
+			$query->setLimit($limit);
211
+		}
212
+
213
+		if ($order) {
214
+			$query->setOrderings($order->getOrderings());
215
+
216
+			// Loops around the orderings adding if necessary a dummy condition
217
+			// to make sure the relations can be resolved when transforming the query to plain SQL.
218
+			foreach ($order->getOrderings() as $ordering => $direction) {
219
+				if ($this->hasForeignRelationIn($ordering)) {
220
+					$relationalField = $this->getForeignRelationFrom($ordering);
221
+					$matcher->like($relationalField . '.uid', '');
222
+				}
223
+			}
224
+		}
225
+
226
+		if ($offset) {
227
+			$query->setOffset($offset);
228
+		}
229
+
230
+		$constraints = $this->computeConstraints($query, $matcher);
231
+
232
+		if ($constraints) {
233
+			$query->matching($constraints);
234
+		}
235
+
236
+		return $query->execute();
237
+	}
238
+
239
+	/**
240
+	 * Find one Content object given specified matches.
241
+	 *
242
+	 * @param Matcher $matcher
243
+	 * @return Content
244
+	 */
245
+	public function findOneBy(Matcher $matcher): Content
246
+	{
247
+
248
+		$query = $this->createQuery();
249
+
250
+		$constraints = $this->computeConstraints($query, $matcher);
251
+
252
+		if ($constraints) {
253
+			$query->matching($constraints);
254
+		}
255
+
256
+		$query->setLimit(1); // only take one!
257
+
258
+		$resultSet = $query->execute();
259
+		if ($resultSet) {
260
+			$resultSet = current($resultSet);
261
+		}
262
+		return $resultSet;
263
+	}
264
+
265
+	/**
266
+	 * Count all Contents given specified matches.
267
+	 *
268
+	 * @param Matcher $matcher
269
+	 * @return int
270
+	 */
271
+	public function countBy(Matcher $matcher): int
272
+	{
273
+
274
+		$query = $this->createQuery();
275
+
276
+		$constraints = $this->computeConstraints($query, $matcher);
277
+
278
+		if ($constraints) {
279
+			$query->matching($constraints);
280
+		}
281
+
282
+		return $query->count();
283
+	}
284
+
285
+	/**
286
+	 * Update a content with new information.
287
+	 *
288
+	 * @param Content $content
289
+	 * @param $language
290
+	 * @return bool
291
+	 */
292
+	public function localize($content, $language): bool
293
+	{
294
+
295
+		// Security check
296
+		$this->getContentValidator()->validate($content);
297
+		$this->getLanguageValidator()->validate($language);
298
+
299
+		$dataType = $content->getDataType();
300
+		$handler = $this->getDataHandlerFactory()->action(ProcessAction::LOCALIZE)->forType($dataType)->getDataHandler();
301
+
302
+		$handlerResult = $handler->processLocalize($content, $language);
303
+		$this->errorMessages = $handler->getErrorMessages();
304
+		return $handlerResult;
305
+	}
306
+
307
+	/**
308
+	 * Update a content with new information.
309
+	 *
310
+	 * @param Content $content
311
+	 * @return bool
312
+	 */
313
+	public function update($content)
314
+	{
315
+
316
+		// Security check.
317
+		$this->getContentValidator()->validate($content);
318
+
319
+		$dataType = $content->getDataType();
320
+		$handler = $this->getDataHandlerFactory()->action(ProcessAction::UPDATE)->forType($dataType)->getDataHandler();
321
+
322
+		$handlerResult = $handler->processUpdate($content);
323
+		$this->errorMessages = $handler->getErrorMessages();
324
+		return $handlerResult;
325
+	}
326
+
327
+	/**
328
+	 * Removes an object from this repository.
329
+	 *
330
+	 * @param Content $content
331
+	 * @return boolean
332
+	 */
333
+	public function remove($content)
334
+	{
335
+		$dataType = $content->getDataType();
336
+		$handler = $this->getDataHandlerFactory()->action(ProcessAction::REMOVE)->forType($dataType)->getDataHandler();
337
+
338
+		$handlerResult = $handler->processRemove($content);
339
+		$this->errorMessages = $handler->getErrorMessages();
340
+		return $handlerResult;
341
+	}
342
+
343
+	/**
344
+	 * Move a content within this repository.
345
+	 * The $target corresponds to the pid to move the records to.
346
+	 * It can also be a negative value in case of sorting. The negative value would be the uid of its predecessor.
347
+	 *
348
+	 * @param Content $content
349
+	 * @param string $target
350
+	 * @return bool
351
+	 */
352
+	public function move($content, $target): bool
353
+	{
354
+
355
+		// Security check.
356
+		$this->getContentValidator()->validate($content);
357
+
358
+		$dataType = $content->getDataType();
359
+		$handler = $this->getDataHandlerFactory()->action(ProcessAction::MOVE)->forType($dataType)->getDataHandler();
360
+
361
+		$handlerResult = $handler->processMove($content, $target);
362
+		$this->errorMessages = $handler->getErrorMessages();
363
+		return $handlerResult;
364
+	}
365
+
366
+	/**
367
+	 * Copy a content within this repository.
368
+	 *
369
+	 * @param Content $content
370
+	 * @return bool
371
+	 */
372
+	public function copy($content, $target): bool
373
+	{
374
+
375
+		// Security check.
376
+		$this->getContentValidator()->validate($content);
377
+
378
+		$dataType = $content->getDataType();
379
+		$handler = $this->getDataHandlerFactory()->action(ProcessAction::COPY)->forType($dataType)->getDataHandler();
380
+
381
+		$handlerResult = $handler->processCopy($content, $target);
382
+		$this->errorMessages = $handler->getErrorMessages();
383
+		return $handlerResult;
384
+	}
385
+
386
+	/**
387
+	 * Adds an object to this repository.
388
+	 *
389
+	 * @param object $object The object to add
390
+	 * @return void
391
+	 * @api
392
+	 */
393
+	public function add($object)
394
+	{
395
+		throw new \BadMethodCallException('Repository does not support the add() method.', 1375805599);
396
+	}
397
+
398
+	/**
399
+	 * Returns the total number objects of this repository.
400
+	 *
401
+	 * @return integer The object count
402
+	 * @api
403
+	 */
404
+	public function countAll()
405
+	{
406
+		$query = $this->createQuery();
407
+		return $query->count();
408
+	}
409
+
410
+	/**
411
+	 * Removes all objects of this repository as if remove() was called for
412
+	 * all of them.
413
+	 *
414
+	 * @return void
415
+	 * @api
416
+	 */
417
+	public function removeAll()
418
+	{
419
+		// TODO: Implement removeAll() method.
420
+	}
421
+
422
+	/**
423
+	 * Finds an object matching the given identifier.
424
+	 *
425
+	 * @param mixed $identifier The identifier of the object to find
426
+	 * @return Content|null
427
+	 * @api
428
+	 */
429
+	public function findByIdentifier($identifier)
430
+	{
431
+		$query = $this->createQuery();
432
+
433
+		$result = $query->matching(
434
+			$query->equals('uid', $identifier)
435
+		)
436
+			->execute();
437
+
438
+		if (is_array($result)) {
439
+			$result = current($result);
440
+		}
441
+
442
+		return $result;
443
+	}
444
+
445
+	/**
446
+	 * Dispatches magic methods (findBy[Property]())
447
+	 *
448
+	 * @param string $methodName The name of the magic method
449
+	 * @param string $arguments The arguments of the magic method
450
+	 * @return mixed
451
+	 * @api
452
+	 */
453
+	public function __call($methodName, $arguments)
454
+	{
455
+		if (substr($methodName, 0, 6) === 'findBy' && strlen($methodName) > 7) {
456
+			$propertyName = strtolower(substr(substr($methodName, 6), 0, 1)) . substr(substr($methodName, 6), 1);
457
+			$result = $this->processMagicCall($propertyName, $arguments[0]);
458
+		} elseif (substr($methodName, 0, 9) === 'findOneBy' && strlen($methodName) > 10) {
459
+			$propertyName = strtolower(substr(substr($methodName, 9), 0, 1)) . substr(substr($methodName, 9), 1);
460
+			$result = $this->processMagicCall($propertyName, $arguments[0], 'one');
461
+		} elseif (substr($methodName, 0, 7) === 'countBy' && strlen($methodName) > 8) {
462
+			$propertyName = strtolower(substr(substr($methodName, 7), 0, 1)) . substr(substr($methodName, 7), 1);
463
+			$result = $this->processMagicCall($propertyName, $arguments[0], 'count');
464
+		} else {
465
+			throw new UnsupportedMethodException('The method "' . $methodName . '" is not supported by the repository.', 1360838010);
466
+		}
467
+		return $result;
468
+	}
469
+
470
+	/**
471
+	 * Returns a query for objects of this repository
472
+	 *
473
+	 * @return Query
474
+	 * @api
475
+	 */
476
+	public function createQuery()
477
+	{
478
+		/** @var Query $query */
479
+		$query = $this->getObjectManager()->get(Query::class, $this->dataType);
480
+		$query->setSourceFieldName($this->sourceFieldName);
481
+
482
+		if ($this->defaultQuerySettings) {
483
+			$query->setQuerySettings($this->defaultQuerySettings);
484
+		} else {
485
+
486
+			// Initialize and pass the query settings at this level.
487
+			/** @var QuerySettings $querySettings */
488
+			$querySettings = $this->getObjectManager()->get(QuerySettings::class);
489
+
490
+			// Default choice for the BE.
491
+			if ($this->isBackendMode()) {
492
+				$querySettings->setIgnoreEnableFields(true);
493
+			}
494
+
495
+			$query->setQuerySettings($querySettings);
496
+		}
497
+
498
+		return $query;
499
+	}
500
+
501
+	/**
502
+	 * Sets the property names to order the result by per default.
503
+	 * Expected like this:
504
+	 * array(
505
+	 * 'foo' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_ASCENDING,
506
+	 * 'bar' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_DESCENDING
507
+	 * )
508
+	 *
509
+	 * @param array $defaultOrderings The property names to order by
510
+	 * @return void
511
+	 * @api
512
+	 */
513
+	public function setDefaultOrderings(array $defaultOrderings)
514
+	{
515
+		throw new \BadMethodCallException('Repository does not support the setDefaultOrderings() method.', 1375805598);
516
+	}
517
+
518
+	/**
519
+	 * Sets the default query settings to be used in this repository
520
+	 *
521
+	 * @param QuerySettingsInterface $defaultQuerySettings The query settings to be used by default
522
+	 * @return void
523
+	 * @api
524
+	 */
525
+	public function setDefaultQuerySettings(QuerySettingsInterface $defaultQuerySettings)
526
+	{
527
+		$this->defaultQuerySettings = $defaultQuerySettings;
528
+	}
529
+
530
+	/**
531
+	 * @return void
532
+	 */
533
+	public function resetDefaultQuerySettings(): void
534
+	{
535
+		$this->defaultQuerySettings = null;
536
+	}
537
+
538
+
539
+	/**
540
+	 * @return array
541
+	 */
542
+	public function getErrorMessages(): array
543
+	{
544
+		return $this->errorMessages;
545
+	}
546
+
547
+	/**
548
+	 * @param string $sourceFieldName
549
+	 * @return $this
550
+	 */
551
+	public function setSourceFieldName($sourceFieldName): self
552
+	{
553
+		$this->sourceFieldName = $sourceFieldName;
554
+		return $this;
555
+	}
556
+
557
+	/**
558
+	 * @return string
559
+	 */
560
+	public function getDataType(): string
561
+	{
562
+		return $this->dataType;
563
+	}
564
+
565
+	/**
566
+	 * Tell whether the order has a foreign table in its expression, e.g. "metadata.title".
567
+	 *
568
+	 * @param string $ordering
569
+	 * @return bool
570
+	 */
571
+	protected function hasForeignRelationIn($ordering): bool
572
+	{
573
+		return strpos($ordering, '.') !== false;
574
+	}
575
+
576
+	/**
577
+	 * Extract the foreign relation of the ordering "metadata.title" -> "metadata"
578
+	 *
579
+	 * @param string $ordering
580
+	 * @return string
581
+	 */
582
+	protected function getForeignRelationFrom($ordering): string
583
+	{
584
+		$parts = explode('.', $ordering);
585
+		return $parts[0];
586
+	}
587
+
588
+	/**
589
+	 * Get the constraints
590
+	 *
591
+	 * @param Query $query
592
+	 * @param Matcher $matcher
593
+	 * @return ConstraintInterface|null
594
+	 */
595
+	protected function computeConstraints(Query $query, Matcher $matcher): ?ConstraintInterface
596
+	{
597
+		$constraints = null;
598
+
599
+		$collectedConstraints = [];
600
+
601
+		// Search term
602
+		$constraint = $this->computeSearchTermConstraint($query, $matcher);
603
+		if ($constraint) {
604
+			$collectedConstraints[] = $constraint;
605
+		}
606
+
607
+		foreach ($matcher->getSupportedOperators() as $operator) {
608
+			$constraint = $this->computeConstraint($query, $matcher, $operator);
609
+			if ($constraint) {
610
+				$collectedConstraints[] = $constraint;
611
+			}
612
+		}
613
+
614
+		if (count($collectedConstraints) > 1) {
615
+			$logical = $matcher->getDefaultLogicalSeparator();
616
+			$constraints = $query->$logical($collectedConstraints);
617
+		} elseif (!empty($collectedConstraints)) {
618
+
619
+			// true means there is one constraint only and should become the result
620
+			$constraints = current($collectedConstraints);
621
+		}
622
+
623
+		// Trigger signal for post processing the computed constraints object.
624
+		$constraints = $this->emitPostProcessConstraintsSignal($query, $constraints);
625
+
626
+		return $constraints;
627
+	}
628
+
629
+	/**
630
+	 * Computes the search constraint and returns it.
631
+	 *
632
+	 * @param Query $query
633
+	 * @param Matcher $matcher
634
+	 * @return ConstraintInterface|null
635
+	 */
636
+	protected function computeSearchTermConstraint(Query $query, Matcher $matcher): ?ConstraintInterface
637
+	{
638
+
639
+		$result = null;
640
+
641
+		// Search term case
642
+		if ($matcher->getSearchTerm()) {
643
+
644
+			$fields = GeneralUtility::trimExplode(',', Tca::table($this->dataType)->getSearchFields(), true);
645
+
646
+			$constraints = [];
647
+			$likeClause = sprintf('%%%s%%', $matcher->getSearchTerm());
648
+			foreach ($fields as $fieldNameAndPath) {
649
+				if ($this->isSuitableForLike($fieldNameAndPath, $matcher->getSearchTerm())) {
650
+
651
+					$dataType = $this->getFieldPathResolver()->getDataType($fieldNameAndPath, $this->dataType);
652
+					$fieldName = $this->getFieldPathResolver()->stripFieldPath($fieldNameAndPath, $this->dataType);
653
+
654
+					if (Tca::table($dataType)->hasField($fieldName) && Tca::table($dataType)->field($fieldName)->hasRelation()) {
655
+						$foreignTable = Tca::table($dataType)->field($fieldName)->getForeignTable();
656
+						$fieldNameAndPath = $fieldNameAndPath . '.' . Tca::table($foreignTable)->getLabelField();
657
+					}
658
+					$constraints[] = $query->like($fieldNameAndPath, $likeClause);
659
+				}
660
+			}
661
+			$logical = $matcher->getLogicalSeparatorForSearchTerm();
662
+			$result = $query->$logical($constraints);
663
+		}
664
+
665
+		return $result;
666
+	}
667
+
668
+	/**
669
+	 * It does not make sense to have a "like" in presence of numerical field, e.g "uid".
670
+	 * Tell whether the given value makes sense for a "like" clause.
671
+	 *
672
+	 * @param string $fieldNameAndPath
673
+	 * @param string $value
674
+	 * @return bool
675
+	 */
676
+	protected function isSuitableForLike($fieldNameAndPath, $value): bool
677
+	{
678
+		$isSuitable = true;
679
+
680
+		// true means it is a string
681
+		if (!MathUtility::canBeInterpretedAsInteger($value)) {
682
+
683
+			$dataType = $this->getFieldPathResolver()->getDataType($fieldNameAndPath, $this->dataType);
684
+			$fieldName = $this->getFieldPathResolver()->stripFieldPath($fieldNameAndPath, $this->dataType);
685
+
686
+			if (Tca::table($dataType)->field($fieldName)->isNumerical()
687
+				&& !Tca::table($dataType)->field($fieldName)->hasRelation()
688
+			) {
689
+				$isSuitable = false;
690
+			}
691
+		}
692
+
693
+		return $isSuitable;
694
+	}
695
+
696
+	/**
697
+	 * Computes the constraint for matches and returns it.
698
+	 *
699
+	 * @param Query $query
700
+	 * @param Matcher $matcher
701
+	 * @param string $operator
702
+	 * @return ConstraintInterface|null
703
+	 */
704
+	protected function computeConstraint(Query $query, Matcher $matcher, $operator): ?ConstraintInterface
705
+	{
706
+		$result = null;
707
+
708
+		$operatorName = ucfirst($operator);
709
+		$getCriteria = sprintf('get%s', $operatorName);
710
+		$criteria = $matcher->$getCriteria();
711
+
712
+		if (!empty($criteria)) {
713
+			$constraints = [];
714
+
715
+			foreach ($criteria as $criterion) {
716
+
717
+				$fieldNameAndPath = $criterion['fieldNameAndPath'];
718
+				$operand = $criterion['operand'];
719
+
720
+				// Compute a few variables...
721
+				// $dataType is generally equals to $this->dataType but not always... if fieldName is a path.
722
+				$dataType = $this->getFieldPathResolver()->getDataType($fieldNameAndPath, $this->dataType);
723
+				$fieldName = $this->getFieldPathResolver()->stripFieldPath($fieldNameAndPath, $this->dataType);
724
+				$fieldPath = $this->getFieldPathResolver()->stripFieldName($fieldNameAndPath, $this->dataType);
725
+
726
+				if (Tca::table($dataType)->field($fieldName)->hasRelation()) {
727
+					if (MathUtility::canBeInterpretedAsInteger($operand)) {
728
+						$fieldNameAndPath = $fieldName . '.uid';
729
+					} else {
730
+						$foreignTableName = Tca::table($dataType)->field($fieldName)->getForeignTable();
731
+						$foreignTable = Tca::table($foreignTableName);
732
+						$fieldNameAndPath = $fieldName . '.' . $foreignTable->getLabelField();
733
+					}
734
+
735
+					// If different means we should restore the prepended path segment for proper SQL parser.
736
+					// This is true for a composite field, e.g items.sys_file_metadata for categories.
737
+					if ($fieldName !== $fieldPath) {
738
+						$fieldNameAndPath = $fieldPath . '.' . $fieldNameAndPath;
739
+					}
740
+				}
741
+
742
+				if (strpos($operator, 'not') === 0) {
743
+					$strippedOperator = strtolower(substr($operator, 3));
744
+					$constraints[] = $query->logicalNot($query->$strippedOperator($fieldNameAndPath, $criterion['operand']));
745
+				} else {
746
+					$constraints[] = $query->$operator($fieldNameAndPath, $criterion['operand']);
747
+				}
748
+			}
749
+
750
+			$getLogicalSeparator = sprintf('getLogicalSeparatorFor%s', $operatorName);
751
+			$logical = method_exists($matcher, $getLogicalSeparator)
752
+				? $matcher->$getLogicalSeparator()
753
+				: $matcher->getDefaultLogicalSeparator();
754
+
755
+			$result = $query->$logical($constraints);
756
+		}
757
+
758
+		return $result;
759
+	}
760
+
761
+	/**
762
+	 * @return DataHandler
763
+	 */
764
+	protected function getDataHandler(): DataHandler
765
+	{
766
+		if (!$this->dataHandler) {
767
+			$this->dataHandler = GeneralUtility::makeInstance(DataHandler::class);
768
+		}
769
+		return $this->dataHandler;
770
+	}
771
+
772
+	/**
773
+	 * Handle the magic call by properly creating a Query object and returning its result.
774
+	 *
775
+	 * @param string $propertyName
776
+	 * @param string $value
777
+	 * @param string $flag
778
+	 * @return mixed
779
+	 */
780
+	protected function processMagicCall($propertyName, $value, $flag = '')
781
+	{
782
+
783
+		$fieldName = Property::name($propertyName)->of($this->dataType)->toFieldName();
784
+
785
+		/** @var $matcher Matcher */
786
+		$matcher = GeneralUtility::makeInstance(Matcher::class, [], $this->getDataType());
787
+
788
+		$table = Tca::table($this->dataType);
789
+		if ($table->field($fieldName)->isGroup()) {
790
+
791
+			$valueParts = explode('.', $value, 2);
792
+			$fieldName = $fieldName . '.' . $valueParts[0];
793
+			$value = $valueParts[1];
794
+		}
795
+
796
+		$matcher->equals($fieldName, $value);
797
+
798
+		if ($flag === 'count') {
799
+			$result = $this->countBy($matcher);
800
+		} else {
801
+			$result = $this->findBy($matcher);
802
+		}
803
+		return $flag === 'one' && !empty($result) ? reset($result) : $result;
804
+	}
805
+
806
+	/**
807
+	 * @return DataHandlerFactory|object
808
+	 */
809
+	protected function getDataHandlerFactory()
810
+	{
811
+		return GeneralUtility::makeInstance(DataHandlerFactory::class);
812
+	}
813
+
814
+	/**
815
+	 * Returns whether the current mode is Backend
816
+	 *
817
+	 * @return bool
818
+	 */
819
+	protected function isBackendMode(): bool
820
+	{
821
+		return TYPO3_MODE === 'BE';
822
+	}
823
+
824
+	/**
825
+	 * @return FieldPathResolver|object
826
+	 */
827
+	protected function getFieldPathResolver()
828
+	{
829
+		return GeneralUtility::makeInstance(FieldPathResolver::class);
830
+	}
831
+
832
+	/**
833
+	 * @return ObjectManager|object
834
+	 */
835
+	protected function getObjectManager(): ObjectManager
836
+	{
837
+		return GeneralUtility::makeInstance(ObjectManager::class);
838
+	}
839
+
840
+	/**
841
+	 * @return ContentValidator|object
842
+	 */
843
+	protected function getContentValidator(): ContentValidator
844
+	{
845
+		return GeneralUtility::makeInstance(ContentValidator::class);
846
+	}
847
+
848
+	/**
849
+	 * @return LanguageValidator|object
850
+	 */
851
+	protected function getLanguageValidator(): LanguageValidator
852
+	{
853
+		return GeneralUtility::makeInstance(LanguageValidator::class);
854
+	}
855
+
856
+	/**
857
+	 * Signal that is called for post-processing the computed constraints object.
858
+	 *
859
+	 * @param Query $query
860
+	 * @param ConstraintInterface|null $constraints
861
+	 * @return ConstraintInterface|null $constraints
862
+	 */
863
+	protected function emitPostProcessConstraintsSignal(Query $query, $constraints): ?ConstraintInterface
864
+	{
865
+		/** @var ConstraintContainer $constraintContainer */
866
+		$constraintContainer = GeneralUtility::makeInstance(ConstraintContainer::class);
867
+		$result = $this->getSignalSlotDispatcher()->dispatch(
868
+			self::class,
869
+			'postProcessConstraintsObject',
870
+			[
871
+				$query,
872
+				$constraints,
873
+				$constraintContainer
874
+			]
875
+		);
876
+
877
+		// Backward compatibility.
878
+		$processedConstraints = $result[1];
879
+
880
+		// New way to transmit the constraints.
881
+		if ($constraintContainer->getConstraint()) {
882
+			$processedConstraints = $constraintContainer->getConstraint();
883
+		}
884
+		return $processedConstraints;
885
+	}
886
+
887
+	/**
888
+	 * @return Dispatcher
889
+	 */
890
+	protected function getSignalSlotDispatcher(): Dispatcher
891
+	{
892
+		return $this->getObjectManager()->get(Dispatcher::class);
893
+	}
894 894
 
895 895
 }
Please login to merge, or discard this patch.
Classes/Persistence/MatcherObjectFactory.php 1 patch
Indentation   +271 added lines, -271 removed lines patch added patch discarded remove patch
@@ -25,275 +25,275 @@
 block discarded – undo
25 25
 class MatcherObjectFactory implements SingletonInterface
26 26
 {
27 27
 
28
-    /**
29
-     * Gets a singleton instance of this class.
30
-     *
31
-     * @return $this
32
-     */
33
-    static public function getInstance(): self
34
-    {
35
-        return GeneralUtility::makeInstance(self::class);
36
-    }
37
-
38
-    /**
39
-     * Returns a matcher object.
40
-     *
41
-     * @param array $matches
42
-     * @param string $dataType
43
-     * @return Matcher
44
-     */
45
-    public function getMatcher(array $matches = [], $dataType = ''): Matcher
46
-    {
47
-        if ($dataType === '') {
48
-            $dataType = $this->getModuleLoader()->getDataType();
49
-        }
50
-
51
-        /** @var $matcher Matcher */
52
-        $matcher = GeneralUtility::makeInstance(Matcher::class, [], $dataType);
53
-
54
-        $matcher = $this->applyCriteriaFromDataTables($matcher);
55
-        $matcher = $this->applyCriteriaFromMatchesArgument($matcher, $matches);
56
-
57
-        if ($this->isBackendMode()) {
58
-            $matcher = $this->applyCriteriaFromUrl($matcher);
59
-            $matcher = $this->applyCriteriaFromTSConfig($matcher);
60
-        }
61
-
62
-        // Trigger signal for post processing Matcher Object.
63
-        $this->emitPostProcessMatcherObjectSignal($matcher);
64
-
65
-        return $matcher;
66
-    }
67
-
68
-    /**
69
-     * Get a possible id from the URL and apply as filter criteria.
70
-     * Except if the main module belongs to the File. The id would be a combined identifier
71
-     * including the storage and a mount point.
72
-     *
73
-     * @param Matcher $matcher
74
-     * @return Matcher $matcher
75
-     */
76
-    protected function applyCriteriaFromUrl(Matcher $matcher): Matcher
77
-    {
78
-        if (GeneralUtility::_GP('id')
79
-            && !$this->getModuleLoader()->isPidIgnored()
80
-            && $this->getModuleLoader()->getMainModule() !== ModuleName::FILE) {
81
-            $matcher->equals('pid', GeneralUtility::_GP('id'));
82
-        }
83
-
84
-        return $matcher;
85
-    }
86
-
87
-    /**
88
-     * @param Matcher $matcher
89
-     * @return Matcher $matcher
90
-     */
91
-    protected function applyCriteriaFromTSConfig(Matcher $matcher): Matcher
92
-    {
93
-        $dataType = $matcher->getDataType();
94
-        $tsConfigPath = sprintf('tx_vidi.dataType.%s.constraints', $dataType);
95
-        $tsConfig = $this->getBackendUser()->getTSConfig($tsConfigPath);
96
-
97
-        if (is_array($tsConfig['properties']) && !empty($tsConfig['properties'])) {
98
-
99
-            foreach ($tsConfig['properties'] as $constraint) {
100
-
101
-                if (preg_match('/(.+) (>=|>|<|<=|=|like) (.+)/is', $constraint, $matches) && count($matches) === 4) {
102
-
103
-                    $operator = $matcher->getSupportedOperators()[strtolower(trim($matches[2]))];
104
-                    $operand = trim($matches[1]);
105
-                    $value = trim($matches[3]);
106
-
107
-                    $matcher->$operator($operand, $value);
108
-                } elseif (preg_match('/(.+) (in) (.+)/is', $constraint, $matches) && count($matches) === 4) {
109
-
110
-                    $operator = $matcher->getSupportedOperators()[trim($matches[2])];
111
-                    $operand = trim($matches[1]);
112
-                    $value = trim($matches[3]);
113
-                    $matcher->$operator($operand, GeneralUtility::trimExplode(',', $value, true));
114
-                }
115
-            }
116
-        }
117
-
118
-        return $matcher;
119
-    }
120
-
121
-    /**
122
-     * @param Matcher $matcher
123
-     * @param array $matches
124
-     * @return Matcher $matcher
125
-     */
126
-    protected function applyCriteriaFromMatchesArgument(Matcher $matcher, $matches): Matcher
127
-    {
128
-        foreach ($matches as $fieldNameAndPath => $value) {
129
-            // CSV values should be considered as "in" operator in the query, otherwise "equals".
130
-            $explodedValues = GeneralUtility::trimExplode(',', $value, true);
131
-            if (count($explodedValues) > 1) {
132
-                $matcher->in($fieldNameAndPath, $explodedValues);
133
-            } else {
134
-                $matcher->equals($fieldNameAndPath, $explodedValues[0]);
135
-            }
136
-        }
137
-
138
-        return $matcher;
139
-    }
140
-
141
-    /**
142
-     * Apply criteria specific to jQuery plugin DataTable.
143
-     *
144
-     * @param Matcher $matcher
145
-     * @return Matcher $matcher
146
-     */
147
-    protected function applyCriteriaFromDataTables(Matcher $matcher): Matcher
148
-    {
149
-
150
-        // Special case for Grid in the BE using jQuery DataTables plugin.
151
-        // Retrieve a possible search term from GP.
152
-        $query = GeneralUtility::_GP('search');
153
-        if (is_array($query)) {
154
-            if (!empty($query['value'])) {
155
-                $query = $query['value'];
156
-            } else {
157
-                $query = '';
158
-            }
159
-        }
160
-
161
-        if (strlen($query) > 0) {
162
-
163
-            // Parse the json query coming from the Visual Search.
164
-            $query = rawurldecode($query);
165
-            $queryParts = json_decode($query, true);
166
-
167
-            if (is_array($queryParts)) {
168
-                $matcher = $this->parseQuery($queryParts, $matcher);
169
-            } else {
170
-                $matcher->setSearchTerm($query);
171
-            }
172
-        }
173
-        return $matcher;
174
-    }
175
-
176
-    /**
177
-     * @param array $queryParts
178
-     * @param Matcher $matcher
179
-     * @return Matcher $matcher
180
-     */
181
-    protected function parseQuery(array $queryParts, Matcher $matcher): Matcher
182
-    {
183
-        $dataType = $matcher->getDataType();
184
-        foreach ($queryParts as $term) {
185
-            $fieldNameAndPath = key($term);
186
-
187
-            $resolvedDataType = $this->getFieldPathResolver()->getDataType($fieldNameAndPath, $dataType);
188
-            $fieldName = $this->getFieldPathResolver()->stripFieldPath($fieldNameAndPath, $dataType);
189
-
190
-            // Retrieve the value.
191
-            $value = current($term);
192
-
193
-            if (Tca::grid($resolvedDataType)->hasFacet($fieldName) && Tca::grid($resolvedDataType)->facet($fieldName)->canModifyMatcher()) {
194
-                $matcher = Tca::grid($resolvedDataType)->facet($fieldName)->modifyMatcher($matcher, $value);
195
-            } elseif (Tca::table($resolvedDataType)->hasField($fieldName)) {
196
-                // Check whether the field exists and set it as "equal" or "like".
197
-                if ($this->isOperatorEquals($fieldNameAndPath, $dataType, $value)) {
198
-                    $matcher->equals($fieldNameAndPath, $value);
199
-                } else {
200
-                    $matcher->like($fieldNameAndPath, $value);
201
-                }
202
-            } elseif ($fieldNameAndPath === 'text') {
203
-                // Special case if field is "text" which is a pseudo field in this case.
204
-                // Set the search term which means Vidi will
205
-                // search in various fields with operator "like". The fields come from key "searchFields" in the TCA.
206
-                $matcher->setSearchTerm($value);
207
-            }
208
-        }
209
-        return $matcher;
210
-    }
211
-
212
-    /**
213
-     * Tell whether the operator should be equals instead of like for a search, e.g. if the value is numerical.
214
-     *
215
-     * @param string $fieldName
216
-     * @param string $dataType
217
-     * @param string $value
218
-     * @return bool
219
-     */
220
-    protected function isOperatorEquals($fieldName, $dataType, $value): bool
221
-    {
222
-        return (Tca::table($dataType)->field($fieldName)->hasRelation() && MathUtility::canBeInterpretedAsInteger($value))
223
-            || Tca::table($dataType)->field($fieldName)->isNumerical();
224
-    }
225
-
226
-    /**
227
-     * Signal that is called for post-processing a matcher object.
228
-     *
229
-     * @param Matcher $matcher
230
-     */
231
-    protected function emitPostProcessMatcherObjectSignal(Matcher $matcher): void
232
-    {
233
-
234
-        if (strlen($matcher->getDataType()) <= 0) {
235
-
236
-            /** @var ModuleLoader $moduleLoader */
237
-            $moduleLoader = $this->getObjectManager()->get(ModuleLoader::class);
238
-            $matcher->setDataType($moduleLoader->getDataType());
239
-        }
240
-
241
-        $this->getSignalSlotDispatcher()->dispatch('Fab\Vidi\Controller\Backend\ContentController', 'postProcessMatcherObject', array($matcher, $matcher->getDataType()));
242
-    }
243
-
244
-    /**
245
-     * Get the SignalSlot dispatcher
246
-     *
247
-     * @return Dispatcher|object
248
-     */
249
-    protected function getSignalSlotDispatcher()
250
-    {
251
-        return $this->getObjectManager()->get(Dispatcher::class);
252
-    }
253
-
254
-    /**
255
-     * @return ObjectManager|object
256
-     */
257
-    protected function getObjectManager()
258
-    {
259
-        return GeneralUtility::makeInstance(ObjectManager::class);
260
-    }
261
-
262
-    /**
263
-     * Get the Vidi Module Loader.
264
-     *
265
-     * @return ModuleLoader|object
266
-     */
267
-    protected function getModuleLoader()
268
-    {
269
-        return GeneralUtility::makeInstance(ModuleLoader::class);
270
-    }
271
-
272
-    /**
273
-     * @return FieldPathResolver|object
274
-     */
275
-    protected function getFieldPathResolver()
276
-    {
277
-        return GeneralUtility::makeInstance(FieldPathResolver::class);
278
-    }
279
-
280
-    /**
281
-     * Returns an instance of the current Backend User.
282
-     *
283
-     * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
284
-     */
285
-    protected function getBackendUser(): \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
286
-    {
287
-        return $GLOBALS['BE_USER'];
288
-    }
289
-
290
-    /**
291
-     * Returns whether the current mode is Backend
292
-     *
293
-     * @return bool
294
-     */
295
-    protected function isBackendMode(): bool
296
-    {
297
-        return TYPO3_MODE === 'BE';
298
-    }
28
+	/**
29
+	 * Gets a singleton instance of this class.
30
+	 *
31
+	 * @return $this
32
+	 */
33
+	static public function getInstance(): self
34
+	{
35
+		return GeneralUtility::makeInstance(self::class);
36
+	}
37
+
38
+	/**
39
+	 * Returns a matcher object.
40
+	 *
41
+	 * @param array $matches
42
+	 * @param string $dataType
43
+	 * @return Matcher
44
+	 */
45
+	public function getMatcher(array $matches = [], $dataType = ''): Matcher
46
+	{
47
+		if ($dataType === '') {
48
+			$dataType = $this->getModuleLoader()->getDataType();
49
+		}
50
+
51
+		/** @var $matcher Matcher */
52
+		$matcher = GeneralUtility::makeInstance(Matcher::class, [], $dataType);
53
+
54
+		$matcher = $this->applyCriteriaFromDataTables($matcher);
55
+		$matcher = $this->applyCriteriaFromMatchesArgument($matcher, $matches);
56
+
57
+		if ($this->isBackendMode()) {
58
+			$matcher = $this->applyCriteriaFromUrl($matcher);
59
+			$matcher = $this->applyCriteriaFromTSConfig($matcher);
60
+		}
61
+
62
+		// Trigger signal for post processing Matcher Object.
63
+		$this->emitPostProcessMatcherObjectSignal($matcher);
64
+
65
+		return $matcher;
66
+	}
67
+
68
+	/**
69
+	 * Get a possible id from the URL and apply as filter criteria.
70
+	 * Except if the main module belongs to the File. The id would be a combined identifier
71
+	 * including the storage and a mount point.
72
+	 *
73
+	 * @param Matcher $matcher
74
+	 * @return Matcher $matcher
75
+	 */
76
+	protected function applyCriteriaFromUrl(Matcher $matcher): Matcher
77
+	{
78
+		if (GeneralUtility::_GP('id')
79
+			&& !$this->getModuleLoader()->isPidIgnored()
80
+			&& $this->getModuleLoader()->getMainModule() !== ModuleName::FILE) {
81
+			$matcher->equals('pid', GeneralUtility::_GP('id'));
82
+		}
83
+
84
+		return $matcher;
85
+	}
86
+
87
+	/**
88
+	 * @param Matcher $matcher
89
+	 * @return Matcher $matcher
90
+	 */
91
+	protected function applyCriteriaFromTSConfig(Matcher $matcher): Matcher
92
+	{
93
+		$dataType = $matcher->getDataType();
94
+		$tsConfigPath = sprintf('tx_vidi.dataType.%s.constraints', $dataType);
95
+		$tsConfig = $this->getBackendUser()->getTSConfig($tsConfigPath);
96
+
97
+		if (is_array($tsConfig['properties']) && !empty($tsConfig['properties'])) {
98
+
99
+			foreach ($tsConfig['properties'] as $constraint) {
100
+
101
+				if (preg_match('/(.+) (>=|>|<|<=|=|like) (.+)/is', $constraint, $matches) && count($matches) === 4) {
102
+
103
+					$operator = $matcher->getSupportedOperators()[strtolower(trim($matches[2]))];
104
+					$operand = trim($matches[1]);
105
+					$value = trim($matches[3]);
106
+
107
+					$matcher->$operator($operand, $value);
108
+				} elseif (preg_match('/(.+) (in) (.+)/is', $constraint, $matches) && count($matches) === 4) {
109
+
110
+					$operator = $matcher->getSupportedOperators()[trim($matches[2])];
111
+					$operand = trim($matches[1]);
112
+					$value = trim($matches[3]);
113
+					$matcher->$operator($operand, GeneralUtility::trimExplode(',', $value, true));
114
+				}
115
+			}
116
+		}
117
+
118
+		return $matcher;
119
+	}
120
+
121
+	/**
122
+	 * @param Matcher $matcher
123
+	 * @param array $matches
124
+	 * @return Matcher $matcher
125
+	 */
126
+	protected function applyCriteriaFromMatchesArgument(Matcher $matcher, $matches): Matcher
127
+	{
128
+		foreach ($matches as $fieldNameAndPath => $value) {
129
+			// CSV values should be considered as "in" operator in the query, otherwise "equals".
130
+			$explodedValues = GeneralUtility::trimExplode(',', $value, true);
131
+			if (count($explodedValues) > 1) {
132
+				$matcher->in($fieldNameAndPath, $explodedValues);
133
+			} else {
134
+				$matcher->equals($fieldNameAndPath, $explodedValues[0]);
135
+			}
136
+		}
137
+
138
+		return $matcher;
139
+	}
140
+
141
+	/**
142
+	 * Apply criteria specific to jQuery plugin DataTable.
143
+	 *
144
+	 * @param Matcher $matcher
145
+	 * @return Matcher $matcher
146
+	 */
147
+	protected function applyCriteriaFromDataTables(Matcher $matcher): Matcher
148
+	{
149
+
150
+		// Special case for Grid in the BE using jQuery DataTables plugin.
151
+		// Retrieve a possible search term from GP.
152
+		$query = GeneralUtility::_GP('search');
153
+		if (is_array($query)) {
154
+			if (!empty($query['value'])) {
155
+				$query = $query['value'];
156
+			} else {
157
+				$query = '';
158
+			}
159
+		}
160
+
161
+		if (strlen($query) > 0) {
162
+
163
+			// Parse the json query coming from the Visual Search.
164
+			$query = rawurldecode($query);
165
+			$queryParts = json_decode($query, true);
166
+
167
+			if (is_array($queryParts)) {
168
+				$matcher = $this->parseQuery($queryParts, $matcher);
169
+			} else {
170
+				$matcher->setSearchTerm($query);
171
+			}
172
+		}
173
+		return $matcher;
174
+	}
175
+
176
+	/**
177
+	 * @param array $queryParts
178
+	 * @param Matcher $matcher
179
+	 * @return Matcher $matcher
180
+	 */
181
+	protected function parseQuery(array $queryParts, Matcher $matcher): Matcher
182
+	{
183
+		$dataType = $matcher->getDataType();
184
+		foreach ($queryParts as $term) {
185
+			$fieldNameAndPath = key($term);
186
+
187
+			$resolvedDataType = $this->getFieldPathResolver()->getDataType($fieldNameAndPath, $dataType);
188
+			$fieldName = $this->getFieldPathResolver()->stripFieldPath($fieldNameAndPath, $dataType);
189
+
190
+			// Retrieve the value.
191
+			$value = current($term);
192
+
193
+			if (Tca::grid($resolvedDataType)->hasFacet($fieldName) && Tca::grid($resolvedDataType)->facet($fieldName)->canModifyMatcher()) {
194
+				$matcher = Tca::grid($resolvedDataType)->facet($fieldName)->modifyMatcher($matcher, $value);
195
+			} elseif (Tca::table($resolvedDataType)->hasField($fieldName)) {
196
+				// Check whether the field exists and set it as "equal" or "like".
197
+				if ($this->isOperatorEquals($fieldNameAndPath, $dataType, $value)) {
198
+					$matcher->equals($fieldNameAndPath, $value);
199
+				} else {
200
+					$matcher->like($fieldNameAndPath, $value);
201
+				}
202
+			} elseif ($fieldNameAndPath === 'text') {
203
+				// Special case if field is "text" which is a pseudo field in this case.
204
+				// Set the search term which means Vidi will
205
+				// search in various fields with operator "like". The fields come from key "searchFields" in the TCA.
206
+				$matcher->setSearchTerm($value);
207
+			}
208
+		}
209
+		return $matcher;
210
+	}
211
+
212
+	/**
213
+	 * Tell whether the operator should be equals instead of like for a search, e.g. if the value is numerical.
214
+	 *
215
+	 * @param string $fieldName
216
+	 * @param string $dataType
217
+	 * @param string $value
218
+	 * @return bool
219
+	 */
220
+	protected function isOperatorEquals($fieldName, $dataType, $value): bool
221
+	{
222
+		return (Tca::table($dataType)->field($fieldName)->hasRelation() && MathUtility::canBeInterpretedAsInteger($value))
223
+			|| Tca::table($dataType)->field($fieldName)->isNumerical();
224
+	}
225
+
226
+	/**
227
+	 * Signal that is called for post-processing a matcher object.
228
+	 *
229
+	 * @param Matcher $matcher
230
+	 */
231
+	protected function emitPostProcessMatcherObjectSignal(Matcher $matcher): void
232
+	{
233
+
234
+		if (strlen($matcher->getDataType()) <= 0) {
235
+
236
+			/** @var ModuleLoader $moduleLoader */
237
+			$moduleLoader = $this->getObjectManager()->get(ModuleLoader::class);
238
+			$matcher->setDataType($moduleLoader->getDataType());
239
+		}
240
+
241
+		$this->getSignalSlotDispatcher()->dispatch('Fab\Vidi\Controller\Backend\ContentController', 'postProcessMatcherObject', array($matcher, $matcher->getDataType()));
242
+	}
243
+
244
+	/**
245
+	 * Get the SignalSlot dispatcher
246
+	 *
247
+	 * @return Dispatcher|object
248
+	 */
249
+	protected function getSignalSlotDispatcher()
250
+	{
251
+		return $this->getObjectManager()->get(Dispatcher::class);
252
+	}
253
+
254
+	/**
255
+	 * @return ObjectManager|object
256
+	 */
257
+	protected function getObjectManager()
258
+	{
259
+		return GeneralUtility::makeInstance(ObjectManager::class);
260
+	}
261
+
262
+	/**
263
+	 * Get the Vidi Module Loader.
264
+	 *
265
+	 * @return ModuleLoader|object
266
+	 */
267
+	protected function getModuleLoader()
268
+	{
269
+		return GeneralUtility::makeInstance(ModuleLoader::class);
270
+	}
271
+
272
+	/**
273
+	 * @return FieldPathResolver|object
274
+	 */
275
+	protected function getFieldPathResolver()
276
+	{
277
+		return GeneralUtility::makeInstance(FieldPathResolver::class);
278
+	}
279
+
280
+	/**
281
+	 * Returns an instance of the current Backend User.
282
+	 *
283
+	 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
284
+	 */
285
+	protected function getBackendUser(): \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
286
+	{
287
+		return $GLOBALS['BE_USER'];
288
+	}
289
+
290
+	/**
291
+	 * Returns whether the current mode is Backend
292
+	 *
293
+	 * @return bool
294
+	 */
295
+	protected function isBackendMode(): bool
296
+	{
297
+		return TYPO3_MODE === 'BE';
298
+	}
299 299
 }
Please login to merge, or discard this patch.
Classes/Service/ContentService.php 1 patch
Indentation   +121 added lines, -121 removed lines patch added patch discarded remove patch
@@ -23,126 +23,126 @@
 block discarded – undo
23 23
 class ContentService
24 24
 {
25 25
 
26
-    /**
27
-     * @var string
28
-     */
29
-    protected $dataType;
30
-
31
-    /**
32
-     * @var \Fab\Vidi\Domain\Model\Content[]
33
-     */
34
-    protected $objects = [];
35
-
36
-    /**
37
-     * @var int
38
-     */
39
-    protected $numberOfObjects = 0;
40
-
41
-    /**
42
-     * Constructor
43
-     *
44
-     * @param string $dataType
45
-     */
46
-    public function __construct($dataType = '')
47
-    {
48
-        if (empty($dataType)) {
49
-            $dataType = $this->getModuleLoader()->getDataType();
50
-        }
51
-        $this->dataType = $dataType;
52
-    }
53
-
54
-    /**
55
-     * Fetch the files given an object assuming
56
-     *
57
-     * @param Matcher $matcher
58
-     * @param Order $order The order
59
-     * @param int $limit
60
-     * @param int $offset
61
-     * @return $this
62
-     */
63
-    public function findBy(Matcher $matcher, Order $order = null, $limit = null, $offset = null)
64
-    {
65
-
66
-        // Query the repository.
67
-        $objects = ContentRepositoryFactory::getInstance($this->dataType)->findBy($matcher, $order, $limit, $offset);
68
-        $signalResult = $this->emitAfterFindContentObjectsSignal($objects, $matcher, $order, $limit, $offset);
69
-
70
-        // Reset objects variable after possible signal / slot processing.
71
-        $this->objects = $signalResult->getContentObjects();
72
-
73
-        // Count number of content objects.
74
-        if ($signalResult->getHasBeenProcessed()) {
75
-            $this->numberOfObjects = $signalResult->getNumberOfObjects();
76
-        } else {
77
-            $this->numberOfObjects = ContentRepositoryFactory::getInstance($this->dataType)->countBy($matcher);
78
-        }
79
-
80
-        return $this;
81
-    }
82
-
83
-    /**
84
-     * Signal that is called after the content objects have been found.
85
-     *
86
-     * @param array $contentObjects
87
-     * @param \Fab\Vidi\Persistence\Matcher $matcher
88
-     * @param Order $order
89
-     * @param int $limit
90
-     * @param int $offset
91
-     * @return AfterFindContentObjectsSignalArguments
92
-     */
93
-    protected function emitAfterFindContentObjectsSignal($contentObjects, Matcher $matcher, Order $order = null, $limit = 0, $offset = 0)
94
-    {
95
-
96
-        /** @var AfterFindContentObjectsSignalArguments $signalArguments */
97
-        $signalArguments = GeneralUtility::makeInstance(AfterFindContentObjectsSignalArguments::class);
98
-        $signalArguments->setDataType($this->dataType)
99
-            ->setContentObjects($contentObjects)
100
-            ->setMatcher($matcher)
101
-            ->setOrder($order)
102
-            ->setLimit($limit)
103
-            ->setOffset($offset)
104
-            ->setHasBeenProcessed(false);
105
-
106
-        $signalResult = $this->getSignalSlotDispatcher()->dispatch(ContentService::class, 'afterFindContentObjects', array($signalArguments));
107
-        return $signalResult[0];
108
-    }
109
-
110
-    /**
111
-     * Get the Vidi Module Loader.
112
-     *
113
-     * @return ModuleLoader|object
114
-     */
115
-    protected function getModuleLoader()
116
-    {
117
-        return GeneralUtility::makeInstance(ModuleLoader::class);
118
-    }
119
-
120
-    /**
121
-     * Get the SignalSlot dispatcher.
122
-     *
123
-     * @return Dispatcher|object
124
-     */
125
-    protected function getSignalSlotDispatcher()
126
-    {
127
-        /** @var ObjectManager $objectManager */
128
-        $objectManager = GeneralUtility::makeInstance(ObjectManager::class);
129
-        return $objectManager->get(Dispatcher::class);
130
-    }
131
-
132
-    /**
133
-     * @return \Fab\Vidi\Domain\Model\Content[]
134
-     */
135
-    public function getObjects()
136
-    {
137
-        return $this->objects;
138
-    }
139
-
140
-    /**
141
-     * @return int
142
-     */
143
-    public function getNumberOfObjects()
144
-    {
145
-        return $this->numberOfObjects;
146
-    }
26
+	/**
27
+	 * @var string
28
+	 */
29
+	protected $dataType;
30
+
31
+	/**
32
+	 * @var \Fab\Vidi\Domain\Model\Content[]
33
+	 */
34
+	protected $objects = [];
35
+
36
+	/**
37
+	 * @var int
38
+	 */
39
+	protected $numberOfObjects = 0;
40
+
41
+	/**
42
+	 * Constructor
43
+	 *
44
+	 * @param string $dataType
45
+	 */
46
+	public function __construct($dataType = '')
47
+	{
48
+		if (empty($dataType)) {
49
+			$dataType = $this->getModuleLoader()->getDataType();
50
+		}
51
+		$this->dataType = $dataType;
52
+	}
53
+
54
+	/**
55
+	 * Fetch the files given an object assuming
56
+	 *
57
+	 * @param Matcher $matcher
58
+	 * @param Order $order The order
59
+	 * @param int $limit
60
+	 * @param int $offset
61
+	 * @return $this
62
+	 */
63
+	public function findBy(Matcher $matcher, Order $order = null, $limit = null, $offset = null)
64
+	{
65
+
66
+		// Query the repository.
67
+		$objects = ContentRepositoryFactory::getInstance($this->dataType)->findBy($matcher, $order, $limit, $offset);
68
+		$signalResult = $this->emitAfterFindContentObjectsSignal($objects, $matcher, $order, $limit, $offset);
69
+
70
+		// Reset objects variable after possible signal / slot processing.
71
+		$this->objects = $signalResult->getContentObjects();
72
+
73
+		// Count number of content objects.
74
+		if ($signalResult->getHasBeenProcessed()) {
75
+			$this->numberOfObjects = $signalResult->getNumberOfObjects();
76
+		} else {
77
+			$this->numberOfObjects = ContentRepositoryFactory::getInstance($this->dataType)->countBy($matcher);
78
+		}
79
+
80
+		return $this;
81
+	}
82
+
83
+	/**
84
+	 * Signal that is called after the content objects have been found.
85
+	 *
86
+	 * @param array $contentObjects
87
+	 * @param \Fab\Vidi\Persistence\Matcher $matcher
88
+	 * @param Order $order
89
+	 * @param int $limit
90
+	 * @param int $offset
91
+	 * @return AfterFindContentObjectsSignalArguments
92
+	 */
93
+	protected function emitAfterFindContentObjectsSignal($contentObjects, Matcher $matcher, Order $order = null, $limit = 0, $offset = 0)
94
+	{
95
+
96
+		/** @var AfterFindContentObjectsSignalArguments $signalArguments */
97
+		$signalArguments = GeneralUtility::makeInstance(AfterFindContentObjectsSignalArguments::class);
98
+		$signalArguments->setDataType($this->dataType)
99
+			->setContentObjects($contentObjects)
100
+			->setMatcher($matcher)
101
+			->setOrder($order)
102
+			->setLimit($limit)
103
+			->setOffset($offset)
104
+			->setHasBeenProcessed(false);
105
+
106
+		$signalResult = $this->getSignalSlotDispatcher()->dispatch(ContentService::class, 'afterFindContentObjects', array($signalArguments));
107
+		return $signalResult[0];
108
+	}
109
+
110
+	/**
111
+	 * Get the Vidi Module Loader.
112
+	 *
113
+	 * @return ModuleLoader|object
114
+	 */
115
+	protected function getModuleLoader()
116
+	{
117
+		return GeneralUtility::makeInstance(ModuleLoader::class);
118
+	}
119
+
120
+	/**
121
+	 * Get the SignalSlot dispatcher.
122
+	 *
123
+	 * @return Dispatcher|object
124
+	 */
125
+	protected function getSignalSlotDispatcher()
126
+	{
127
+		/** @var ObjectManager $objectManager */
128
+		$objectManager = GeneralUtility::makeInstance(ObjectManager::class);
129
+		return $objectManager->get(Dispatcher::class);
130
+	}
131
+
132
+	/**
133
+	 * @return \Fab\Vidi\Domain\Model\Content[]
134
+	 */
135
+	public function getObjects()
136
+	{
137
+		return $this->objects;
138
+	}
139
+
140
+	/**
141
+	 * @return int
142
+	 */
143
+	public function getNumberOfObjects()
144
+	{
145
+		return $this->numberOfObjects;
146
+	}
147 147
 
148 148
 }
Please login to merge, or discard this patch.
Classes/Tca/Tca.php 1 patch
Indentation   +130 added lines, -130 removed lines patch added patch discarded remove patch
@@ -21,135 +21,135 @@
 block discarded – undo
21 21
 class Tca implements SingletonInterface, TcaServiceInterface
22 22
 {
23 23
 
24
-    /**
25
-     * Fields that are considered as system.
26
-     *
27
-     * @var array
28
-     */
29
-    static protected $systemFields = array(
30
-        'uid',
31
-        'pid',
32
-        'tstamp',
33
-        'crdate',
34
-        'deleted',
35
-        'hidden',
36
-        'sys_language_uid',
37
-        'l18n_parent',
38
-        'l18n_diffsource',
39
-        't3ver_oid',
40
-        't3ver_id',
41
-        't3ver_wsid',
42
-        't3ver_label',
43
-        't3ver_state',
44
-        't3ver_stage',
45
-        't3ver_count',
46
-        't3ver_tstamp',
47
-        't3_origuid',
48
-    );
49
-
50
-    /**
51
-     * @var array
52
-     */
53
-    static protected $instances;
54
-
55
-    /**
56
-     * Returns a class instance of a corresponding TCA service.
57
-     * If the class instance does not exist, create one.
58
-     *
59
-     * @throws NotExistingClassException
60
-     * @param string $dataType
61
-     * @param string $serviceType of the TCA, TcaServiceInterface::TYPE_TABLE or TcaServiceInterface::TYPE_GRID
62
-     * @return TcaServiceInterface
63
-     * @throws \Fab\Vidi\Exception\InvalidKeyInArrayException
64
-     * @throws \InvalidArgumentException
65
-     */
66
-    static protected function getService($dataType = '', $serviceType)
67
-    {
68
-        if (TYPO3_MODE === 'BE' && empty($dataType)) {
69
-
70
-            /** @var \Fab\Vidi\Module\ModuleLoader $moduleLoader */
71
-            $moduleLoader = GeneralUtility::makeInstance(\Fab\Vidi\Module\ModuleLoader::class);
72
-            $dataType = $moduleLoader->getDataType();
73
-        }
74
-
75
-        if (empty(self::$instances[$dataType][$serviceType])) {
76
-            $className = sprintf('Fab\Vidi\Tca\%sService', ucfirst($serviceType));
77
-
78
-            // Signal to pre-process the TCA of the given $dataType.
79
-            self::emitPreProcessTcaSignal($dataType, $serviceType);
80
-
81
-            $instance = GeneralUtility::makeInstance($className, $dataType, $serviceType);
82
-            self::$instances[$dataType][$serviceType] = $instance;
83
-        }
84
-        return self::$instances[$dataType][$serviceType];
85
-    }
86
-
87
-    /**
88
-     * Returns a "grid" service instance.
89
-     *
90
-     * @param string|Content $tableNameOrContentObject
91
-     * @return \Fab\Vidi\Tca\GridService
92
-     * @throws \Fab\Vidi\Exception\NotExistingClassException
93
-     */
94
-    static public function grid($tableNameOrContentObject = '')
95
-    {
96
-        $tableName = $tableNameOrContentObject instanceof Content ? $tableNameOrContentObject->getDataType() : $tableNameOrContentObject;
97
-        return self::getService($tableName, self::TYPE_GRID);
98
-    }
99
-
100
-    /**
101
-     * Returns a "table" service instance ("ctrl" part of the TCA).
102
-     *
103
-     * @param string|Content $tableNameOrContentObject
104
-     * @return \Fab\Vidi\Tca\TableService
105
-     * @throws \Fab\Vidi\Exception\NotExistingClassException
106
-     */
107
-    static public function table($tableNameOrContentObject = '')
108
-    {
109
-        $tableName = $tableNameOrContentObject instanceof Content ? $tableNameOrContentObject->getDataType() : $tableNameOrContentObject;
110
-        return self::getService($tableName, self::TYPE_TABLE);
111
-    }
112
-
113
-    /**
114
-     * @return array
115
-     */
116
-    public static function getInstanceStorage()
117
-    {
118
-        return self::$instances;
119
-    }
120
-
121
-    /**
122
-     * @return array
123
-     */
124
-    public static function getSystemFields()
125
-    {
126
-        return self::$systemFields;
127
-    }
128
-
129
-    /**
130
-     * Signal that is called after the content repository for a content type has been instantiated.
131
-     *
132
-     * @param string $dataType
133
-     * @param string $serviceType
134
-     * @throws \TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotException
135
-     * @throws \TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotReturnException
136
-     * @throws \InvalidArgumentException
137
-     */
138
-    static protected function emitPreProcessTcaSignal($dataType, $serviceType)
139
-    {
140
-        self::getSignalSlotDispatcher()->dispatch(Tca::class, 'preProcessTca', array($dataType, $serviceType));
141
-    }
142
-
143
-    /**
144
-     * Get the SignalSlot dispatcher
145
-     *
146
-     * @return Dispatcher
147
-     * @throws \InvalidArgumentException
148
-     */
149
-    static protected function getSignalSlotDispatcher()
150
-    {
151
-        $objectManager = GeneralUtility::makeInstance(ObjectManager::class);
152
-        return $objectManager->get(Dispatcher::class);
153
-    }
24
+	/**
25
+	 * Fields that are considered as system.
26
+	 *
27
+	 * @var array
28
+	 */
29
+	static protected $systemFields = array(
30
+		'uid',
31
+		'pid',
32
+		'tstamp',
33
+		'crdate',
34
+		'deleted',
35
+		'hidden',
36
+		'sys_language_uid',
37
+		'l18n_parent',
38
+		'l18n_diffsource',
39
+		't3ver_oid',
40
+		't3ver_id',
41
+		't3ver_wsid',
42
+		't3ver_label',
43
+		't3ver_state',
44
+		't3ver_stage',
45
+		't3ver_count',
46
+		't3ver_tstamp',
47
+		't3_origuid',
48
+	);
49
+
50
+	/**
51
+	 * @var array
52
+	 */
53
+	static protected $instances;
54
+
55
+	/**
56
+	 * Returns a class instance of a corresponding TCA service.
57
+	 * If the class instance does not exist, create one.
58
+	 *
59
+	 * @throws NotExistingClassException
60
+	 * @param string $dataType
61
+	 * @param string $serviceType of the TCA, TcaServiceInterface::TYPE_TABLE or TcaServiceInterface::TYPE_GRID
62
+	 * @return TcaServiceInterface
63
+	 * @throws \Fab\Vidi\Exception\InvalidKeyInArrayException
64
+	 * @throws \InvalidArgumentException
65
+	 */
66
+	static protected function getService($dataType = '', $serviceType)
67
+	{
68
+		if (TYPO3_MODE === 'BE' && empty($dataType)) {
69
+
70
+			/** @var \Fab\Vidi\Module\ModuleLoader $moduleLoader */
71
+			$moduleLoader = GeneralUtility::makeInstance(\Fab\Vidi\Module\ModuleLoader::class);
72
+			$dataType = $moduleLoader->getDataType();
73
+		}
74
+
75
+		if (empty(self::$instances[$dataType][$serviceType])) {
76
+			$className = sprintf('Fab\Vidi\Tca\%sService', ucfirst($serviceType));
77
+
78
+			// Signal to pre-process the TCA of the given $dataType.
79
+			self::emitPreProcessTcaSignal($dataType, $serviceType);
80
+
81
+			$instance = GeneralUtility::makeInstance($className, $dataType, $serviceType);
82
+			self::$instances[$dataType][$serviceType] = $instance;
83
+		}
84
+		return self::$instances[$dataType][$serviceType];
85
+	}
86
+
87
+	/**
88
+	 * Returns a "grid" service instance.
89
+	 *
90
+	 * @param string|Content $tableNameOrContentObject
91
+	 * @return \Fab\Vidi\Tca\GridService
92
+	 * @throws \Fab\Vidi\Exception\NotExistingClassException
93
+	 */
94
+	static public function grid($tableNameOrContentObject = '')
95
+	{
96
+		$tableName = $tableNameOrContentObject instanceof Content ? $tableNameOrContentObject->getDataType() : $tableNameOrContentObject;
97
+		return self::getService($tableName, self::TYPE_GRID);
98
+	}
99
+
100
+	/**
101
+	 * Returns a "table" service instance ("ctrl" part of the TCA).
102
+	 *
103
+	 * @param string|Content $tableNameOrContentObject
104
+	 * @return \Fab\Vidi\Tca\TableService
105
+	 * @throws \Fab\Vidi\Exception\NotExistingClassException
106
+	 */
107
+	static public function table($tableNameOrContentObject = '')
108
+	{
109
+		$tableName = $tableNameOrContentObject instanceof Content ? $tableNameOrContentObject->getDataType() : $tableNameOrContentObject;
110
+		return self::getService($tableName, self::TYPE_TABLE);
111
+	}
112
+
113
+	/**
114
+	 * @return array
115
+	 */
116
+	public static function getInstanceStorage()
117
+	{
118
+		return self::$instances;
119
+	}
120
+
121
+	/**
122
+	 * @return array
123
+	 */
124
+	public static function getSystemFields()
125
+	{
126
+		return self::$systemFields;
127
+	}
128
+
129
+	/**
130
+	 * Signal that is called after the content repository for a content type has been instantiated.
131
+	 *
132
+	 * @param string $dataType
133
+	 * @param string $serviceType
134
+	 * @throws \TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotException
135
+	 * @throws \TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotReturnException
136
+	 * @throws \InvalidArgumentException
137
+	 */
138
+	static protected function emitPreProcessTcaSignal($dataType, $serviceType)
139
+	{
140
+		self::getSignalSlotDispatcher()->dispatch(Tca::class, 'preProcessTca', array($dataType, $serviceType));
141
+	}
142
+
143
+	/**
144
+	 * Get the SignalSlot dispatcher
145
+	 *
146
+	 * @return Dispatcher
147
+	 * @throws \InvalidArgumentException
148
+	 */
149
+	static protected function getSignalSlotDispatcher()
150
+	{
151
+		$objectManager = GeneralUtility::makeInstance(ObjectManager::class);
152
+		return $objectManager->get(Dispatcher::class);
153
+	}
154 154
 
155 155
 }
Please login to merge, or discard this patch.