Completed
Push — master ( 9e3b6d...6d03f6 )
by Fabien
06:07 queued 02:59
created
Classes/DataHandler/CoreDataHandler.php 2 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -94,7 +94,7 @@
 block discarded – undo
94 94
      *
95 95
      * @param Content $content
96 96
      * @param string $target
97
-     * @return bool
97
+     * @return boolean|null
98 98
      */
99 99
     public function processCopy(Content $content, $target)
100 100
     {
Please login to merge, or discard this patch.
Indentation   +135 added lines, -135 removed lines patch added patch discarded remove patch
@@ -24,140 +24,140 @@
 block discarded – undo
24 24
 class CoreDataHandler extends AbstractDataHandler
25 25
 {
26 26
 
27
-    /**
28
-     * @var array
29
-     */
30
-    protected $dataHandler;
31
-
32
-    /**
33
-     * Process Content with action "update".
34
-     *
35
-     * @param Content $content
36
-     * @throws \Exception
37
-     * @return bool
38
-     */
39
-    public function processUpdate(Content $content)
40
-    {
41
-
42
-        $values = array();
43
-
44
-        // Check the field to be updated exists
45
-        foreach ($content->toArray() as $fieldName => $value) {
46
-            if (!Tca::table($content->getDataType())->hasField($fieldName)) {
47
-                $message = sprintf('It looks field "%s" does not exist for data type "%s"', $fieldName, $content->getDataType());
48
-                throw new \Exception($message, 1390668497);
49
-            }
50
-
51
-            // Flatten value if array given which is required for the DataHandler.
52
-            if (is_array($value)) {
53
-                $value = implode(',', $value);
54
-            }
55
-            $values[$fieldName] = $value;
56
-        }
57
-
58
-        $data[$content->getDataType()][$content->getUid()] = $values;
59
-
60
-        $dataHandler = $this->getDataHandler();
61
-        $dataHandler->start($data, array());
62
-        $dataHandler->process_datamap();
63
-        $this->errorMessages = $dataHandler->errorLog;
64
-
65
-        // Returns TRUE is log does not contain errors.
66
-        return empty($dataHandler->errorLog);
67
-    }
68
-
69
-    /**
70
-     * Process Content with action "remove".
71
-     *
72
-     * @param Content $content
73
-     * @return bool
74
-     */
75
-    public function processRemove(Content $content)
76
-    {
77
-
78
-        // Build command
79
-        $cmd[$content->getDataType()][$content->getUid()]['delete'] = 1;
80
-
81
-        /** @var $dataHandler \TYPO3\CMS\Core\DataHandling\DataHandler */
82
-        $dataHandler = $this->getDataHandler();
83
-        $dataHandler->start(array(), $cmd);
84
-        $dataHandler->process_datamap();
85
-        $dataHandler->process_cmdmap();
86
-        $this->errorMessages = $dataHandler->errorLog;
87
-
88
-        // Returns TRUE is log does not contain errors.
89
-        return empty($dataHandler->errorLog);
90
-    }
91
-
92
-    /**
93
-     * Process Content with action "copy".
94
-     *
95
-     * @param Content $content
96
-     * @param string $target
97
-     * @return bool
98
-     */
99
-    public function processCopy(Content $content, $target)
100
-    {
101
-        // TODO: Implement processCopy() method.
102
-    }
103
-
104
-    /**
105
-     * Process Content with action "move".
106
-     * The $target corresponds to the pid to move the records to.
107
-     * It can also be a negative value in case of sorting. The negative value would be the uid of its predecessor.
108
-     *
109
-     * @param Content $content
110
-     * @param int $target corresponds
111
-     * @return bool
112
-     */
113
-    public function processMove(Content $content, $target)
114
-    {
115
-
116
-        // Build command
117
-        $cmd[$content->getDataType()][$content->getUid()]['move'] = $target;
118
-
119
-        /** @var $dataHandler \TYPO3\CMS\Core\DataHandling\DataHandler */
120
-        $dataHandler = $this->getDataHandler();
121
-        $dataHandler->start(array(), $cmd);
122
-        $dataHandler->process_datamap();
123
-        $dataHandler->process_cmdmap();
124
-        $this->errorMessages = $dataHandler->errorLog;
125
-
126
-        // Returns TRUE is log does not contain errors.
127
-        return empty($dataHandler->errorLog);
128
-    }
129
-
130
-    /**
131
-     * Process Content with action "localize".
132
-     *
133
-     * @param Content $content
134
-     * @param int $language
135
-     * @return bool
136
-     */
137
-    public function processLocalize(Content $content, $language)
138
-    {
139
-
140
-        $command[$content->getDataType()][$content->getUid()]['localize'] = $language;
141
-
142
-        $dataHandler = $this->getDataHandler();
143
-        $dataHandler->start(array(), $command);
144
-        $dataHandler->process_datamap();
145
-        $dataHandler->process_cmdmap();
146
-        $this->errorMessages = $dataHandler->errorLog;
147
-
148
-        // Returns TRUE is log does not contain errors.
149
-        return empty($dataHandler->errorLog);
150
-    }
151
-
152
-    /**
153
-     * @return \TYPO3\CMS\Core\DataHandling\DataHandler
154
-     */
155
-    protected function getDataHandler()
156
-    {
157
-        if (!$this->dataHandler) {
158
-            $this->dataHandler = GeneralUtility::makeInstance('TYPO3\CMS\Core\DataHandling\DataHandler');
159
-        }
160
-        return $this->dataHandler;
161
-    }
27
+	/**
28
+	 * @var array
29
+	 */
30
+	protected $dataHandler;
31
+
32
+	/**
33
+	 * Process Content with action "update".
34
+	 *
35
+	 * @param Content $content
36
+	 * @throws \Exception
37
+	 * @return bool
38
+	 */
39
+	public function processUpdate(Content $content)
40
+	{
41
+
42
+		$values = array();
43
+
44
+		// Check the field to be updated exists
45
+		foreach ($content->toArray() as $fieldName => $value) {
46
+			if (!Tca::table($content->getDataType())->hasField($fieldName)) {
47
+				$message = sprintf('It looks field "%s" does not exist for data type "%s"', $fieldName, $content->getDataType());
48
+				throw new \Exception($message, 1390668497);
49
+			}
50
+
51
+			// Flatten value if array given which is required for the DataHandler.
52
+			if (is_array($value)) {
53
+				$value = implode(',', $value);
54
+			}
55
+			$values[$fieldName] = $value;
56
+		}
57
+
58
+		$data[$content->getDataType()][$content->getUid()] = $values;
59
+
60
+		$dataHandler = $this->getDataHandler();
61
+		$dataHandler->start($data, array());
62
+		$dataHandler->process_datamap();
63
+		$this->errorMessages = $dataHandler->errorLog;
64
+
65
+		// Returns TRUE is log does not contain errors.
66
+		return empty($dataHandler->errorLog);
67
+	}
68
+
69
+	/**
70
+	 * Process Content with action "remove".
71
+	 *
72
+	 * @param Content $content
73
+	 * @return bool
74
+	 */
75
+	public function processRemove(Content $content)
76
+	{
77
+
78
+		// Build command
79
+		$cmd[$content->getDataType()][$content->getUid()]['delete'] = 1;
80
+
81
+		/** @var $dataHandler \TYPO3\CMS\Core\DataHandling\DataHandler */
82
+		$dataHandler = $this->getDataHandler();
83
+		$dataHandler->start(array(), $cmd);
84
+		$dataHandler->process_datamap();
85
+		$dataHandler->process_cmdmap();
86
+		$this->errorMessages = $dataHandler->errorLog;
87
+
88
+		// Returns TRUE is log does not contain errors.
89
+		return empty($dataHandler->errorLog);
90
+	}
91
+
92
+	/**
93
+	 * Process Content with action "copy".
94
+	 *
95
+	 * @param Content $content
96
+	 * @param string $target
97
+	 * @return bool
98
+	 */
99
+	public function processCopy(Content $content, $target)
100
+	{
101
+		// TODO: Implement processCopy() method.
102
+	}
103
+
104
+	/**
105
+	 * Process Content with action "move".
106
+	 * The $target corresponds to the pid to move the records to.
107
+	 * It can also be a negative value in case of sorting. The negative value would be the uid of its predecessor.
108
+	 *
109
+	 * @param Content $content
110
+	 * @param int $target corresponds
111
+	 * @return bool
112
+	 */
113
+	public function processMove(Content $content, $target)
114
+	{
115
+
116
+		// Build command
117
+		$cmd[$content->getDataType()][$content->getUid()]['move'] = $target;
118
+
119
+		/** @var $dataHandler \TYPO3\CMS\Core\DataHandling\DataHandler */
120
+		$dataHandler = $this->getDataHandler();
121
+		$dataHandler->start(array(), $cmd);
122
+		$dataHandler->process_datamap();
123
+		$dataHandler->process_cmdmap();
124
+		$this->errorMessages = $dataHandler->errorLog;
125
+
126
+		// Returns TRUE is log does not contain errors.
127
+		return empty($dataHandler->errorLog);
128
+	}
129
+
130
+	/**
131
+	 * Process Content with action "localize".
132
+	 *
133
+	 * @param Content $content
134
+	 * @param int $language
135
+	 * @return bool
136
+	 */
137
+	public function processLocalize(Content $content, $language)
138
+	{
139
+
140
+		$command[$content->getDataType()][$content->getUid()]['localize'] = $language;
141
+
142
+		$dataHandler = $this->getDataHandler();
143
+		$dataHandler->start(array(), $command);
144
+		$dataHandler->process_datamap();
145
+		$dataHandler->process_cmdmap();
146
+		$this->errorMessages = $dataHandler->errorLog;
147
+
148
+		// Returns TRUE is log does not contain errors.
149
+		return empty($dataHandler->errorLog);
150
+	}
151
+
152
+	/**
153
+	 * @return \TYPO3\CMS\Core\DataHandling\DataHandler
154
+	 */
155
+	protected function getDataHandler()
156
+	{
157
+		if (!$this->dataHandler) {
158
+			$this->dataHandler = GeneralUtility::makeInstance('TYPO3\CMS\Core\DataHandling\DataHandler');
159
+		}
160
+		return $this->dataHandler;
161
+	}
162 162
 
163 163
 }
Please login to merge, or discard this patch.
Classes/Domain/Model/Content.php 3 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -385,7 +385,7 @@
 block discarded – undo
385 385
     /**
386 386
      * Return the properties of this object.
387 387
      *
388
-     * @return array
388
+     * @return string[]
389 389
      */
390 390
     public function toFields()
391 391
     {
Please login to merge, or discard this patch.
Spacing   +7 added lines, -7 removed lines patch added patch discarded remove patch
@@ -99,7 +99,7 @@  discard block
 block discarded – undo
99 99
     {
100 100
         $value = NULL;
101 101
         if (substr($methodName, 0, 3) === 'get' && strlen($methodName) > 4) {
102
-            $propertyName = strtolower(substr(substr($methodName, 3), 0, 1)) . substr(substr($methodName, 3), 1);
102
+            $propertyName = strtolower(substr(substr($methodName, 3), 0, 1)).substr(substr($methodName, 3), 1);
103 103
 
104 104
             $fieldName = Property::name($propertyName)->of($this)->toFieldName();
105 105
             $field = Tca::table($this->dataType)->field($fieldName);
@@ -119,7 +119,7 @@  discard block
 block discarded – undo
119 119
             }
120 120
 
121 121
         } elseif (substr($methodName, 0, 3) === 'set' && strlen($methodName) > 4 && isset($arguments[0])) {
122
-            $propertyName = strtolower(substr(substr($methodName, 3), 0, 1)) . substr(substr($methodName, 3), 1);
122
+            $propertyName = strtolower(substr(substr($methodName, 3), 0, 1)).substr(substr($methodName, 3), 1);
123 123
             $this->$propertyName = $arguments[0];
124 124
         }
125 125
         return $value;
@@ -177,13 +177,13 @@  discard block
 block discarded – undo
177 177
 
178 178
             // Fetch values from repository.
179 179
             $foreignPropertyName = Field::name($foreignFieldName)->of($this)->toPropertyName();
180
-            $findByProperty = 'findBy' . ucfirst($foreignPropertyName);
180
+            $findByProperty = 'findBy'.ucfirst($foreignPropertyName);
181 181
 
182 182
             // Date picker (type == group) are special fields because property path must contain the table name
183 183
             // to determine the relation type. Example for sys_category, property path will look like "items.sys_file"
184 184
             $propertyValue = $this->uid;
185 185
             if (Tca::table($foreignDataType)->field($foreignFieldName)->isGroup()) {
186
-                $propertyValue = $this->dataType . '.' . $this->uid;
186
+                $propertyValue = $this->dataType.'.'.$this->uid;
187 187
             }
188 188
 
189 189
             $this->$propertyName = $foreignContentRepository->$findByProperty($propertyValue);
@@ -203,7 +203,7 @@  discard block
 block discarded – undo
203 203
                 $foreignDataType = Tca::table($this->dataType)->field($fieldName)->getForeignTable();
204 204
                 $foreignField = Tca::table($this->dataType)->field($fieldName)->getForeignField();
205 205
                 $foreignContentRepository = ContentRepositoryFactory::getInstance($foreignDataType);
206
-                $find = 'findOneBy' . GeneralUtility::underscoredToUpperCamelCase($foreignField);
206
+                $find = 'findOneBy'.GeneralUtility::underscoredToUpperCamelCase($foreignField);
207 207
 
208 208
                 /** @var Content $foreignObject */
209 209
                 $this->$propertyName = $foreignContentRepository->$find($this->getUid());
@@ -252,7 +252,7 @@  discard block
 block discarded – undo
252 252
     public function offsetGet($offset)
253 253
     {
254 254
         $offset = Field::name($offset)->of($this)->toPropertyName();
255
-        $getter = 'get' . ucfirst($offset);
255
+        $getter = 'get'.ucfirst($offset);
256 256
         return $this->$getter();
257 257
     }
258 258
 
@@ -267,7 +267,7 @@  discard block
 block discarded – undo
267 267
     public function offsetSet($offset, $value)
268 268
     {
269 269
         $offset = Field::name($offset)->of($this)->toPropertyName();
270
-        $setter = 'set' . ucfirst($offset);
270
+        $setter = 'set'.ucfirst($offset);
271 271
         $this->$setter($value);
272 272
         return $this;
273 273
     }
Please login to merge, or discard this patch.
Indentation   +445 added lines, -445 removed lines patch added patch discarded remove patch
@@ -23,450 +23,450 @@
 block discarded – undo
23 23
 class Content implements \ArrayAccess
24 24
 {
25 25
 
26
-    /**
27
-     * @var int
28
-     */
29
-    protected $uid;
30
-
31
-    /**
32
-     * @var string
33
-     */
34
-    protected $dataType;
35
-
36
-    /**
37
-     * Constructor for a Content object.
38
-     *
39
-     * @param string $dataType will basically correspond to a table name, e.g fe_users, tt_content, ...
40
-     * @param array $contentData
41
-     * @return \Fab\Vidi\Domain\Model\Content
42
-     * @throws \InvalidArgumentException
43
-     * @throws \Fab\Vidi\Exception\NotExistingClassException
44
-     */
45
-    public function __construct($dataType, array $contentData = array())
46
-    {
47
-
48
-        $this->dataType = $dataType;
49
-        $this->uid = empty($contentData['uid']) ? NULL : (int)$contentData['uid'];
50
-
51
-        /** @var \Fab\Vidi\Tca\TableService $table */
52
-        $table = Tca::table($dataType);
53
-
54
-        // Initialize the array containing the allowed fields to be filled-in.
55
-        $fields = array('pid');
56
-
57
-        // If a creation time stamp has been defined for this data type.
58
-        if ($table->getTimeCreationField()) {
59
-            $fields[] = $table->getTimeCreationField();
60
-        }
61
-
62
-        // If an update time stamp has been defined for this data type.
63
-        if ($table->getTimeModificationField()) {
64
-            $fields[] = $table->getTimeModificationField();
65
-        }
66
-
67
-        // Merge the other fields allowed for this data type.
68
-        $fields = array_merge($fields, $table->getFields());
69
-
70
-        // Fetch excluded fields from the grid.
71
-        if ($this->isBackendMode()) {
72
-            $fields = $this->filterForConfiguration($fields);
73
-            $fields = $this->filterForBackendUser($fields);
74
-        }
75
-
76
-        // Get column to be displayed
77
-        foreach ($fields as $fieldName) {
78
-            if (array_key_exists($fieldName, $contentData)) {
79
-                $propertyName = Field::name($fieldName)->of($dataType)->toPropertyName();
80
-                $this->$propertyName = $contentData[$fieldName];
81
-            }
82
-        }
83
-    }
84
-
85
-    /**
86
-     * Dispatches magic methods (findBy[Property]())
87
-     *
88
-     * @param string $methodName The name of the magic method
89
-     * @param string $arguments The arguments of the magic method
90
-     * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\UnsupportedMethodException
91
-     * @return mixed
92
-     * @api
93
-     */
94
-    public function __call($methodName, $arguments)
95
-    {
96
-        $value = NULL;
97
-        if (substr($methodName, 0, 3) === 'get' && strlen($methodName) > 4) {
98
-            $propertyName = strtolower(substr(substr($methodName, 3), 0, 1)) . substr(substr($methodName, 3), 1);
99
-
100
-            $fieldName = Property::name($propertyName)->of($this)->toFieldName();
101
-            $field = Tca::table($this->dataType)->field($fieldName);
102
-
103
-            $value = $this->$propertyName;
104
-
105
-            // true means it is a relation and it is not yet resolved.
106
-            if ($this->hasRelation($propertyName) && is_scalar($this->$propertyName)) {
107
-                $value = $this->resolveRelation($propertyName);
108
-            } elseif ($field->getType() === FieldType::RADIO || $field->getType() === FieldType::SELECT) {
109
-
110
-                // Attempt to convert the value into a label for radio and select fields.
111
-                $label = Tca::table($this->getDataType())->field($fieldName)->getLabelForItem($value);
112
-                if ($label) {
113
-                    $value = $label;
114
-                }
115
-            }
116
-
117
-        } elseif (substr($methodName, 0, 3) === 'set' && strlen($methodName) > 4 && isset($arguments[0])) {
118
-            $propertyName = strtolower(substr(substr($methodName, 3), 0, 1)) . substr(substr($methodName, 3), 1);
119
-            $this->$propertyName = $arguments[0];
120
-        }
121
-        return $value;
122
-    }
123
-
124
-    /**
125
-     * Tell whether the property has a relation.
126
-     *
127
-     * @param string $propertyName
128
-     * @return bool
129
-     */
130
-    protected function hasRelation($propertyName)
131
-    {
132
-        $fieldName = Property::name($propertyName)->of($this)->toFieldName();
133
-        return Tca::table($this->dataType)->field($fieldName)->hasRelation();
134
-    }
135
-
136
-    /**
137
-     * Try to "resolve" the property whether it has a relation.
138
-     * If the property has not relation it simply returns the same value.
139
-     *
140
-     * @throws \RuntimeException
141
-     * @param string $propertyName
142
-     * @return mixed
143
-     */
144
-    protected function resolveRelation($propertyName)
145
-    {
146
-
147
-        // Convert property name to field name and get the foreign data type.
148
-        $fieldName = Property::name($propertyName)->of($this)->toFieldName();
149
-        $foreignDataType = Tca::table($this->dataType)->field($fieldName)->relationDataType();
150
-
151
-        // Get the foreign repository instance form the factory
152
-        /** @var \Fab\Vidi\Domain\Repository\ContentRepository $foreignContentRepository */
153
-        $foreignContentRepository = ContentRepositoryFactory::getInstance($foreignDataType, $fieldName);
154
-
155
-        if (Tca::table($this->dataType)->field($fieldName)->hasRelationWithCommaSeparatedValues()) {
156
-
157
-            // Fetch values from repository
158
-            $values = GeneralUtility::trimExplode(',', $this->$propertyName);
159
-            $this->$propertyName = $foreignContentRepository->findIn('uid', $values);
160
-        } elseif (Tca::table($this->dataType)->field($fieldName)->hasMany()) {
161
-            // Include relation many-to-many and one-to-many
162
-            // Tca::table($this->dataType)->field($fieldName)->hasRelationOneToMany()
163
-            // Tca::table($this->dataType)->field($fieldName)->hasRelationManyToMany()
164
-
165
-            $foreignFieldName = Tca::table($this->dataType)->field($fieldName)->getForeignField();
166
-            if (empty($foreignFieldName)) {
167
-                $message = sprintf('Missing "foreign_field" key for field "%s" in table "%s".',
168
-                    $fieldName,
169
-                    $this->dataType
170
-                );
171
-                throw new \RuntimeException($message, 1376149186);
172
-            }
173
-
174
-            // Fetch values from repository.
175
-            $foreignPropertyName = Field::name($foreignFieldName)->of($this)->toPropertyName();
176
-            $findByProperty = 'findBy' . ucfirst($foreignPropertyName);
177
-
178
-            // Date picker (type == group) are special fields because property path must contain the table name
179
-            // to determine the relation type. Example for sys_category, property path will look like "items.sys_file"
180
-            $propertyValue = $this->uid;
181
-            if (Tca::table($foreignDataType)->field($foreignFieldName)->isGroup()) {
182
-                $propertyValue = $this->dataType . '.' . $this->uid;
183
-            }
184
-
185
-            $this->$propertyName = $foreignContentRepository->$findByProperty($propertyValue);
186
-
187
-        } elseif (Tca::table($this->dataType)->field($fieldName)->hasOne()) {
188
-
189
-            $fieldConfiguration = Tca::table($this->dataType)->field($fieldName)->getConfiguration();
190
-
191
-            // First case, we are on the "good side" of the relation, just query the repository
192
-            if (empty($fieldConfiguration['foreign_field'])) {
193
-                $this->$propertyName = $foreignContentRepository->findByUid($this->$propertyName);
194
-            } else {
195
-                // Second case, we are the "bad side" of the relation, query the foreign repository
196
-                // e.g. in case of one-to-one relation.
197
-
198
-                // We must query the opposite side to get the identifier of the foreign object.
199
-                $foreignDataType = Tca::table($this->dataType)->field($fieldName)->getForeignTable();
200
-                $foreignField = Tca::table($this->dataType)->field($fieldName)->getForeignField();
201
-                $foreignContentRepository = ContentRepositoryFactory::getInstance($foreignDataType);
202
-                $find = 'findOneBy' . GeneralUtility::underscoredToUpperCamelCase($foreignField);
203
-
204
-                /** @var Content $foreignObject */
205
-                $this->$propertyName = $foreignContentRepository->$find($this->getUid());
206
-            }
207
-
208
-        }
209
-        return $this->$propertyName;
210
-    }
211
-
212
-    /**
213
-     * @return int
214
-     */
215
-    public function getUid()
216
-    {
217
-        return $this->uid;
218
-    }
219
-
220
-    /**
221
-     * @return string
222
-     */
223
-    public function getDataType()
224
-    {
225
-        return $this->dataType;
226
-    }
227
-
228
-    /**
229
-     * Whether a offset exists
230
-     *
231
-     * @link http://php.net/manual/en/arrayaccess.offsetexists.php
232
-     * @param mixed $offset
233
-     * @return boolean true on success or false on failure.
234
-     * @throws \RuntimeException
235
-     * @throws \InvalidArgumentException
236
-     */
237
-    public function offsetExists($offset)
238
-    {
239
-        $offset = Field::name($offset)->of($this)->toPropertyName();
240
-        return isset($this->$offset);
241
-    }
242
-
243
-    /**
244
-     * Offset to retrieve
245
-     *
246
-     * @link http://php.net/manual/en/arrayaccess.offsetget.php
247
-     * @param mixed $offset
248
-     * @return mixed Can return all value types.
249
-     * @throws \RuntimeException
250
-     * @throws \InvalidArgumentException
251
-     */
252
-    public function offsetGet($offset)
253
-    {
254
-        $offset = Field::name($offset)->of($this)->toPropertyName();
255
-        $getter = 'get' . ucfirst($offset);
256
-        return $this->$getter();
257
-    }
258
-
259
-    /**
260
-     * Offset to set
261
-     *
262
-     * @link http://php.net/manual/en/arrayaccess.offsetset.php
263
-     * @param mixed $offset
264
-     * @param mixed $value
265
-     * @return $this
266
-     * @throws \RuntimeException
267
-     * @throws \InvalidArgumentException
268
-     */
269
-    public function offsetSet($offset, $value)
270
-    {
271
-        $offset = Field::name($offset)->of($this)->toPropertyName();
272
-        $setter = 'set' . ucfirst($offset);
273
-        $this->$setter($value);
274
-        return $this;
275
-    }
276
-
277
-    /**
278
-     * Offset to unset
279
-     *
280
-     * @link http://php.net/manual/en/arrayaccess.offsetunset.php
281
-     * @param mixed $offset
282
-     * @throws NotImplementedException
283
-     * @return void
284
-     */
285
-    public function offsetUnset($offset)
286
-    {
287
-        $message = 'Un-setting value for Array object is not supported';
288
-        throw new NotImplementedException($message, 1376132306);
289
-    }
290
-
291
-    /**
292
-     * Convert this to array
293
-     *
294
-     * @return array
295
-     * @throws \InvalidArgumentException
296
-     */
297
-    public function toArray()
298
-    {
299
-        $result['uid'] = $this->uid;
300
-        $propertiesAndValues = json_decode(json_encode($this), true);
301
-
302
-        foreach ($propertiesAndValues as $propertyName => $value) {
303
-            $fieldName = Property::name($propertyName)->of($this)->toFieldName();
304
-            $result[$fieldName] = $value;
305
-        }
306
-
307
-        return $result;
308
-    }
309
-
310
-    /**
311
-     * Convert this object to an array containing the resolved values.
312
-     *
313
-     * @param bool $resolveRelations
314
-     * @return array
315
-     * @throws \Exception
316
-     */
317
-    public function toValues($resolveRelations = true)
318
-    {
319
-        $result['uid'] = $this->uid;
320
-        $propertiesAndValues = json_decode(json_encode($this), true);
321
-
322
-        foreach ($propertiesAndValues as $propertyName => $value) {
323
-            $fieldName = Property::name($propertyName)->of($this)->toFieldName();
324
-
325
-            $result[$fieldName] = $value;
326
-            if ($resolveRelations) {
327
-                $field = Tca::table($this->dataType)->field($fieldName);
328
-
329
-                $resolvedValue = '';
330
-                if ($field->getType() === FieldType::FILE) {
331
-
332
-                    if ($field->hasMany()) {
333
-                        $files = FileReferenceService::getInstance()->findReferencedBy($propertyName, $this);
334
-
335
-                        $resolvedValue = array();
336
-                        foreach ($files as $file) {
337
-                            $resolvedValue[] = $file->getIdentifier();
338
-                        }
339
-                    } else {
340
-                        $files = FileReferenceService::getInstance()->findReferencedBy($propertyName, $this);
341
-                        if (!empty($files)) {
342
-                            $resolvedValue = current($files)->getIdentifier();
343
-                        }
344
-                    }
345
-
346
-                    // Reset value
347
-                    $result[$fieldName] = $resolvedValue;
348
-
349
-                } elseif (Tca::table($this->dataType)->field($fieldName)->hasRelation()) {
350
-                    $objects = $this[$fieldName];
351
-                    if (is_array($objects)) {
352
-                        $resolvedValue = array();
353
-                        foreach ($objects as $object) {
354
-                            /** @var $object Content */
355
-                            $labelField = Tca::table($object->getDataType())->getLabelField();
356
-                            $resolvedValue[] = $object[$labelField];
357
-                        }
358
-                    } elseif ($objects instanceof Content) {
359
-                        $labelField = Tca::table($objects->getDataType())->getLabelField();
360
-                        $resolvedValue = $objects[$labelField];
361
-                    }
362
-
363
-                    // Reset value
364
-                    $result[$fieldName] = $resolvedValue;
365
-                }
366
-            }
367
-        }
368
-
369
-        return $result;
370
-    }
371
-
372
-    /**
373
-     * Return the properties of this object.
374
-     *
375
-     * @return array
376
-     */
377
-    public function toProperties()
378
-    {
379
-        $result[] = 'uid';
380
-        $propertiesAndValues = json_decode(json_encode($this), true);
381
-
382
-        foreach ($propertiesAndValues as $propertyName => $value) {
383
-            $result[] = $propertyName;
384
-        }
385
-        return $result;
386
-    }
387
-
388
-    /**
389
-     * Return the properties of this object.
390
-     *
391
-     * @return array
392
-     */
393
-    public function toFields()
394
-    {
395
-        $result[] = 'uid';
396
-        $propertiesAndValues = json_decode(json_encode($this), true);
397
-
398
-        foreach ($propertiesAndValues as $propertyName => $value) {
399
-            $result[] = Property::name($propertyName)->of($this)->toFieldName();
400
-        }
401
-
402
-        return $result;
403
-    }
404
-
405
-    /**
406
-     * @return string
407
-     */
408
-    public function __toString()
409
-    {
410
-        $labelField = Tca::table($this->dataType)->getLabelField();
411
-        return $this[$labelField];
412
-    }
413
-
414
-    /**
415
-     * Remove fields according to BE User permission.
416
-     *
417
-     * @param $fields
418
-     * @return array
419
-     * @throws \Exception
420
-     */
421
-    protected function filterForBackendUser($fields)
422
-    {
423
-        if (!$this->getBackendUser()->isAdmin()) {
424
-            foreach ($fields as $key => $fieldName) {
425
-                if (Tca::table($this->dataType)->hasField($fieldName) && !Tca::table($this->dataType)->field($fieldName)->hasAccess()) {
426
-                    unset($fields[$key]);
427
-                }
428
-            }
429
-        }
430
-        return $fields;
431
-    }
432
-
433
-    /**
434
-     * Remove fields according to Grid configuration.
435
-     *
436
-     * @param $fields
437
-     * @return array
438
-     */
439
-    protected function filterForConfiguration($fields)
440
-    {
441
-
442
-        $excludedFields = Tca::grid($this->dataType)->getExcludedFields();
443
-        foreach ($fields as $key => $field) {
444
-            if (in_array($field, $excludedFields)) {
445
-                unset($fields[$key]);
446
-            }
447
-        }
448
-
449
-        return $fields;
450
-    }
451
-
452
-    /**
453
-     * Returns an instance of the current Backend User.
454
-     *
455
-     * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
456
-     */
457
-    protected function getBackendUser()
458
-    {
459
-        return $GLOBALS['BE_USER'];
460
-    }
461
-
462
-    /**
463
-     * Returns whether the current mode is Backend
464
-     *
465
-     * @return bool
466
-     */
467
-    protected function isBackendMode()
468
-    {
469
-        return TYPO3_MODE === 'BE';
470
-    }
26
+	/**
27
+	 * @var int
28
+	 */
29
+	protected $uid;
30
+
31
+	/**
32
+	 * @var string
33
+	 */
34
+	protected $dataType;
35
+
36
+	/**
37
+	 * Constructor for a Content object.
38
+	 *
39
+	 * @param string $dataType will basically correspond to a table name, e.g fe_users, tt_content, ...
40
+	 * @param array $contentData
41
+	 * @return \Fab\Vidi\Domain\Model\Content
42
+	 * @throws \InvalidArgumentException
43
+	 * @throws \Fab\Vidi\Exception\NotExistingClassException
44
+	 */
45
+	public function __construct($dataType, array $contentData = array())
46
+	{
47
+
48
+		$this->dataType = $dataType;
49
+		$this->uid = empty($contentData['uid']) ? NULL : (int)$contentData['uid'];
50
+
51
+		/** @var \Fab\Vidi\Tca\TableService $table */
52
+		$table = Tca::table($dataType);
53
+
54
+		// Initialize the array containing the allowed fields to be filled-in.
55
+		$fields = array('pid');
56
+
57
+		// If a creation time stamp has been defined for this data type.
58
+		if ($table->getTimeCreationField()) {
59
+			$fields[] = $table->getTimeCreationField();
60
+		}
61
+
62
+		// If an update time stamp has been defined for this data type.
63
+		if ($table->getTimeModificationField()) {
64
+			$fields[] = $table->getTimeModificationField();
65
+		}
66
+
67
+		// Merge the other fields allowed for this data type.
68
+		$fields = array_merge($fields, $table->getFields());
69
+
70
+		// Fetch excluded fields from the grid.
71
+		if ($this->isBackendMode()) {
72
+			$fields = $this->filterForConfiguration($fields);
73
+			$fields = $this->filterForBackendUser($fields);
74
+		}
75
+
76
+		// Get column to be displayed
77
+		foreach ($fields as $fieldName) {
78
+			if (array_key_exists($fieldName, $contentData)) {
79
+				$propertyName = Field::name($fieldName)->of($dataType)->toPropertyName();
80
+				$this->$propertyName = $contentData[$fieldName];
81
+			}
82
+		}
83
+	}
84
+
85
+	/**
86
+	 * Dispatches magic methods (findBy[Property]())
87
+	 *
88
+	 * @param string $methodName The name of the magic method
89
+	 * @param string $arguments The arguments of the magic method
90
+	 * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\UnsupportedMethodException
91
+	 * @return mixed
92
+	 * @api
93
+	 */
94
+	public function __call($methodName, $arguments)
95
+	{
96
+		$value = NULL;
97
+		if (substr($methodName, 0, 3) === 'get' && strlen($methodName) > 4) {
98
+			$propertyName = strtolower(substr(substr($methodName, 3), 0, 1)) . substr(substr($methodName, 3), 1);
99
+
100
+			$fieldName = Property::name($propertyName)->of($this)->toFieldName();
101
+			$field = Tca::table($this->dataType)->field($fieldName);
102
+
103
+			$value = $this->$propertyName;
104
+
105
+			// true means it is a relation and it is not yet resolved.
106
+			if ($this->hasRelation($propertyName) && is_scalar($this->$propertyName)) {
107
+				$value = $this->resolveRelation($propertyName);
108
+			} elseif ($field->getType() === FieldType::RADIO || $field->getType() === FieldType::SELECT) {
109
+
110
+				// Attempt to convert the value into a label for radio and select fields.
111
+				$label = Tca::table($this->getDataType())->field($fieldName)->getLabelForItem($value);
112
+				if ($label) {
113
+					$value = $label;
114
+				}
115
+			}
116
+
117
+		} elseif (substr($methodName, 0, 3) === 'set' && strlen($methodName) > 4 && isset($arguments[0])) {
118
+			$propertyName = strtolower(substr(substr($methodName, 3), 0, 1)) . substr(substr($methodName, 3), 1);
119
+			$this->$propertyName = $arguments[0];
120
+		}
121
+		return $value;
122
+	}
123
+
124
+	/**
125
+	 * Tell whether the property has a relation.
126
+	 *
127
+	 * @param string $propertyName
128
+	 * @return bool
129
+	 */
130
+	protected function hasRelation($propertyName)
131
+	{
132
+		$fieldName = Property::name($propertyName)->of($this)->toFieldName();
133
+		return Tca::table($this->dataType)->field($fieldName)->hasRelation();
134
+	}
135
+
136
+	/**
137
+	 * Try to "resolve" the property whether it has a relation.
138
+	 * If the property has not relation it simply returns the same value.
139
+	 *
140
+	 * @throws \RuntimeException
141
+	 * @param string $propertyName
142
+	 * @return mixed
143
+	 */
144
+	protected function resolveRelation($propertyName)
145
+	{
146
+
147
+		// Convert property name to field name and get the foreign data type.
148
+		$fieldName = Property::name($propertyName)->of($this)->toFieldName();
149
+		$foreignDataType = Tca::table($this->dataType)->field($fieldName)->relationDataType();
150
+
151
+		// Get the foreign repository instance form the factory
152
+		/** @var \Fab\Vidi\Domain\Repository\ContentRepository $foreignContentRepository */
153
+		$foreignContentRepository = ContentRepositoryFactory::getInstance($foreignDataType, $fieldName);
154
+
155
+		if (Tca::table($this->dataType)->field($fieldName)->hasRelationWithCommaSeparatedValues()) {
156
+
157
+			// Fetch values from repository
158
+			$values = GeneralUtility::trimExplode(',', $this->$propertyName);
159
+			$this->$propertyName = $foreignContentRepository->findIn('uid', $values);
160
+		} elseif (Tca::table($this->dataType)->field($fieldName)->hasMany()) {
161
+			// Include relation many-to-many and one-to-many
162
+			// Tca::table($this->dataType)->field($fieldName)->hasRelationOneToMany()
163
+			// Tca::table($this->dataType)->field($fieldName)->hasRelationManyToMany()
164
+
165
+			$foreignFieldName = Tca::table($this->dataType)->field($fieldName)->getForeignField();
166
+			if (empty($foreignFieldName)) {
167
+				$message = sprintf('Missing "foreign_field" key for field "%s" in table "%s".',
168
+					$fieldName,
169
+					$this->dataType
170
+				);
171
+				throw new \RuntimeException($message, 1376149186);
172
+			}
173
+
174
+			// Fetch values from repository.
175
+			$foreignPropertyName = Field::name($foreignFieldName)->of($this)->toPropertyName();
176
+			$findByProperty = 'findBy' . ucfirst($foreignPropertyName);
177
+
178
+			// Date picker (type == group) are special fields because property path must contain the table name
179
+			// to determine the relation type. Example for sys_category, property path will look like "items.sys_file"
180
+			$propertyValue = $this->uid;
181
+			if (Tca::table($foreignDataType)->field($foreignFieldName)->isGroup()) {
182
+				$propertyValue = $this->dataType . '.' . $this->uid;
183
+			}
184
+
185
+			$this->$propertyName = $foreignContentRepository->$findByProperty($propertyValue);
186
+
187
+		} elseif (Tca::table($this->dataType)->field($fieldName)->hasOne()) {
188
+
189
+			$fieldConfiguration = Tca::table($this->dataType)->field($fieldName)->getConfiguration();
190
+
191
+			// First case, we are on the "good side" of the relation, just query the repository
192
+			if (empty($fieldConfiguration['foreign_field'])) {
193
+				$this->$propertyName = $foreignContentRepository->findByUid($this->$propertyName);
194
+			} else {
195
+				// Second case, we are the "bad side" of the relation, query the foreign repository
196
+				// e.g. in case of one-to-one relation.
197
+
198
+				// We must query the opposite side to get the identifier of the foreign object.
199
+				$foreignDataType = Tca::table($this->dataType)->field($fieldName)->getForeignTable();
200
+				$foreignField = Tca::table($this->dataType)->field($fieldName)->getForeignField();
201
+				$foreignContentRepository = ContentRepositoryFactory::getInstance($foreignDataType);
202
+				$find = 'findOneBy' . GeneralUtility::underscoredToUpperCamelCase($foreignField);
203
+
204
+				/** @var Content $foreignObject */
205
+				$this->$propertyName = $foreignContentRepository->$find($this->getUid());
206
+			}
207
+
208
+		}
209
+		return $this->$propertyName;
210
+	}
211
+
212
+	/**
213
+	 * @return int
214
+	 */
215
+	public function getUid()
216
+	{
217
+		return $this->uid;
218
+	}
219
+
220
+	/**
221
+	 * @return string
222
+	 */
223
+	public function getDataType()
224
+	{
225
+		return $this->dataType;
226
+	}
227
+
228
+	/**
229
+	 * Whether a offset exists
230
+	 *
231
+	 * @link http://php.net/manual/en/arrayaccess.offsetexists.php
232
+	 * @param mixed $offset
233
+	 * @return boolean true on success or false on failure.
234
+	 * @throws \RuntimeException
235
+	 * @throws \InvalidArgumentException
236
+	 */
237
+	public function offsetExists($offset)
238
+	{
239
+		$offset = Field::name($offset)->of($this)->toPropertyName();
240
+		return isset($this->$offset);
241
+	}
242
+
243
+	/**
244
+	 * Offset to retrieve
245
+	 *
246
+	 * @link http://php.net/manual/en/arrayaccess.offsetget.php
247
+	 * @param mixed $offset
248
+	 * @return mixed Can return all value types.
249
+	 * @throws \RuntimeException
250
+	 * @throws \InvalidArgumentException
251
+	 */
252
+	public function offsetGet($offset)
253
+	{
254
+		$offset = Field::name($offset)->of($this)->toPropertyName();
255
+		$getter = 'get' . ucfirst($offset);
256
+		return $this->$getter();
257
+	}
258
+
259
+	/**
260
+	 * Offset to set
261
+	 *
262
+	 * @link http://php.net/manual/en/arrayaccess.offsetset.php
263
+	 * @param mixed $offset
264
+	 * @param mixed $value
265
+	 * @return $this
266
+	 * @throws \RuntimeException
267
+	 * @throws \InvalidArgumentException
268
+	 */
269
+	public function offsetSet($offset, $value)
270
+	{
271
+		$offset = Field::name($offset)->of($this)->toPropertyName();
272
+		$setter = 'set' . ucfirst($offset);
273
+		$this->$setter($value);
274
+		return $this;
275
+	}
276
+
277
+	/**
278
+	 * Offset to unset
279
+	 *
280
+	 * @link http://php.net/manual/en/arrayaccess.offsetunset.php
281
+	 * @param mixed $offset
282
+	 * @throws NotImplementedException
283
+	 * @return void
284
+	 */
285
+	public function offsetUnset($offset)
286
+	{
287
+		$message = 'Un-setting value for Array object is not supported';
288
+		throw new NotImplementedException($message, 1376132306);
289
+	}
290
+
291
+	/**
292
+	 * Convert this to array
293
+	 *
294
+	 * @return array
295
+	 * @throws \InvalidArgumentException
296
+	 */
297
+	public function toArray()
298
+	{
299
+		$result['uid'] = $this->uid;
300
+		$propertiesAndValues = json_decode(json_encode($this), true);
301
+
302
+		foreach ($propertiesAndValues as $propertyName => $value) {
303
+			$fieldName = Property::name($propertyName)->of($this)->toFieldName();
304
+			$result[$fieldName] = $value;
305
+		}
306
+
307
+		return $result;
308
+	}
309
+
310
+	/**
311
+	 * Convert this object to an array containing the resolved values.
312
+	 *
313
+	 * @param bool $resolveRelations
314
+	 * @return array
315
+	 * @throws \Exception
316
+	 */
317
+	public function toValues($resolveRelations = true)
318
+	{
319
+		$result['uid'] = $this->uid;
320
+		$propertiesAndValues = json_decode(json_encode($this), true);
321
+
322
+		foreach ($propertiesAndValues as $propertyName => $value) {
323
+			$fieldName = Property::name($propertyName)->of($this)->toFieldName();
324
+
325
+			$result[$fieldName] = $value;
326
+			if ($resolveRelations) {
327
+				$field = Tca::table($this->dataType)->field($fieldName);
328
+
329
+				$resolvedValue = '';
330
+				if ($field->getType() === FieldType::FILE) {
331
+
332
+					if ($field->hasMany()) {
333
+						$files = FileReferenceService::getInstance()->findReferencedBy($propertyName, $this);
334
+
335
+						$resolvedValue = array();
336
+						foreach ($files as $file) {
337
+							$resolvedValue[] = $file->getIdentifier();
338
+						}
339
+					} else {
340
+						$files = FileReferenceService::getInstance()->findReferencedBy($propertyName, $this);
341
+						if (!empty($files)) {
342
+							$resolvedValue = current($files)->getIdentifier();
343
+						}
344
+					}
345
+
346
+					// Reset value
347
+					$result[$fieldName] = $resolvedValue;
348
+
349
+				} elseif (Tca::table($this->dataType)->field($fieldName)->hasRelation()) {
350
+					$objects = $this[$fieldName];
351
+					if (is_array($objects)) {
352
+						$resolvedValue = array();
353
+						foreach ($objects as $object) {
354
+							/** @var $object Content */
355
+							$labelField = Tca::table($object->getDataType())->getLabelField();
356
+							$resolvedValue[] = $object[$labelField];
357
+						}
358
+					} elseif ($objects instanceof Content) {
359
+						$labelField = Tca::table($objects->getDataType())->getLabelField();
360
+						$resolvedValue = $objects[$labelField];
361
+					}
362
+
363
+					// Reset value
364
+					$result[$fieldName] = $resolvedValue;
365
+				}
366
+			}
367
+		}
368
+
369
+		return $result;
370
+	}
371
+
372
+	/**
373
+	 * Return the properties of this object.
374
+	 *
375
+	 * @return array
376
+	 */
377
+	public function toProperties()
378
+	{
379
+		$result[] = 'uid';
380
+		$propertiesAndValues = json_decode(json_encode($this), true);
381
+
382
+		foreach ($propertiesAndValues as $propertyName => $value) {
383
+			$result[] = $propertyName;
384
+		}
385
+		return $result;
386
+	}
387
+
388
+	/**
389
+	 * Return the properties of this object.
390
+	 *
391
+	 * @return array
392
+	 */
393
+	public function toFields()
394
+	{
395
+		$result[] = 'uid';
396
+		$propertiesAndValues = json_decode(json_encode($this), true);
397
+
398
+		foreach ($propertiesAndValues as $propertyName => $value) {
399
+			$result[] = Property::name($propertyName)->of($this)->toFieldName();
400
+		}
401
+
402
+		return $result;
403
+	}
404
+
405
+	/**
406
+	 * @return string
407
+	 */
408
+	public function __toString()
409
+	{
410
+		$labelField = Tca::table($this->dataType)->getLabelField();
411
+		return $this[$labelField];
412
+	}
413
+
414
+	/**
415
+	 * Remove fields according to BE User permission.
416
+	 *
417
+	 * @param $fields
418
+	 * @return array
419
+	 * @throws \Exception
420
+	 */
421
+	protected function filterForBackendUser($fields)
422
+	{
423
+		if (!$this->getBackendUser()->isAdmin()) {
424
+			foreach ($fields as $key => $fieldName) {
425
+				if (Tca::table($this->dataType)->hasField($fieldName) && !Tca::table($this->dataType)->field($fieldName)->hasAccess()) {
426
+					unset($fields[$key]);
427
+				}
428
+			}
429
+		}
430
+		return $fields;
431
+	}
432
+
433
+	/**
434
+	 * Remove fields according to Grid configuration.
435
+	 *
436
+	 * @param $fields
437
+	 * @return array
438
+	 */
439
+	protected function filterForConfiguration($fields)
440
+	{
441
+
442
+		$excludedFields = Tca::grid($this->dataType)->getExcludedFields();
443
+		foreach ($fields as $key => $field) {
444
+			if (in_array($field, $excludedFields)) {
445
+				unset($fields[$key]);
446
+			}
447
+		}
448
+
449
+		return $fields;
450
+	}
451
+
452
+	/**
453
+	 * Returns an instance of the current Backend User.
454
+	 *
455
+	 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
456
+	 */
457
+	protected function getBackendUser()
458
+	{
459
+		return $GLOBALS['BE_USER'];
460
+	}
461
+
462
+	/**
463
+	 * Returns whether the current mode is Backend
464
+	 *
465
+	 * @return bool
466
+	 */
467
+	protected function isBackendMode()
468
+	{
469
+		return TYPO3_MODE === 'BE';
470
+	}
471 471
 
472 472
 }
Please login to merge, or discard this patch.
Classes/Grid/GridAnalyserService.php 2 patches
Doc Comments   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -81,7 +81,7 @@  discard block
 block discarded – undo
81 81
      *
82 82
      * @param string $tableName
83 83
      * @param string $fieldName
84
-     * @return array
84
+     * @return string[]
85 85
      */
86 86
     protected function checkRelationManyToMany($tableName, $fieldName)
87 87
     {
@@ -115,7 +115,7 @@  discard block
 block discarded – undo
115 115
      * @param string $tableName
116 116
      * @param string $fieldName
117 117
      * @param string $relationType
118
-     * @return array
118
+     * @return string[]
119 119
      */
120 120
     protected function checkRelationOf($tableName, $fieldName, $relationType)
121 121
     {
Please login to merge, or discard this patch.
Indentation   +102 added lines, -102 removed lines patch added patch discarded remove patch
@@ -22,114 +22,114 @@
 block discarded – undo
22 22
 class GridAnalyserService
23 23
 {
24 24
 
25
-    /**
26
-     * Check relation for table.
27
-     *
28
-     * @param $tableName
29
-     * @return array
30
-     */
31
-    public function checkRelationForTable($tableName)
32
-    {
25
+	/**
26
+	 * Check relation for table.
27
+	 *
28
+	 * @param $tableName
29
+	 * @return array
30
+	 */
31
+	public function checkRelationForTable($tableName)
32
+	{
33 33
 
34
-        $relations = array();
35
-        $table = Tca::table($tableName);
34
+		$relations = array();
35
+		$table = Tca::table($tableName);
36 36
 
37
-        $missingOppositionRelationMessage = <<<EOF
37
+		$missingOppositionRelationMessage = <<<EOF
38 38
 
39 39
   WARNING! Could not define relation precisely. This is not necessarily a problem
40 40
   if the opposite relation is not required in a Grid. But consider adding the opposite
41 41
   TCA configuration if so.
42 42
 EOF;
43 43
 
44
-        foreach (Tca::grid($tableName)->getFields() as $fieldName => $configuration) {
45
-
46
-            if ($table->hasField($fieldName)) {
47
-                if ($table->field($fieldName)->hasMany()) {
48
-                    if ($table->field($fieldName)->hasRelationWithCommaSeparatedValues()) {
49
-                        $_relations = $this->checkRelationOf($tableName, $fieldName, 'comma separated values');
50
-                        $relations = array_merge($relations, $_relations);
51
-                    } elseif ($table->field($fieldName)->hasRelationManyToMany()) {
52
-                        $_relations = $this->checkRelationManyToMany($tableName, $fieldName);
53
-                        $relations = array_merge($relations, $_relations);
54
-
55
-                    } elseif ($table->field($fieldName)->hasRelationOneToMany()) {
56
-                        $_relations = $this->checkRelationOf($tableName, $fieldName, 'one-to-many');
57
-                        $relations = array_merge($relations, $_relations);
58
-                    } else {
59
-                        $relations[] = sprintf('* field: "%s", relation: ?-to-many%s', $fieldName, $missingOppositionRelationMessage);
60
-                    }
61
-                    $relations[] = '';
62
-                } elseif ($table->field($fieldName)->hasOne()) {
63
-
64
-                    if ($table->field($fieldName)->hasRelationOneToOne()) {
65
-                        $relations[] = sprintf('* one-to-one "%s"', $fieldName);
66
-                    } elseif ($table->field($fieldName)->hasRelationManyToOne()) {
67
-                        $_relations = $this->checkRelationOf($tableName, $fieldName, 'many-to-one');
68
-                        $relations = array_merge($relations, $_relations);
69
-                    } else {
70
-                        $relations[] = sprintf('* field: "%s", relation: ?-to-one%s', $fieldName, $missingOppositionRelationMessage);
71
-                    }
72
-                    $relations[] = '';
73
-                }
74
-            }
75
-        }
76
-        return $relations;
77
-    }
78
-
79
-    /**
80
-     * Convenience method for printing out relation many-to-many.
81
-     *
82
-     * @param string $tableName
83
-     * @param string $fieldName
84
-     * @return array
85
-     */
86
-    protected function checkRelationManyToMany($tableName, $fieldName)
87
-    {
88
-
89
-        $output = array();
90
-
91
-        $table = Tca::table($tableName);
92
-        $output[] = sprintf('* field: "%s", relation: many-to-many', $fieldName);
93
-
94
-        $foreignTable = $table->field($fieldName)->getForeignTable();
95
-        $manyToManyTable = $table->field($fieldName)->getManyToManyTable();
96
-        $foreignField = $table->field($fieldName)->getForeignField();
97
-
98
-        if (!$foreignField) {
99
-            $output[] = sprintf('  ERROR! Can not found foreign field for "%s". Perhaps missing opposite configuration?', $fieldName);
100
-        } elseif (!$foreignTable) {
101
-            $output[] = sprintf('  ERROR! Can not found foreign table for "%s". Perhaps missing opposite configuration?', $fieldName);
102
-        } elseif (!$manyToManyTable) {
103
-            $output[] = sprintf('  ERROR! Can not found relation table (MM) for "%s". Perhaps missing opposite configuration?', $fieldName);
104
-        } else {
105
-            $output[] = sprintf('  %s.%s <--> %s <--> %s.%s', $tableName, $fieldName, $manyToManyTable, $foreignTable, $foreignField);
106
-        }
107
-
108
-        $output[] = '';
109
-        return $output;
110
-    }
111
-
112
-    /**
113
-     * Convenience method for printing out relation.
114
-     *
115
-     * @param string $tableName
116
-     * @param string $fieldName
117
-     * @param string $relationType
118
-     * @return array
119
-     */
120
-    protected function checkRelationOf($tableName, $fieldName, $relationType)
121
-    {
122
-
123
-        $output = array();
124
-
125
-        $table = Tca::table($tableName);
126
-        $output[] = sprintf('* field: "%s", relation: %s', $fieldName, $relationType);
127
-
128
-        $foreignTable = $table->field($fieldName)->getForeignTable();
129
-        $foreignField = $table->field($fieldName)->getForeignField();
130
-        $output[] = sprintf('  %s.%s <--> %s.%s', $tableName, $fieldName, $foreignTable, $foreignField);
131
-        $output[] = '';
132
-
133
-        return $output;
134
-    }
44
+		foreach (Tca::grid($tableName)->getFields() as $fieldName => $configuration) {
45
+
46
+			if ($table->hasField($fieldName)) {
47
+				if ($table->field($fieldName)->hasMany()) {
48
+					if ($table->field($fieldName)->hasRelationWithCommaSeparatedValues()) {
49
+						$_relations = $this->checkRelationOf($tableName, $fieldName, 'comma separated values');
50
+						$relations = array_merge($relations, $_relations);
51
+					} elseif ($table->field($fieldName)->hasRelationManyToMany()) {
52
+						$_relations = $this->checkRelationManyToMany($tableName, $fieldName);
53
+						$relations = array_merge($relations, $_relations);
54
+
55
+					} elseif ($table->field($fieldName)->hasRelationOneToMany()) {
56
+						$_relations = $this->checkRelationOf($tableName, $fieldName, 'one-to-many');
57
+						$relations = array_merge($relations, $_relations);
58
+					} else {
59
+						$relations[] = sprintf('* field: "%s", relation: ?-to-many%s', $fieldName, $missingOppositionRelationMessage);
60
+					}
61
+					$relations[] = '';
62
+				} elseif ($table->field($fieldName)->hasOne()) {
63
+
64
+					if ($table->field($fieldName)->hasRelationOneToOne()) {
65
+						$relations[] = sprintf('* one-to-one "%s"', $fieldName);
66
+					} elseif ($table->field($fieldName)->hasRelationManyToOne()) {
67
+						$_relations = $this->checkRelationOf($tableName, $fieldName, 'many-to-one');
68
+						$relations = array_merge($relations, $_relations);
69
+					} else {
70
+						$relations[] = sprintf('* field: "%s", relation: ?-to-one%s', $fieldName, $missingOppositionRelationMessage);
71
+					}
72
+					$relations[] = '';
73
+				}
74
+			}
75
+		}
76
+		return $relations;
77
+	}
78
+
79
+	/**
80
+	 * Convenience method for printing out relation many-to-many.
81
+	 *
82
+	 * @param string $tableName
83
+	 * @param string $fieldName
84
+	 * @return array
85
+	 */
86
+	protected function checkRelationManyToMany($tableName, $fieldName)
87
+	{
88
+
89
+		$output = array();
90
+
91
+		$table = Tca::table($tableName);
92
+		$output[] = sprintf('* field: "%s", relation: many-to-many', $fieldName);
93
+
94
+		$foreignTable = $table->field($fieldName)->getForeignTable();
95
+		$manyToManyTable = $table->field($fieldName)->getManyToManyTable();
96
+		$foreignField = $table->field($fieldName)->getForeignField();
97
+
98
+		if (!$foreignField) {
99
+			$output[] = sprintf('  ERROR! Can not found foreign field for "%s". Perhaps missing opposite configuration?', $fieldName);
100
+		} elseif (!$foreignTable) {
101
+			$output[] = sprintf('  ERROR! Can not found foreign table for "%s". Perhaps missing opposite configuration?', $fieldName);
102
+		} elseif (!$manyToManyTable) {
103
+			$output[] = sprintf('  ERROR! Can not found relation table (MM) for "%s". Perhaps missing opposite configuration?', $fieldName);
104
+		} else {
105
+			$output[] = sprintf('  %s.%s <--> %s <--> %s.%s', $tableName, $fieldName, $manyToManyTable, $foreignTable, $foreignField);
106
+		}
107
+
108
+		$output[] = '';
109
+		return $output;
110
+	}
111
+
112
+	/**
113
+	 * Convenience method for printing out relation.
114
+	 *
115
+	 * @param string $tableName
116
+	 * @param string $fieldName
117
+	 * @param string $relationType
118
+	 * @return array
119
+	 */
120
+	protected function checkRelationOf($tableName, $fieldName, $relationType)
121
+	{
122
+
123
+		$output = array();
124
+
125
+		$table = Tca::table($tableName);
126
+		$output[] = sprintf('* field: "%s", relation: %s', $fieldName, $relationType);
127
+
128
+		$foreignTable = $table->field($fieldName)->getForeignTable();
129
+		$foreignField = $table->field($fieldName)->getForeignField();
130
+		$output[] = sprintf('  %s.%s <--> %s.%s', $tableName, $fieldName, $foreignTable, $foreignField);
131
+		$output[] = '';
132
+
133
+		return $output;
134
+	}
135 135
 }
Please login to merge, or discard this patch.
Classes/Language/LanguageService.php 2 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -109,7 +109,7 @@
 block discarded – undo
109 109
      *
110 110
      * @param Content $object
111 111
      * @param int $language
112
-     * @return string
112
+     * @return boolean
113 113
      */
114 114
     public function hasLocalization(Content $object, $language)
115 115
     {
Please login to merge, or discard this patch.
Indentation   +173 added lines, -173 removed lines patch added patch discarded remove patch
@@ -25,178 +25,178 @@
 block discarded – undo
25 25
 class LanguageService implements SingletonInterface
26 26
 {
27 27
 
28
-    /**
29
-     * @var array
30
-     */
31
-    protected $languages;
32
-
33
-    /**
34
-     * @var array
35
-     */
36
-    protected $defaultIcon;
37
-
38
-    /**
39
-     * Store the localized records to boost up performance.
40
-     *
41
-     * @var array
42
-     */
43
-    protected $localizedRecordStorage;
44
-
45
-    /**
46
-     * Returns available language records.
47
-     * The method stores the records in the property to speed up the process as the method can be often called.
48
-     *
49
-     * @return array
50
-     */
51
-    public function getLanguages()
52
-    {
53
-        if (is_null($this->languages)) {
54
-
55
-            $tableName = 'sys_language';
56
-
57
-            $clause = '1 = 1';
58
-            $clause .= BackendUtility::deleteClause($tableName);
59
-            $clause .= BackendUtility::BEenableFields($tableName);
60
-            $this->languages = $this->getDatabaseConnection()->exec_SELECTgetRows('*', $tableName, $clause);
61
-        }
62
-        return $this->languages;
63
-    }
64
-
65
-    /**
66
-     * Returns a localized record according to a Content object and a language identifier.
67
-     * Notice! This method does not overlay anything but simply returns the raw localized record.
68
-     *
69
-     * @param Content $object
70
-     * @param int $language
71
-     * @return Content
72
-     */
73
-    public function getLocalizedContent(Content $object, $language)
74
-    {
75
-
76
-        // We want to cache data per Content object. Retrieve the Object hash.
77
-        $objectHash = spl_object_hash($object);
78
-
79
-        // Initialize the storage
80
-        if (empty($this->localizedRecordStorage[$objectHash])) {
81
-            $this->localizedRecordStorage[$objectHash] = array();
82
-        }
83
-
84
-        if (empty($this->localizedRecordStorage[$objectHash][$language])) {
85
-
86
-            $clause = sprintf('%s = %s AND %s = %s',
87
-                Tca::table($object)->getLanguageParentField(), // e.g. l10n_parent
88
-                $object->getUid(),
89
-                Tca::table($object)->getLanguageField(), // e.g. sys_language_uid
90
-                $language
91
-            );
92
-
93
-            $clause .= BackendUtility::deleteClause($object->getDataType());
94
-            $localizedRecord = $this->getDatabaseConnection()->exec_SELECTgetSingleRow('*', $object->getDataType(), $clause);
95
-
96
-            if ($localizedRecord) {
97
-                $localizedContent = GeneralUtility::makeInstance('Fab\Vidi\Domain\Model\Content', $object->getDataType(), $localizedRecord);
98
-                $this->localizedRecordStorage[$objectHash][$language] = $localizedContent;
99
-            } else {
100
-                $this->localizedRecordStorage[$objectHash][$language] = array(); // We want an array at least, even if empty.
101
-            }
102
-        }
103
-
104
-        return $this->localizedRecordStorage[$objectHash][$language];
105
-    }
106
-
107
-    /**
108
-     * Tell whether the given Content object has a localization.
109
-     *
110
-     * @param Content $object
111
-     * @param int $language
112
-     * @return string
113
-     */
114
-    public function hasLocalization(Content $object, $language)
115
-    {
116
-        $localizedRecord = $this->getLocalizedContent($object, $language);
117
-        return !empty($localizedRecord);
118
-    }
119
-
120
-    /**
121
-     * Returns a localized field according to a Content object and a language identifier.
122
-     * Notice! If there is not translation, simply returns an empty string.
123
-     *
124
-     * @param Content $object
125
-     * @param int $language
126
-     * @param string $fieldName
127
-     * @return string
128
-     */
129
-    public function getLocalizedFieldName(Content $object, $language, $fieldName)
130
-    {
131
-        $localizedRecord = $this->getLocalizedContent($object, $language);
132
-        return empty($localizedRecord) ? '' : $localizedRecord[$fieldName];
133
-    }
134
-
135
-    /**
136
-     * Returns the default language configured by TSConfig.
137
-     *
138
-     * @return array
139
-     */
140
-    public function getDefaultFlag()
141
-    {
142
-
143
-        if (is_null($this->defaultIcon)) {
144
-
145
-            $defaultFlag = ''; // default value
146
-
147
-            $tsConfig = BackendUtility::getModTSconfig(0, 'mod.SHARED');
148
-
149
-            // Fallback non sprite-configuration
150
-            if (($pos = strrpos($tsConfig['properties']['defaultLanguageFlag'], '.')) !== FALSE) {
151
-                $defaultFlag = substr($tsConfig['properties']['defaultLanguageFlag'], 0, $pos);
152
-            }
153
-
154
-            $this->defaultIcon = $defaultFlag;
155
-        }
156
-
157
-        return $this->defaultIcon;
158
-    }
159
-
160
-    /**
161
-     * Returns whether the system includes language records.
162
-     *
163
-     * @return bool
164
-     */
165
-    public function hasLanguages()
166
-    {
167
-        $languages = $this->getLanguages();
168
-        return !empty($languages);
169
-    }
170
-
171
-    /**
172
-     * Tell whether the given language exists.
173
-     *
174
-     * @param int $language
175
-     * @return bool
176
-     */
177
-    public function languageExists($language)
178
-    {
179
-        $languages = $this->getLanguages();
180
-
181
-        $LanguageExists = FALSE;
182
-        foreach ($languages as $_language) {
183
-            if ((int)$_language['uid'] === (int)$language) {
184
-                $LanguageExists = TRUE;
185
-                break;
186
-            }
187
-        }
188
-
189
-        return $LanguageExists;
190
-    }
191
-
192
-    /**
193
-     * Returns a pointer to the database.
194
-     *
195
-     * @return \TYPO3\CMS\Core\Database\DatabaseConnection
196
-     */
197
-    protected function getDatabaseConnection()
198
-    {
199
-        return $GLOBALS['TYPO3_DB'];
200
-    }
28
+	/**
29
+	 * @var array
30
+	 */
31
+	protected $languages;
32
+
33
+	/**
34
+	 * @var array
35
+	 */
36
+	protected $defaultIcon;
37
+
38
+	/**
39
+	 * Store the localized records to boost up performance.
40
+	 *
41
+	 * @var array
42
+	 */
43
+	protected $localizedRecordStorage;
44
+
45
+	/**
46
+	 * Returns available language records.
47
+	 * The method stores the records in the property to speed up the process as the method can be often called.
48
+	 *
49
+	 * @return array
50
+	 */
51
+	public function getLanguages()
52
+	{
53
+		if (is_null($this->languages)) {
54
+
55
+			$tableName = 'sys_language';
56
+
57
+			$clause = '1 = 1';
58
+			$clause .= BackendUtility::deleteClause($tableName);
59
+			$clause .= BackendUtility::BEenableFields($tableName);
60
+			$this->languages = $this->getDatabaseConnection()->exec_SELECTgetRows('*', $tableName, $clause);
61
+		}
62
+		return $this->languages;
63
+	}
64
+
65
+	/**
66
+	 * Returns a localized record according to a Content object and a language identifier.
67
+	 * Notice! This method does not overlay anything but simply returns the raw localized record.
68
+	 *
69
+	 * @param Content $object
70
+	 * @param int $language
71
+	 * @return Content
72
+	 */
73
+	public function getLocalizedContent(Content $object, $language)
74
+	{
75
+
76
+		// We want to cache data per Content object. Retrieve the Object hash.
77
+		$objectHash = spl_object_hash($object);
78
+
79
+		// Initialize the storage
80
+		if (empty($this->localizedRecordStorage[$objectHash])) {
81
+			$this->localizedRecordStorage[$objectHash] = array();
82
+		}
83
+
84
+		if (empty($this->localizedRecordStorage[$objectHash][$language])) {
85
+
86
+			$clause = sprintf('%s = %s AND %s = %s',
87
+				Tca::table($object)->getLanguageParentField(), // e.g. l10n_parent
88
+				$object->getUid(),
89
+				Tca::table($object)->getLanguageField(), // e.g. sys_language_uid
90
+				$language
91
+			);
92
+
93
+			$clause .= BackendUtility::deleteClause($object->getDataType());
94
+			$localizedRecord = $this->getDatabaseConnection()->exec_SELECTgetSingleRow('*', $object->getDataType(), $clause);
95
+
96
+			if ($localizedRecord) {
97
+				$localizedContent = GeneralUtility::makeInstance('Fab\Vidi\Domain\Model\Content', $object->getDataType(), $localizedRecord);
98
+				$this->localizedRecordStorage[$objectHash][$language] = $localizedContent;
99
+			} else {
100
+				$this->localizedRecordStorage[$objectHash][$language] = array(); // We want an array at least, even if empty.
101
+			}
102
+		}
103
+
104
+		return $this->localizedRecordStorage[$objectHash][$language];
105
+	}
106
+
107
+	/**
108
+	 * Tell whether the given Content object has a localization.
109
+	 *
110
+	 * @param Content $object
111
+	 * @param int $language
112
+	 * @return string
113
+	 */
114
+	public function hasLocalization(Content $object, $language)
115
+	{
116
+		$localizedRecord = $this->getLocalizedContent($object, $language);
117
+		return !empty($localizedRecord);
118
+	}
119
+
120
+	/**
121
+	 * Returns a localized field according to a Content object and a language identifier.
122
+	 * Notice! If there is not translation, simply returns an empty string.
123
+	 *
124
+	 * @param Content $object
125
+	 * @param int $language
126
+	 * @param string $fieldName
127
+	 * @return string
128
+	 */
129
+	public function getLocalizedFieldName(Content $object, $language, $fieldName)
130
+	{
131
+		$localizedRecord = $this->getLocalizedContent($object, $language);
132
+		return empty($localizedRecord) ? '' : $localizedRecord[$fieldName];
133
+	}
134
+
135
+	/**
136
+	 * Returns the default language configured by TSConfig.
137
+	 *
138
+	 * @return array
139
+	 */
140
+	public function getDefaultFlag()
141
+	{
142
+
143
+		if (is_null($this->defaultIcon)) {
144
+
145
+			$defaultFlag = ''; // default value
146
+
147
+			$tsConfig = BackendUtility::getModTSconfig(0, 'mod.SHARED');
148
+
149
+			// Fallback non sprite-configuration
150
+			if (($pos = strrpos($tsConfig['properties']['defaultLanguageFlag'], '.')) !== FALSE) {
151
+				$defaultFlag = substr($tsConfig['properties']['defaultLanguageFlag'], 0, $pos);
152
+			}
153
+
154
+			$this->defaultIcon = $defaultFlag;
155
+		}
156
+
157
+		return $this->defaultIcon;
158
+	}
159
+
160
+	/**
161
+	 * Returns whether the system includes language records.
162
+	 *
163
+	 * @return bool
164
+	 */
165
+	public function hasLanguages()
166
+	{
167
+		$languages = $this->getLanguages();
168
+		return !empty($languages);
169
+	}
170
+
171
+	/**
172
+	 * Tell whether the given language exists.
173
+	 *
174
+	 * @param int $language
175
+	 * @return bool
176
+	 */
177
+	public function languageExists($language)
178
+	{
179
+		$languages = $this->getLanguages();
180
+
181
+		$LanguageExists = FALSE;
182
+		foreach ($languages as $_language) {
183
+			if ((int)$_language['uid'] === (int)$language) {
184
+				$LanguageExists = TRUE;
185
+				break;
186
+			}
187
+		}
188
+
189
+		return $LanguageExists;
190
+	}
191
+
192
+	/**
193
+	 * Returns a pointer to the database.
194
+	 *
195
+	 * @return \TYPO3\CMS\Core\Database\DatabaseConnection
196
+	 */
197
+	protected function getDatabaseConnection()
198
+	{
199
+		return $GLOBALS['TYPO3_DB'];
200
+	}
201 201
 
202 202
 }
Please login to merge, or discard this patch.
Classes/Persistence/Query.php 3 patches
Doc Comments   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -290,7 +290,7 @@  discard block
 block discarded – undo
290 290
      * 'bar' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_DESCENDING
291 291
      * )
292 292
      *
293
-     * @return array
293
+     * @return integer
294 294
      * @api
295 295
      */
296 296
     public function getOrderings()
@@ -483,7 +483,7 @@  discard block
 block discarded – undo
483 483
      * Returns a like criterion used for matching objects against a query
484 484
      *
485 485
      * @param string $propertyName The name of the property to compare against
486
-     * @param mixed $operand The value to compare with
486
+     * @param string $operand The value to compare with
487 487
      * @param boolean $caseSensitive Whether the matching should be done case-sensitive
488 488
      * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
489 489
      * @api
Please login to merge, or discard this patch.
Indentation   +644 added lines, -644 removed lines patch added patch discarded remove patch
@@ -29,649 +29,649 @@
 block discarded – undo
29 29
 class Query implements QueryInterface
30 30
 {
31 31
 
32
-    /**
33
-     * An inner join.
34
-     */
35
-    const JCR_JOIN_TYPE_INNER = '{http://www.jcp.org/jcr/1.0}joinTypeInner';
36
-
37
-    /**
38
-     * A left-outer join.
39
-     */
40
-    const JCR_JOIN_TYPE_LEFT_OUTER = '{http://www.jcp.org/jcr/1.0}joinTypeLeftOuter';
41
-
42
-    /**
43
-     * A right-outer join.
44
-     */
45
-    const JCR_JOIN_TYPE_RIGHT_OUTER = '{http://www.jcp.org/jcr/1.0}joinTypeRightOuter';
46
-
47
-    /**
48
-     * Charset of strings in QOM
49
-     */
50
-    const CHARSET = 'utf-8';
51
-
52
-    /**
53
-     * @var string
54
-     */
55
-    protected $sourceFieldName;
56
-
57
-    /**
58
-     * @var string
59
-     */
60
-    protected $type;
61
-
62
-    /**
63
-     * @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
64
-     */
65
-    protected $objectManager;
66
-
67
-    /**
68
-     * @var \TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface
69
-     */
70
-    protected $persistenceManager;
71
-
72
-    /**
73
-     * @var \TYPO3\CMS\Extbase\Persistence\Generic\Qom\QueryObjectModelFactory
74
-     */
75
-    protected $qomFactory;
76
-
77
-    /**
78
-     * @var \TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInterface
79
-     */
80
-    protected $source;
81
-
82
-    /**
83
-     * @var ConstraintInterface
84
-     */
85
-    protected $constraint;
86
-
87
-    /**
88
-     * @var \TYPO3\CMS\Extbase\Persistence\Generic\Qom\Statement
89
-     */
90
-    protected $statement;
91
-
92
-    /**
93
-     * @var int
94
-     */
95
-    protected $orderings = array();
96
-
97
-    /**
98
-     * @var int
99
-     */
100
-    protected $limit;
101
-
102
-    /**
103
-     * @var int
104
-     */
105
-    protected $offset;
106
-
107
-    /**
108
-     * Apply DISTINCT upon property.
109
-     *
110
-     * @var string
111
-     */
112
-    protected $distinct;
113
-
114
-    /**
115
-     * The query settings.
116
-     *
117
-     * @var \Fab\Vidi\Persistence\QuerySettings
118
-     * @inject
119
-     */
120
-    protected $querySettings;
121
-
122
-    /**
123
-     * Constructs a query object working on the given class name
124
-     *
125
-     * @param string $type
126
-     */
127
-    public function __construct($type)
128
-    {
129
-        $this->type = $type;
130
-    }
131
-
132
-    /**
133
-     * @param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager
134
-     * @return void
135
-     */
136
-    public function injectObjectManager(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager)
137
-    {
138
-        $this->objectManager = $objectManager;
139
-    }
140
-
141
-    /**
142
-     * Injects the persistence manager, used to fetch the CR session
143
-     *
144
-     * @param \TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface $persistenceManager
145
-     * @return void
146
-     */
147
-    public function injectPersistenceManager(\TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface $persistenceManager)
148
-    {
149
-        $this->persistenceManager = $persistenceManager;
150
-    }
151
-
152
-    /**
153
-     * Injects the Query Object Model Factory
154
-     *
155
-     * @param \TYPO3\CMS\Extbase\Persistence\Generic\Qom\QueryObjectModelFactory $qomFactory
156
-     * @return void
157
-     */
158
-    public function injectQomFactory(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\QueryObjectModelFactory $qomFactory)
159
-    {
160
-        $this->qomFactory = $qomFactory;
161
-    }
162
-
163
-    /**
164
-     * Sets the Query Settings. These Query settings must match the settings expected by
165
-     * the specific Storage Backend.
166
-     *
167
-     * @param \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface $querySettings The Query Settings
168
-     * @return void
169
-     * @api This method is not part of FLOW3 API
170
-     */
171
-    public function setQuerySettings(\TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface $querySettings)
172
-    {
173
-        $this->querySettings = $querySettings;
174
-    }
175
-
176
-    /**
177
-     * Returns the Query Settings.
178
-     *
179
-     * @throws \Exception
180
-     * @return \Fab\Vidi\Persistence\QuerySettings $querySettings The Query Settings
181
-     * @api This method is not part of FLOW3 API
182
-     */
183
-    public function getQuerySettings()
184
-    {
185
-        if (!$this->querySettings instanceof \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface) {
186
-            throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception('Tried to get the query settings without setting them before.', 1248689115);
187
-        }
188
-
189
-        // Apply possible settings to the query.
190
-        if ($this->isBackendMode()) {
191
-            /** @var \TYPO3\CMS\Extbase\Configuration\BackendConfigurationManager $backendConfigurationManager */
192
-            $backendConfigurationManager = $this->objectManager->get('TYPO3\CMS\Extbase\Configuration\BackendConfigurationManager');
193
-            $configuration = $backendConfigurationManager->getTypoScriptSetup();
194
-            $querySettings = array('respectSysLanguage');
195
-            foreach ($querySettings as $setting) {
196
-                if (isset($configuration['config.']['tx_vidi.']['persistence.']['backend.'][$this->type . '.'][$setting])) {
197
-                    $value = (bool)$configuration['config.']['tx_vidi.']['persistence.']['backend.'][$this->type . '.'][$setting];
198
-                    ObjectAccess::setProperty($this->querySettings, $setting, $value);
199
-                }
200
-            }
201
-        }
202
-
203
-        return $this->querySettings;
204
-    }
205
-
206
-    /**
207
-     * Returns the type this query cares for.
208
-     *
209
-     * @return string
210
-     * @api
211
-     */
212
-    public function getType()
213
-    {
214
-        return $this->type;
215
-    }
216
-
217
-    /**
218
-     * Sets the source to fetch the result from
219
-     *
220
-     * @param \TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInterface $source
221
-     */
222
-    public function setSource(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInterface $source)
223
-    {
224
-        $this->source = $source;
225
-    }
226
-
227
-    /**
228
-     * Returns the selectorn name or an empty string, if the source is not a selector
229
-     * TODO This has to be checked at another place
230
-     *
231
-     * @return string The selector name
232
-     */
233
-    protected function getSelectorName()
234
-    {
235
-        if ($this->getSource() instanceof \TYPO3\CMS\Extbase\Persistence\Generic\Qom\SelectorInterface) {
236
-            return $this->source->getSelectorName();
237
-        } else {
238
-            return '';
239
-        }
240
-    }
241
-
242
-    /**
243
-     * Gets the node-tuple source for this query.
244
-     *
245
-     * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInterface the node-tuple source; non-null
246
-     */
247
-    public function getSource()
248
-    {
249
-        if ($this->source === NULL) {
250
-            $this->source = $this->qomFactory->selector($this->getType());
251
-        }
252
-        return $this->source;
253
-    }
254
-
255
-    /**
256
-     * Executes the query against the database and returns the result
257
-     *
258
-     * @return \TYPO3\CMS\Extbase\Persistence\QueryResultInterface|array The query result object or an array if $this->getQuerySettings()->getReturnRawQueryResult() is TRUE
259
-     * @api
260
-     */
261
-    public function execute($returnRawQueryResult = FALSE)
262
-    {
263
-        /** @var \Fab\Vidi\Persistence\Storage\VidiDbBackend $backend */
264
-        $backend = $this->objectManager->get('Fab\Vidi\Persistence\Storage\VidiDbBackend', $this);
265
-        return $backend->fetchResult();
266
-    }
267
-
268
-    /**
269
-     * Sets the property names to order the result by. Expected like this:
270
-     * array(
271
-     * 'foo' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_ASCENDING,
272
-     * 'bar' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_DESCENDING
273
-     * )
274
-     * where 'foo' and 'bar' are property names.
275
-     *
276
-     * @param array $orderings The property names to order by
277
-     * @return QueryInterface
278
-     * @api
279
-     */
280
-    public function setOrderings(array $orderings)
281
-    {
282
-        $this->orderings = $orderings;
283
-        return $this;
284
-    }
285
-
286
-    /**
287
-     * Returns the property names to order the result by. Like this:
288
-     * array(
289
-     * 'foo' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_ASCENDING,
290
-     * 'bar' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_DESCENDING
291
-     * )
292
-     *
293
-     * @return array
294
-     * @api
295
-     */
296
-    public function getOrderings()
297
-    {
298
-        return $this->orderings;
299
-    }
300
-
301
-    /**
302
-     * Sets the maximum size of the result set to limit. Returns $this to allow
303
-     * for chaining (fluid interface)
304
-     *
305
-     * @param integer $limit
306
-     * @throws \InvalidArgumentException
307
-     * @return QueryInterface
308
-     * @api
309
-     */
310
-    public function setLimit($limit)
311
-    {
312
-        if (!is_int($limit) || $limit < 1) {
313
-            throw new \InvalidArgumentException('The limit must be an integer >= 1', 1245071870);
314
-        }
315
-        $this->limit = $limit;
316
-        return $this;
317
-    }
318
-
319
-    /**
320
-     * Resets a previously set maximum size of the result set. Returns $this to allow
321
-     * for chaining (fluid interface)
322
-     *
323
-     * @return QueryInterface
324
-     * @api
325
-     */
326
-    public function unsetLimit()
327
-    {
328
-        unset($this->limit);
329
-        return $this;
330
-    }
331
-
332
-    /**
333
-     * Returns the maximum size of the result set to limit.
334
-     *
335
-     * @return integer
336
-     * @api
337
-     */
338
-    public function getLimit()
339
-    {
340
-        return $this->limit;
341
-    }
342
-
343
-    /**
344
-     * Sets the start offset of the result set to offset. Returns $this to
345
-     * allow for chaining (fluid interface)
346
-     *
347
-     * @param integer $offset
348
-     * @throws \InvalidArgumentException
349
-     * @return QueryInterface
350
-     * @api
351
-     */
352
-    public function setOffset($offset)
353
-    {
354
-        if (!is_int($offset) || $offset < 0) {
355
-            throw new \InvalidArgumentException('The offset must be a positive integer', 1245071872);
356
-        }
357
-        $this->offset = $offset;
358
-        return $this;
359
-    }
360
-
361
-    /**
362
-     * Returns the start offset of the result set.
363
-     *
364
-     * @return integer
365
-     * @api
366
-     */
367
-    public function getOffset()
368
-    {
369
-        return $this->offset;
370
-    }
371
-
372
-    /**
373
-     * The constraint used to limit the result set. Returns $this to allow
374
-     * for chaining (fluid interface)
375
-     *
376
-     * @param ConstraintInterface $constraint
377
-     * @return QueryInterface
378
-     * @api
379
-     */
380
-    public function matching($constraint)
381
-    {
382
-        $this->constraint = $constraint;
383
-        return $this;
384
-    }
385
-
386
-    /**
387
-     * Gets the constraint for this query.
388
-     *
389
-     * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\Constraint the constraint, or null if none
390
-     * @api
391
-     */
392
-    public function getConstraint()
393
-    {
394
-        return $this->constraint;
395
-    }
396
-
397
-    /**
398
-     * Performs a logical conjunction of the given constraints. The method takes one or more contraints and concatenates them with a boolean AND.
399
-     * It also scepts a single array of constraints to be concatenated.
400
-     *
401
-     * @param mixed $constraint1 The first of multiple constraints or an array of constraints.
402
-     * @throws InvalidNumberOfConstraintsException
403
-     * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\AndInterface
404
-     * @api
405
-     */
406
-    public function logicalAnd($constraint1)
407
-    {
408
-        if (is_array($constraint1)) {
409
-            $resultingConstraint = array_shift($constraint1);
410
-            $constraints = $constraint1;
411
-        } else {
412
-            $constraints = func_get_args();
413
-            $resultingConstraint = array_shift($constraints);
414
-        }
415
-        if ($resultingConstraint === NULL) {
416
-            throw new InvalidNumberOfConstraintsException('There must be at least one constraint or a non-empty array of constraints given.', 1401289500);
417
-        }
418
-        foreach ($constraints as $constraint) {
419
-            $resultingConstraint = $this->qomFactory->_and($resultingConstraint, $constraint);
420
-        }
421
-        return $resultingConstraint;
422
-    }
423
-
424
-    /**
425
-     * Performs a logical disjunction of the two given constraints
426
-     *
427
-     * @param mixed $constraint1 The first of multiple constraints or an array of constraints.
428
-     * @throws InvalidNumberOfConstraintsException
429
-     * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\OrInterface
430
-     * @api
431
-     */
432
-    public function logicalOr($constraint1)
433
-    {
434
-        if (is_array($constraint1)) {
435
-            $resultingConstraint = array_shift($constraint1);
436
-            $constraints = $constraint1;
437
-        } else {
438
-            $constraints = func_get_args();
439
-            $resultingConstraint = array_shift($constraints);
440
-        }
441
-        if ($resultingConstraint === NULL) {
442
-            throw new InvalidNumberOfConstraintsException('There must be at least one constraint or a non-empty array of constraints given.', 1401289501);
443
-        }
444
-        foreach ($constraints as $constraint) {
445
-            $resultingConstraint = $this->qomFactory->_or($resultingConstraint, $constraint);
446
-        }
447
-        return $resultingConstraint;
448
-    }
449
-
450
-    /**
451
-     * Performs a logical negation of the given constraint
452
-     *
453
-     * @param ConstraintInterface $constraint Constraint to negate
454
-     * @throws \RuntimeException
455
-     * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\NotInterface
456
-     * @api
457
-     */
458
-    public function logicalNot(ConstraintInterface $constraint)
459
-    {
460
-        return $this->qomFactory->not($constraint);
461
-    }
462
-
463
-    /**
464
-     * Returns an equals criterion used for matching objects against a query
465
-     *
466
-     * @param string $propertyName The name of the property to compare against
467
-     * @param mixed $operand The value to compare with
468
-     * @param boolean $caseSensitive Whether the equality test should be done case-sensitive
469
-     * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
470
-     * @api
471
-     */
472
-    public function equals($propertyName, $operand, $caseSensitive = TRUE)
473
-    {
474
-        if (is_object($operand) || $caseSensitive) {
475
-            $comparison = $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_EQUAL_TO, $operand);
476
-        } else {
477
-            $comparison = $this->qomFactory->comparison($this->qomFactory->lowerCase($this->qomFactory->propertyValue($propertyName, $this->getSelectorName())), QueryInterface::OPERATOR_EQUAL_TO, \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Charset\\CharsetConverter')->conv_case(\TYPO3\CMS\Extbase\Persistence\Generic\Query::CHARSET, $operand, 'toLower'));
478
-        }
479
-        return $comparison;
480
-    }
481
-
482
-    /**
483
-     * Returns a like criterion used for matching objects against a query
484
-     *
485
-     * @param string $propertyName The name of the property to compare against
486
-     * @param mixed $operand The value to compare with
487
-     * @param boolean $caseSensitive Whether the matching should be done case-sensitive
488
-     * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
489
-     * @api
490
-     */
491
-    public function like($propertyName, $operand, $caseSensitive = TRUE)
492
-    {
493
-        return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_LIKE, $operand);
494
-    }
495
-
496
-    /**
497
-     * Returns a "contains" criterion used for matching objects against a query.
498
-     * It matches if the multivalued property contains the given operand.
499
-     *
500
-     * @param string $propertyName The name of the (multivalued) property to compare against
501
-     * @param mixed $operand The value to compare with
502
-     * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
503
-     * @api
504
-     */
505
-    public function contains($propertyName, $operand)
506
-    {
507
-        return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_CONTAINS, $operand);
508
-    }
509
-
510
-    /**
511
-     * Returns an "in" criterion used for matching objects against a query. It
512
-     * matches if the property's value is contained in the multivalued operand.
513
-     *
514
-     * @param string $propertyName The name of the property to compare against
515
-     * @param mixed $operand The value to compare with, multivalued
516
-     * @throws UnexpectedTypeException
517
-     * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
518
-     * @api
519
-     */
520
-    public function in($propertyName, $operand)
521
-    {
522
-        if (!is_array($operand) && !$operand instanceof \ArrayAccess && !$operand instanceof \Traversable) {
523
-            throw new UnexpectedTypeException('The "in" operator must be given a mutlivalued operand (array, ArrayAccess, Traversable).', 1264678095);
524
-        }
525
-        return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_IN, $operand);
526
-    }
527
-
528
-    /**
529
-     * Returns a less than criterion used for matching objects against a query
530
-     *
531
-     * @param string $propertyName The name of the property to compare against
532
-     * @param mixed $operand The value to compare with
533
-     * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
534
-     * @api
535
-     */
536
-    public function lessThan($propertyName, $operand)
537
-    {
538
-        return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_LESS_THAN, $operand);
539
-    }
540
-
541
-    /**
542
-     * Returns a less or equal than criterion used for matching objects against a query
543
-     *
544
-     * @param string $propertyName The name of the property to compare against
545
-     * @param mixed $operand The value to compare with
546
-     * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
547
-     * @api
548
-     */
549
-    public function lessThanOrEqual($propertyName, $operand)
550
-    {
551
-        return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_LESS_THAN_OR_EQUAL_TO, $operand);
552
-    }
553
-
554
-    /**
555
-     * Returns a greater than criterion used for matching objects against a query
556
-     *
557
-     * @param string $propertyName The name of the property to compare against
558
-     * @param mixed $operand The value to compare with
559
-     * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
560
-     * @api
561
-     */
562
-    public function greaterThan($propertyName, $operand)
563
-    {
564
-        return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_GREATER_THAN, $operand);
565
-    }
566
-
567
-    /**
568
-     * Returns a greater than or equal criterion used for matching objects against a query
569
-     *
570
-     * @param string $propertyName The name of the property to compare against
571
-     * @param mixed $operand The value to compare with
572
-     * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
573
-     * @api
574
-     */
575
-    public function greaterThanOrEqual($propertyName, $operand)
576
-    {
577
-        return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_GREATER_THAN_OR_EQUAL_TO, $operand);
578
-    }
579
-
580
-    /**
581
-     * Returns the query result count.
582
-     *
583
-     * @return integer The query result count
584
-     * @api
585
-     */
586
-    public function count()
587
-    {
588
-        /** @var \Fab\Vidi\Persistence\Storage\VidiDbBackend $backend */
589
-        $backend = $this->objectManager->get('Fab\Vidi\Persistence\Storage\VidiDbBackend', $this);
590
-        return $backend->countResult();
591
-    }
592
-
593
-    /**
594
-     * Returns an "isEmpty" criterion used for matching objects against a query.
595
-     * It matches if the multivalued property contains no values or is NULL.
596
-     *
597
-     * @param string $propertyName The name of the multivalued property to compare against
598
-     * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\NotImplementedException
599
-     * @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException if used on a single-valued property
600
-     * @api
601
-     */
602
-    public function isEmpty($propertyName)
603
-    {
604
-        throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\NotImplementedException(__METHOD__);
605
-    }
606
-
607
-    /**
608
-     * @return string
609
-     */
610
-    public function getDistinct()
611
-    {
612
-        return $this->distinct;
613
-    }
614
-
615
-    /**
616
-     * @param string $distinct
617
-     * @return $this
618
-     */
619
-    public function setDistinct($distinct)
620
-    {
621
-        $this->distinct = $distinct;
622
-        return $this;
623
-    }
624
-
625
-    /**
626
-     * Sets the statement of this query. If you use this, you will lose the abstraction from a concrete storage
627
-     * backend (database).
628
-     *
629
-     * @param string|\TYPO3\CMS\Core\Database\PreparedStatement $statement The statement
630
-     * @param array $parameters An array of parameters. These will be bound to placeholders '?' in the $statement.
631
-     * @return QueryInterface
632
-     */
633
-    public function statement($statement, array $parameters = array())
634
-    {
635
-        $this->statement = $this->qomFactory->statement($statement, $parameters);
636
-        return $this;
637
-    }
638
-
639
-    /**
640
-     * Returns the statement of this query.
641
-     *
642
-     * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\Statement
643
-     */
644
-    public function getStatement()
645
-    {
646
-        return $this->statement;
647
-    }
648
-
649
-    /**
650
-     * Returns whether the current mode is Backend.
651
-     *
652
-     * @return bool
653
-     */
654
-    protected function isBackendMode()
655
-    {
656
-        return TYPO3_MODE == 'BE';
657
-    }
658
-
659
-    /**
660
-     * @return string
661
-     */
662
-    public function getSourceFieldName()
663
-    {
664
-        return $this->sourceFieldName;
665
-    }
666
-
667
-    /**
668
-     * @param string $sourceFieldName
669
-     * @return $this
670
-     */
671
-    public function setSourceFieldName($sourceFieldName)
672
-    {
673
-        $this->sourceFieldName = $sourceFieldName;
674
-        return $this;
675
-    }
32
+	/**
33
+	 * An inner join.
34
+	 */
35
+	const JCR_JOIN_TYPE_INNER = '{http://www.jcp.org/jcr/1.0}joinTypeInner';
36
+
37
+	/**
38
+	 * A left-outer join.
39
+	 */
40
+	const JCR_JOIN_TYPE_LEFT_OUTER = '{http://www.jcp.org/jcr/1.0}joinTypeLeftOuter';
41
+
42
+	/**
43
+	 * A right-outer join.
44
+	 */
45
+	const JCR_JOIN_TYPE_RIGHT_OUTER = '{http://www.jcp.org/jcr/1.0}joinTypeRightOuter';
46
+
47
+	/**
48
+	 * Charset of strings in QOM
49
+	 */
50
+	const CHARSET = 'utf-8';
51
+
52
+	/**
53
+	 * @var string
54
+	 */
55
+	protected $sourceFieldName;
56
+
57
+	/**
58
+	 * @var string
59
+	 */
60
+	protected $type;
61
+
62
+	/**
63
+	 * @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
64
+	 */
65
+	protected $objectManager;
66
+
67
+	/**
68
+	 * @var \TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface
69
+	 */
70
+	protected $persistenceManager;
71
+
72
+	/**
73
+	 * @var \TYPO3\CMS\Extbase\Persistence\Generic\Qom\QueryObjectModelFactory
74
+	 */
75
+	protected $qomFactory;
76
+
77
+	/**
78
+	 * @var \TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInterface
79
+	 */
80
+	protected $source;
81
+
82
+	/**
83
+	 * @var ConstraintInterface
84
+	 */
85
+	protected $constraint;
86
+
87
+	/**
88
+	 * @var \TYPO3\CMS\Extbase\Persistence\Generic\Qom\Statement
89
+	 */
90
+	protected $statement;
91
+
92
+	/**
93
+	 * @var int
94
+	 */
95
+	protected $orderings = array();
96
+
97
+	/**
98
+	 * @var int
99
+	 */
100
+	protected $limit;
101
+
102
+	/**
103
+	 * @var int
104
+	 */
105
+	protected $offset;
106
+
107
+	/**
108
+	 * Apply DISTINCT upon property.
109
+	 *
110
+	 * @var string
111
+	 */
112
+	protected $distinct;
113
+
114
+	/**
115
+	 * The query settings.
116
+	 *
117
+	 * @var \Fab\Vidi\Persistence\QuerySettings
118
+	 * @inject
119
+	 */
120
+	protected $querySettings;
121
+
122
+	/**
123
+	 * Constructs a query object working on the given class name
124
+	 *
125
+	 * @param string $type
126
+	 */
127
+	public function __construct($type)
128
+	{
129
+		$this->type = $type;
130
+	}
131
+
132
+	/**
133
+	 * @param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager
134
+	 * @return void
135
+	 */
136
+	public function injectObjectManager(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager)
137
+	{
138
+		$this->objectManager = $objectManager;
139
+	}
140
+
141
+	/**
142
+	 * Injects the persistence manager, used to fetch the CR session
143
+	 *
144
+	 * @param \TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface $persistenceManager
145
+	 * @return void
146
+	 */
147
+	public function injectPersistenceManager(\TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface $persistenceManager)
148
+	{
149
+		$this->persistenceManager = $persistenceManager;
150
+	}
151
+
152
+	/**
153
+	 * Injects the Query Object Model Factory
154
+	 *
155
+	 * @param \TYPO3\CMS\Extbase\Persistence\Generic\Qom\QueryObjectModelFactory $qomFactory
156
+	 * @return void
157
+	 */
158
+	public function injectQomFactory(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\QueryObjectModelFactory $qomFactory)
159
+	{
160
+		$this->qomFactory = $qomFactory;
161
+	}
162
+
163
+	/**
164
+	 * Sets the Query Settings. These Query settings must match the settings expected by
165
+	 * the specific Storage Backend.
166
+	 *
167
+	 * @param \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface $querySettings The Query Settings
168
+	 * @return void
169
+	 * @api This method is not part of FLOW3 API
170
+	 */
171
+	public function setQuerySettings(\TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface $querySettings)
172
+	{
173
+		$this->querySettings = $querySettings;
174
+	}
175
+
176
+	/**
177
+	 * Returns the Query Settings.
178
+	 *
179
+	 * @throws \Exception
180
+	 * @return \Fab\Vidi\Persistence\QuerySettings $querySettings The Query Settings
181
+	 * @api This method is not part of FLOW3 API
182
+	 */
183
+	public function getQuerySettings()
184
+	{
185
+		if (!$this->querySettings instanceof \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface) {
186
+			throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception('Tried to get the query settings without setting them before.', 1248689115);
187
+		}
188
+
189
+		// Apply possible settings to the query.
190
+		if ($this->isBackendMode()) {
191
+			/** @var \TYPO3\CMS\Extbase\Configuration\BackendConfigurationManager $backendConfigurationManager */
192
+			$backendConfigurationManager = $this->objectManager->get('TYPO3\CMS\Extbase\Configuration\BackendConfigurationManager');
193
+			$configuration = $backendConfigurationManager->getTypoScriptSetup();
194
+			$querySettings = array('respectSysLanguage');
195
+			foreach ($querySettings as $setting) {
196
+				if (isset($configuration['config.']['tx_vidi.']['persistence.']['backend.'][$this->type . '.'][$setting])) {
197
+					$value = (bool)$configuration['config.']['tx_vidi.']['persistence.']['backend.'][$this->type . '.'][$setting];
198
+					ObjectAccess::setProperty($this->querySettings, $setting, $value);
199
+				}
200
+			}
201
+		}
202
+
203
+		return $this->querySettings;
204
+	}
205
+
206
+	/**
207
+	 * Returns the type this query cares for.
208
+	 *
209
+	 * @return string
210
+	 * @api
211
+	 */
212
+	public function getType()
213
+	{
214
+		return $this->type;
215
+	}
216
+
217
+	/**
218
+	 * Sets the source to fetch the result from
219
+	 *
220
+	 * @param \TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInterface $source
221
+	 */
222
+	public function setSource(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInterface $source)
223
+	{
224
+		$this->source = $source;
225
+	}
226
+
227
+	/**
228
+	 * Returns the selectorn name or an empty string, if the source is not a selector
229
+	 * TODO This has to be checked at another place
230
+	 *
231
+	 * @return string The selector name
232
+	 */
233
+	protected function getSelectorName()
234
+	{
235
+		if ($this->getSource() instanceof \TYPO3\CMS\Extbase\Persistence\Generic\Qom\SelectorInterface) {
236
+			return $this->source->getSelectorName();
237
+		} else {
238
+			return '';
239
+		}
240
+	}
241
+
242
+	/**
243
+	 * Gets the node-tuple source for this query.
244
+	 *
245
+	 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInterface the node-tuple source; non-null
246
+	 */
247
+	public function getSource()
248
+	{
249
+		if ($this->source === NULL) {
250
+			$this->source = $this->qomFactory->selector($this->getType());
251
+		}
252
+		return $this->source;
253
+	}
254
+
255
+	/**
256
+	 * Executes the query against the database and returns the result
257
+	 *
258
+	 * @return \TYPO3\CMS\Extbase\Persistence\QueryResultInterface|array The query result object or an array if $this->getQuerySettings()->getReturnRawQueryResult() is TRUE
259
+	 * @api
260
+	 */
261
+	public function execute($returnRawQueryResult = FALSE)
262
+	{
263
+		/** @var \Fab\Vidi\Persistence\Storage\VidiDbBackend $backend */
264
+		$backend = $this->objectManager->get('Fab\Vidi\Persistence\Storage\VidiDbBackend', $this);
265
+		return $backend->fetchResult();
266
+	}
267
+
268
+	/**
269
+	 * Sets the property names to order the result by. Expected like this:
270
+	 * array(
271
+	 * 'foo' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_ASCENDING,
272
+	 * 'bar' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_DESCENDING
273
+	 * )
274
+	 * where 'foo' and 'bar' are property names.
275
+	 *
276
+	 * @param array $orderings The property names to order by
277
+	 * @return QueryInterface
278
+	 * @api
279
+	 */
280
+	public function setOrderings(array $orderings)
281
+	{
282
+		$this->orderings = $orderings;
283
+		return $this;
284
+	}
285
+
286
+	/**
287
+	 * Returns the property names to order the result by. Like this:
288
+	 * array(
289
+	 * 'foo' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_ASCENDING,
290
+	 * 'bar' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_DESCENDING
291
+	 * )
292
+	 *
293
+	 * @return array
294
+	 * @api
295
+	 */
296
+	public function getOrderings()
297
+	{
298
+		return $this->orderings;
299
+	}
300
+
301
+	/**
302
+	 * Sets the maximum size of the result set to limit. Returns $this to allow
303
+	 * for chaining (fluid interface)
304
+	 *
305
+	 * @param integer $limit
306
+	 * @throws \InvalidArgumentException
307
+	 * @return QueryInterface
308
+	 * @api
309
+	 */
310
+	public function setLimit($limit)
311
+	{
312
+		if (!is_int($limit) || $limit < 1) {
313
+			throw new \InvalidArgumentException('The limit must be an integer >= 1', 1245071870);
314
+		}
315
+		$this->limit = $limit;
316
+		return $this;
317
+	}
318
+
319
+	/**
320
+	 * Resets a previously set maximum size of the result set. Returns $this to allow
321
+	 * for chaining (fluid interface)
322
+	 *
323
+	 * @return QueryInterface
324
+	 * @api
325
+	 */
326
+	public function unsetLimit()
327
+	{
328
+		unset($this->limit);
329
+		return $this;
330
+	}
331
+
332
+	/**
333
+	 * Returns the maximum size of the result set to limit.
334
+	 *
335
+	 * @return integer
336
+	 * @api
337
+	 */
338
+	public function getLimit()
339
+	{
340
+		return $this->limit;
341
+	}
342
+
343
+	/**
344
+	 * Sets the start offset of the result set to offset. Returns $this to
345
+	 * allow for chaining (fluid interface)
346
+	 *
347
+	 * @param integer $offset
348
+	 * @throws \InvalidArgumentException
349
+	 * @return QueryInterface
350
+	 * @api
351
+	 */
352
+	public function setOffset($offset)
353
+	{
354
+		if (!is_int($offset) || $offset < 0) {
355
+			throw new \InvalidArgumentException('The offset must be a positive integer', 1245071872);
356
+		}
357
+		$this->offset = $offset;
358
+		return $this;
359
+	}
360
+
361
+	/**
362
+	 * Returns the start offset of the result set.
363
+	 *
364
+	 * @return integer
365
+	 * @api
366
+	 */
367
+	public function getOffset()
368
+	{
369
+		return $this->offset;
370
+	}
371
+
372
+	/**
373
+	 * The constraint used to limit the result set. Returns $this to allow
374
+	 * for chaining (fluid interface)
375
+	 *
376
+	 * @param ConstraintInterface $constraint
377
+	 * @return QueryInterface
378
+	 * @api
379
+	 */
380
+	public function matching($constraint)
381
+	{
382
+		$this->constraint = $constraint;
383
+		return $this;
384
+	}
385
+
386
+	/**
387
+	 * Gets the constraint for this query.
388
+	 *
389
+	 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\Constraint the constraint, or null if none
390
+	 * @api
391
+	 */
392
+	public function getConstraint()
393
+	{
394
+		return $this->constraint;
395
+	}
396
+
397
+	/**
398
+	 * Performs a logical conjunction of the given constraints. The method takes one or more contraints and concatenates them with a boolean AND.
399
+	 * It also scepts a single array of constraints to be concatenated.
400
+	 *
401
+	 * @param mixed $constraint1 The first of multiple constraints or an array of constraints.
402
+	 * @throws InvalidNumberOfConstraintsException
403
+	 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\AndInterface
404
+	 * @api
405
+	 */
406
+	public function logicalAnd($constraint1)
407
+	{
408
+		if (is_array($constraint1)) {
409
+			$resultingConstraint = array_shift($constraint1);
410
+			$constraints = $constraint1;
411
+		} else {
412
+			$constraints = func_get_args();
413
+			$resultingConstraint = array_shift($constraints);
414
+		}
415
+		if ($resultingConstraint === NULL) {
416
+			throw new InvalidNumberOfConstraintsException('There must be at least one constraint or a non-empty array of constraints given.', 1401289500);
417
+		}
418
+		foreach ($constraints as $constraint) {
419
+			$resultingConstraint = $this->qomFactory->_and($resultingConstraint, $constraint);
420
+		}
421
+		return $resultingConstraint;
422
+	}
423
+
424
+	/**
425
+	 * Performs a logical disjunction of the two given constraints
426
+	 *
427
+	 * @param mixed $constraint1 The first of multiple constraints or an array of constraints.
428
+	 * @throws InvalidNumberOfConstraintsException
429
+	 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\OrInterface
430
+	 * @api
431
+	 */
432
+	public function logicalOr($constraint1)
433
+	{
434
+		if (is_array($constraint1)) {
435
+			$resultingConstraint = array_shift($constraint1);
436
+			$constraints = $constraint1;
437
+		} else {
438
+			$constraints = func_get_args();
439
+			$resultingConstraint = array_shift($constraints);
440
+		}
441
+		if ($resultingConstraint === NULL) {
442
+			throw new InvalidNumberOfConstraintsException('There must be at least one constraint or a non-empty array of constraints given.', 1401289501);
443
+		}
444
+		foreach ($constraints as $constraint) {
445
+			$resultingConstraint = $this->qomFactory->_or($resultingConstraint, $constraint);
446
+		}
447
+		return $resultingConstraint;
448
+	}
449
+
450
+	/**
451
+	 * Performs a logical negation of the given constraint
452
+	 *
453
+	 * @param ConstraintInterface $constraint Constraint to negate
454
+	 * @throws \RuntimeException
455
+	 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\NotInterface
456
+	 * @api
457
+	 */
458
+	public function logicalNot(ConstraintInterface $constraint)
459
+	{
460
+		return $this->qomFactory->not($constraint);
461
+	}
462
+
463
+	/**
464
+	 * Returns an equals criterion used for matching objects against a query
465
+	 *
466
+	 * @param string $propertyName The name of the property to compare against
467
+	 * @param mixed $operand The value to compare with
468
+	 * @param boolean $caseSensitive Whether the equality test should be done case-sensitive
469
+	 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
470
+	 * @api
471
+	 */
472
+	public function equals($propertyName, $operand, $caseSensitive = TRUE)
473
+	{
474
+		if (is_object($operand) || $caseSensitive) {
475
+			$comparison = $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_EQUAL_TO, $operand);
476
+		} else {
477
+			$comparison = $this->qomFactory->comparison($this->qomFactory->lowerCase($this->qomFactory->propertyValue($propertyName, $this->getSelectorName())), QueryInterface::OPERATOR_EQUAL_TO, \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Charset\\CharsetConverter')->conv_case(\TYPO3\CMS\Extbase\Persistence\Generic\Query::CHARSET, $operand, 'toLower'));
478
+		}
479
+		return $comparison;
480
+	}
481
+
482
+	/**
483
+	 * Returns a like criterion used for matching objects against a query
484
+	 *
485
+	 * @param string $propertyName The name of the property to compare against
486
+	 * @param mixed $operand The value to compare with
487
+	 * @param boolean $caseSensitive Whether the matching should be done case-sensitive
488
+	 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
489
+	 * @api
490
+	 */
491
+	public function like($propertyName, $operand, $caseSensitive = TRUE)
492
+	{
493
+		return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_LIKE, $operand);
494
+	}
495
+
496
+	/**
497
+	 * Returns a "contains" criterion used for matching objects against a query.
498
+	 * It matches if the multivalued property contains the given operand.
499
+	 *
500
+	 * @param string $propertyName The name of the (multivalued) property to compare against
501
+	 * @param mixed $operand The value to compare with
502
+	 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
503
+	 * @api
504
+	 */
505
+	public function contains($propertyName, $operand)
506
+	{
507
+		return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_CONTAINS, $operand);
508
+	}
509
+
510
+	/**
511
+	 * Returns an "in" criterion used for matching objects against a query. It
512
+	 * matches if the property's value is contained in the multivalued operand.
513
+	 *
514
+	 * @param string $propertyName The name of the property to compare against
515
+	 * @param mixed $operand The value to compare with, multivalued
516
+	 * @throws UnexpectedTypeException
517
+	 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
518
+	 * @api
519
+	 */
520
+	public function in($propertyName, $operand)
521
+	{
522
+		if (!is_array($operand) && !$operand instanceof \ArrayAccess && !$operand instanceof \Traversable) {
523
+			throw new UnexpectedTypeException('The "in" operator must be given a mutlivalued operand (array, ArrayAccess, Traversable).', 1264678095);
524
+		}
525
+		return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_IN, $operand);
526
+	}
527
+
528
+	/**
529
+	 * Returns a less than criterion used for matching objects against a query
530
+	 *
531
+	 * @param string $propertyName The name of the property to compare against
532
+	 * @param mixed $operand The value to compare with
533
+	 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
534
+	 * @api
535
+	 */
536
+	public function lessThan($propertyName, $operand)
537
+	{
538
+		return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_LESS_THAN, $operand);
539
+	}
540
+
541
+	/**
542
+	 * Returns a less or equal than criterion used for matching objects against a query
543
+	 *
544
+	 * @param string $propertyName The name of the property to compare against
545
+	 * @param mixed $operand The value to compare with
546
+	 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
547
+	 * @api
548
+	 */
549
+	public function lessThanOrEqual($propertyName, $operand)
550
+	{
551
+		return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_LESS_THAN_OR_EQUAL_TO, $operand);
552
+	}
553
+
554
+	/**
555
+	 * Returns a greater than criterion used for matching objects against a query
556
+	 *
557
+	 * @param string $propertyName The name of the property to compare against
558
+	 * @param mixed $operand The value to compare with
559
+	 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
560
+	 * @api
561
+	 */
562
+	public function greaterThan($propertyName, $operand)
563
+	{
564
+		return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_GREATER_THAN, $operand);
565
+	}
566
+
567
+	/**
568
+	 * Returns a greater than or equal criterion used for matching objects against a query
569
+	 *
570
+	 * @param string $propertyName The name of the property to compare against
571
+	 * @param mixed $operand The value to compare with
572
+	 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
573
+	 * @api
574
+	 */
575
+	public function greaterThanOrEqual($propertyName, $operand)
576
+	{
577
+		return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_GREATER_THAN_OR_EQUAL_TO, $operand);
578
+	}
579
+
580
+	/**
581
+	 * Returns the query result count.
582
+	 *
583
+	 * @return integer The query result count
584
+	 * @api
585
+	 */
586
+	public function count()
587
+	{
588
+		/** @var \Fab\Vidi\Persistence\Storage\VidiDbBackend $backend */
589
+		$backend = $this->objectManager->get('Fab\Vidi\Persistence\Storage\VidiDbBackend', $this);
590
+		return $backend->countResult();
591
+	}
592
+
593
+	/**
594
+	 * Returns an "isEmpty" criterion used for matching objects against a query.
595
+	 * It matches if the multivalued property contains no values or is NULL.
596
+	 *
597
+	 * @param string $propertyName The name of the multivalued property to compare against
598
+	 * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\NotImplementedException
599
+	 * @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException if used on a single-valued property
600
+	 * @api
601
+	 */
602
+	public function isEmpty($propertyName)
603
+	{
604
+		throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\NotImplementedException(__METHOD__);
605
+	}
606
+
607
+	/**
608
+	 * @return string
609
+	 */
610
+	public function getDistinct()
611
+	{
612
+		return $this->distinct;
613
+	}
614
+
615
+	/**
616
+	 * @param string $distinct
617
+	 * @return $this
618
+	 */
619
+	public function setDistinct($distinct)
620
+	{
621
+		$this->distinct = $distinct;
622
+		return $this;
623
+	}
624
+
625
+	/**
626
+	 * Sets the statement of this query. If you use this, you will lose the abstraction from a concrete storage
627
+	 * backend (database).
628
+	 *
629
+	 * @param string|\TYPO3\CMS\Core\Database\PreparedStatement $statement The statement
630
+	 * @param array $parameters An array of parameters. These will be bound to placeholders '?' in the $statement.
631
+	 * @return QueryInterface
632
+	 */
633
+	public function statement($statement, array $parameters = array())
634
+	{
635
+		$this->statement = $this->qomFactory->statement($statement, $parameters);
636
+		return $this;
637
+	}
638
+
639
+	/**
640
+	 * Returns the statement of this query.
641
+	 *
642
+	 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\Statement
643
+	 */
644
+	public function getStatement()
645
+	{
646
+		return $this->statement;
647
+	}
648
+
649
+	/**
650
+	 * Returns whether the current mode is Backend.
651
+	 *
652
+	 * @return bool
653
+	 */
654
+	protected function isBackendMode()
655
+	{
656
+		return TYPO3_MODE == 'BE';
657
+	}
658
+
659
+	/**
660
+	 * @return string
661
+	 */
662
+	public function getSourceFieldName()
663
+	{
664
+		return $this->sourceFieldName;
665
+	}
666
+
667
+	/**
668
+	 * @param string $sourceFieldName
669
+	 * @return $this
670
+	 */
671
+	public function setSourceFieldName($sourceFieldName)
672
+	{
673
+		$this->sourceFieldName = $sourceFieldName;
674
+		return $this;
675
+	}
676 676
 
677 677
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -193,8 +193,8 @@
 block discarded – undo
193 193
             $configuration = $backendConfigurationManager->getTypoScriptSetup();
194 194
             $querySettings = array('respectSysLanguage');
195 195
             foreach ($querySettings as $setting) {
196
-                if (isset($configuration['config.']['tx_vidi.']['persistence.']['backend.'][$this->type . '.'][$setting])) {
197
-                    $value = (bool)$configuration['config.']['tx_vidi.']['persistence.']['backend.'][$this->type . '.'][$setting];
196
+                if (isset($configuration['config.']['tx_vidi.']['persistence.']['backend.'][$this->type.'.'][$setting])) {
197
+                    $value = (bool)$configuration['config.']['tx_vidi.']['persistence.']['backend.'][$this->type.'.'][$setting];
198 198
                     ObjectAccess::setProperty($this->querySettings, $setting, $value);
199 199
                 }
200 200
             }
Please login to merge, or discard this patch.
Classes/Persistence/Storage/VidiDbBackend.php 4 patches
Doc Comments   +3 added lines, -2 removed lines patch added patch discarded remove patch
@@ -231,7 +231,7 @@  discard block
 block discarded – undo
231 231
     /**
232 232
      * Parses the query and returns the SQL statement parts.
233 233
      *
234
-     * @param QueryInterface $query The query
234
+     * @param \Fab\Vidi\Persistence\Query $query The query
235 235
      * @param array &$parameters
236 236
      * @return array The SQL statement parts
237 237
      */
@@ -774,6 +774,7 @@  discard block
 block discarded – undo
774 774
      * @param string &$sqlString The query part with placeholders
775 775
      * @param array $parameters The parameters
776 776
      * @param string $tableName
777
+     * @param string $sqlString
777 778
      *
778 779
      * @throws Exception
779 780
      */
@@ -1071,7 +1072,7 @@  discard block
 block discarded – undo
1071 1072
      *
1072 1073
      * @param SourceInterface $source The source (selector od join)
1073 1074
      * @param array $row
1074
-     * @param QuerySettingsInterface $querySettings The TYPO3 CMS specific query settings
1075
+     * @param \Fab\Vidi\Persistence\QuerySettings $querySettings The TYPO3 CMS specific query settings
1075 1076
      * @return array
1076 1077
      */
1077 1078
     protected function doLanguageAndWorkspaceOverlay(SourceInterface $source, array $row, $querySettings)
Please login to merge, or discard this patch.
Unused Use Statements   -1 removed lines patch added patch discarded remove patch
@@ -18,7 +18,6 @@
 block discarded – undo
18 18
 use TYPO3\CMS\Core\Utility\GeneralUtility;
19 19
 use TYPO3\CMS\Core\Versioning\VersionState;
20 20
 use TYPO3\CMS\Extbase\Persistence\Generic\Exception;
21
-use TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap;
22 21
 use TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface;
23 22
 use TYPO3\CMS\Extbase\Persistence\Generic\Qom\DynamicOperandInterface;
24 23
 use TYPO3\CMS\Extbase\Persistence\Generic\Qom\JoinInterface;
Please login to merge, or discard this patch.
Spacing   +46 added lines, -46 removed lines patch added patch discarded remove patch
@@ -148,7 +148,7 @@  discard block
 block discarded – undo
148 148
         $fieldNames = array_keys($identifier);
149 149
         $suffixedFieldNames = array();
150 150
         foreach ($fieldNames as $fieldName) {
151
-            $suffixedFieldNames[] = $fieldName . '=?';
151
+            $suffixedFieldNames[] = $fieldName.'=?';
152 152
         }
153 153
         return implode(' AND ', $suffixedFieldNames);
154 154
     }
@@ -209,7 +209,7 @@  discard block
 block discarded – undo
209 209
             if (isset($statementParts['keywords']['distinct'])) {
210 210
                 unset($statementParts['keywords']['distinct']);
211 211
                 $distinctField = $this->query->getDistinct() ? $this->query->getDistinct() : 'uid';
212
-                $statementParts['fields'] = array('COUNT(DISTINCT ' . reset($statementParts['tables']) . '.' . $distinctField . ')');
212
+                $statementParts['fields'] = array('COUNT(DISTINCT '.reset($statementParts['tables']).'.'.$distinctField.')');
213 213
             }
214 214
 
215 215
             $statement = $this->buildQuery($statementParts);
@@ -279,14 +279,14 @@  discard block
 block discarded – undo
279 279
             // tx_domain_model_foo0 (the alias) <--> tx_domain_model_foo (the origin table name)
280 280
             $values = array();
281 281
             foreach ($statementParts['fields'] as $key => $value) {
282
-                $values[$key] = str_replace($tableName, $tableName . '0', $value);
282
+                $values[$key] = str_replace($tableName, $tableName.'0', $value);
283 283
             }
284 284
             $statementParts['fields'] = $values;
285 285
 
286 286
             // Same comment as above.
287 287
             $values = array();
288 288
             foreach ($statementParts['where'] as $key => $value) {
289
-                $values[$key] = str_replace($tableName . '0', $tableName, $value);
289
+                $values[$key] = str_replace($tableName.'0', $tableName, $value);
290 290
             }
291 291
             $statementParts['where'] = $values;
292 292
 
@@ -325,25 +325,25 @@  discard block
 block discarded – undo
325 325
         if (!empty($statementParts['unions'])) {
326 326
             foreach ($statementParts['unions'] as $tableName => $unionPart) {
327 327
                 if (!empty($statementParts['additionalWhereClause'][$tableName])) {
328
-                    $statementParts['unions'][$tableName] .= ' AND ' . implode(' AND ', $statementParts['additionalWhereClause'][$tableName]);
328
+                    $statementParts['unions'][$tableName] .= ' AND '.implode(' AND ', $statementParts['additionalWhereClause'][$tableName]);
329 329
                 }
330 330
             }
331 331
         }
332 332
 
333
-        $statement = 'SELECT ' . implode(' ', $statementParts['keywords']) . ' ' . implode(',', $statementParts['fields']) . ' FROM ' . implode(' ', $statementParts['tables']) . ' ' . implode(' ', $statementParts['unions']);
333
+        $statement = 'SELECT '.implode(' ', $statementParts['keywords']).' '.implode(',', $statementParts['fields']).' FROM '.implode(' ', $statementParts['tables']).' '.implode(' ', $statementParts['unions']);
334 334
         if (!empty($statementParts['where'])) {
335
-            $statement .= ' WHERE ' . implode('', $statementParts['where']);
335
+            $statement .= ' WHERE '.implode('', $statementParts['where']);
336 336
             if (!empty($statementParts['additionalWhereClause'][$this->query->getType()])) {
337
-                $statement .= ' AND ' . implode(' AND ', $statementParts['additionalWhereClause'][$this->query->getType()]);
337
+                $statement .= ' AND '.implode(' AND ', $statementParts['additionalWhereClause'][$this->query->getType()]);
338 338
             }
339 339
         } elseif (!empty($statementParts['additionalWhereClause'])) {
340
-            $statement .= ' WHERE ' . implode(' AND ', $statementParts['additionalWhereClause'][$this->query->getType()]);
340
+            $statement .= ' WHERE '.implode(' AND ', $statementParts['additionalWhereClause'][$this->query->getType()]);
341 341
         }
342 342
         if (!empty($statementParts['orderings'])) {
343
-            $statement .= ' ORDER BY ' . implode(', ', $statementParts['orderings']);
343
+            $statement .= ' ORDER BY '.implode(', ', $statementParts['orderings']);
344 344
         }
345 345
         if (!empty($statementParts['limit'])) {
346
-            $statement .= ' LIMIT ' . $statementParts['limit'];
346
+            $statement .= ' LIMIT '.$statementParts['limit'];
347 347
         }
348 348
 
349 349
         return $statement;
@@ -360,10 +360,10 @@  discard block
 block discarded – undo
360 360
     {
361 361
         if ($source instanceof SelectorInterface) {
362 362
             $tableName = $source->getNodeTypeName();
363
-            $sql['fields'][$tableName] = $tableName . '.*';
363
+            $sql['fields'][$tableName] = $tableName.'.*';
364 364
             $sql['tables'][$tableName] = $tableName;
365 365
             if ($this->query->getDistinct()) {
366
-                $sql['fields'][$tableName] = $tableName . '.' . $this->query->getDistinct();
366
+                $sql['fields'][$tableName] = $tableName.'.'.$this->query->getDistinct();
367 367
                 $sql['keywords']['distinct'] = 'DISTINCT';
368 368
             }
369 369
         } elseif ($source instanceof JoinInterface) {
@@ -388,15 +388,15 @@  discard block
 block discarded – undo
388 388
             $rightTableName = $rightSource->getLeft()->getSelectorName();
389 389
         } else {
390 390
             $rightTableName = $rightSource->getSelectorName();
391
-            $sql['fields'][$leftTableName] = $rightTableName . '.*';
391
+            $sql['fields'][$leftTableName] = $rightTableName.'.*';
392 392
         }
393 393
         $sql['tables'][$leftTableName] = $leftTableName;
394
-        $sql['unions'][$rightTableName] = 'LEFT JOIN ' . $rightTableName;
394
+        $sql['unions'][$rightTableName] = 'LEFT JOIN '.$rightTableName;
395 395
         $joinCondition = $join->getJoinCondition();
396 396
         if ($joinCondition instanceof \TYPO3\CMS\Extbase\Persistence\Generic\Qom\EquiJoinCondition) {
397 397
             $column1Name = $joinCondition->getProperty1Name();
398 398
             $column2Name = $joinCondition->getProperty2Name();
399
-            $sql['unions'][$rightTableName] .= ' ON ' . $joinCondition->getSelector1Name() . '.' . $column1Name . ' = ' . $joinCondition->getSelector2Name() . '.' . $column2Name;
399
+            $sql['unions'][$rightTableName] .= ' ON '.$joinCondition->getSelector1Name().'.'.$column1Name.' = '.$joinCondition->getSelector2Name().'.'.$column2Name;
400 400
         }
401 401
         if ($rightSource instanceof JoinInterface) {
402 402
             $this->parseJoin($rightSource, $sql);
@@ -534,7 +534,7 @@  discard block
 block discarded – undo
534 534
             if ($realInput instanceof \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface) {
535 535
                 return $realInput->getUid();
536 536
             } else {
537
-                throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\UnexpectedTypeException('An object of class "' . get_class($realInput) . '" could not be converted to a plain value.', 1274799934);
537
+                throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\UnexpectedTypeException('An object of class "'.get_class($realInput).'" could not be converted to a plain value.', 1274799934);
538 538
             }
539 539
         } elseif (is_bool($input)) {
540 540
             return $input === TRUE ? 1 : 0;
@@ -579,9 +579,9 @@  discard block
 block discarded – undo
579 579
             $operator = $this->resolveOperator($operator);
580 580
             $constraintSQL = '';
581 581
             if ($valueFunction === NULL) {
582
-                $constraintSQL .= (!empty($tableName) ? $tableName . '.' : '') . $columnName . ' ' . $operator . ' ?';
582
+                $constraintSQL .= (!empty($tableName) ? $tableName.'.' : '').$columnName.' '.$operator.' ?';
583 583
             } else {
584
-                $constraintSQL .= $valueFunction . '(' . (!empty($tableName) ? $tableName . '.' : '') . $columnName . ') ' . $operator . ' ?';
584
+                $constraintSQL .= $valueFunction.'('.(!empty($tableName) ? $tableName.'.' : '').$columnName.') '.$operator.' ?';
585 585
             }
586 586
 
587 587
             if (isset($tableName) && !empty($this->currentChildTableNameAlias)) {
@@ -611,7 +611,7 @@  discard block
 block discarded – undo
611 611
         // to determine the relation type. Example for sys_category, property path will look like "items.sys_file"
612 612
         if ($table->field($fieldName)->isGroup()) {
613 613
             $parts = explode('.', $propertyPath, 3);
614
-            $explodedPropertyPath[0] = $parts[0] . '.' . $parts[1];
614
+            $explodedPropertyPath[0] = $parts[0].'.'.$parts[1];
615 615
             $explodedPropertyPath[1] = $parts[2];
616 616
             $fieldName = $explodedPropertyPath[0];
617 617
         }
@@ -620,16 +620,16 @@  discard block
 block discarded – undo
620 620
         $childTableName = $table->field($fieldName)->getForeignTable();
621 621
 
622 622
         if ($childTableName === NULL) {
623
-            throw new Exception\InvalidRelationConfigurationException('The relation information for property "' . $fieldName . '" of class "' . $tableName . '" is missing.', 1353170925);
623
+            throw new Exception\InvalidRelationConfigurationException('The relation information for property "'.$fieldName.'" of class "'.$tableName.'" is missing.', 1353170925);
624 624
         }
625 625
 
626 626
         if ($table->field($fieldName)->hasOne()) { // includes relation "one-to-one" and "many-to-one"
627 627
             // sometimes the opposite relation is not defined. We don't want to force this config for backward compatibility reasons.
628 628
             // $parentKeyFieldName === NULL does the trick somehow. Before condition was if (isset($parentKeyFieldName))
629 629
             if ($table->field($fieldName)->hasRelationManyToOne() || $parentKeyFieldName === NULL) {
630
-                $sql['unions'][$childTableName] = 'LEFT JOIN ' . $childTableName . ' ON ' . $tableName . '.' . $fieldName . '=' . $childTableName . '.uid';
630
+                $sql['unions'][$childTableName] = 'LEFT JOIN '.$childTableName.' ON '.$tableName.'.'.$fieldName.'='.$childTableName.'.uid';
631 631
             } else {
632
-                $sql['unions'][$childTableName] = 'LEFT JOIN ' . $childTableName . ' ON ' . $tableName . '.uid=' . $childTableName . '.' . $parentKeyFieldName;
632
+                $sql['unions'][$childTableName] = 'LEFT JOIN '.$childTableName.' ON '.$tableName.'.uid='.$childTableName.'.'.$parentKeyFieldName;
633 633
             }
634 634
         } elseif ($table->field($fieldName)->hasRelationManyToMany()) {
635 635
             $relationTableName = $table->field($fieldName)->getManyToManyTable();
@@ -794,11 +794,11 @@  discard block
 block discarded – undo
794 794
                     foreach ($parameter as $item) {
795 795
                         $items[] = $this->databaseHandle->fullQuoteStr($item, $tableName);
796 796
                     }
797
-                    $parameter = '(' . implode(',', $items) . ')';
797
+                    $parameter = '('.implode(',', $items).')';
798 798
                 } else {
799 799
                     $parameter = $this->databaseHandle->fullQuoteStr($parameter, $tableName);
800 800
                 }
801
-                $sqlString = substr($sqlString, 0, $markPosition) . $parameter . substr($sqlString, ($markPosition + 1));
801
+                $sqlString = substr($sqlString, 0, $markPosition).$parameter.substr($sqlString, ($markPosition + 1));
802 802
             }
803 803
             $offset = $markPosition + strlen($parameter);
804 804
         }
@@ -902,18 +902,18 @@  discard block
 block discarded – undo
902 902
         // If the table is found to have "workspace" support, add the corresponding fields in the statement.
903 903
         if (Tca::table($tableName)->hasWorkspaceSupport()) {
904 904
             if ($this->getBackendUser()->workspace === 0) {
905
-                $statement .= ' AND ' . $tableName . '.t3ver_state<=' . new VersionState(VersionState::DEFAULT_STATE);
905
+                $statement .= ' AND '.$tableName.'.t3ver_state<='.new VersionState(VersionState::DEFAULT_STATE);
906 906
             } else {
907 907
                 // Show only records of live and of the current workspace
908 908
                 // In case we are in a Versioning preview
909
-                $statement .= ' AND (' .
910
-                    $tableName . '.t3ver_wsid=0 OR ' .
911
-                    $tableName . '.t3ver_wsid=' . (int)$this->getBackendUser()->workspace .
909
+                $statement .= ' AND ('.
910
+                    $tableName.'.t3ver_wsid=0 OR '.
911
+                    $tableName.'.t3ver_wsid='.(int)$this->getBackendUser()->workspace.
912 912
                     ')';
913 913
             }
914 914
 
915 915
             // Check if this segment make sense here or whether it should be in the "if" part when we have workspace = 0
916
-            $statement .= ' AND ' . $tableName . '.pid<>-1';
916
+            $statement .= ' AND '.$tableName.'.pid<>-1';
917 917
         }
918 918
 
919 919
         if (!$includeDeleted) {
@@ -939,25 +939,25 @@  discard block
 block discarded – undo
939 939
         if (is_array($GLOBALS['TCA'][$tableName]['ctrl'])) {
940 940
             if (!empty($GLOBALS['TCA'][$tableName]['ctrl']['languageField'])) {
941 941
                 // Select all entries for the current language
942
-                $additionalWhereClause = $tableNameOrAlias . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] . ' IN (' . intval($querySettings->getLanguageUid()) . ',-1)';
942
+                $additionalWhereClause = $tableNameOrAlias.'.'.$GLOBALS['TCA'][$tableName]['ctrl']['languageField'].' IN ('.intval($querySettings->getLanguageUid()).',-1)';
943 943
                 // If any language is set -> get those entries which are not translated yet
944 944
                 // They will be removed by t3lib_page::getRecordOverlay if not matching overlay mode
945 945
                 if (isset($GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'])
946 946
                     && $querySettings->getLanguageUid() > 0
947 947
                 ) {
948
-                    $additionalWhereClause .= ' OR (' . $tableNameOrAlias . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] . '=0' .
949
-                        ' AND ' . $tableNameOrAlias . '.uid NOT IN (SELECT ' . $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'] .
950
-                        ' FROM ' . $tableName .
951
-                        ' WHERE ' . $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'] . '>0' .
952
-                        ' AND ' . $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] . '>0';
948
+                    $additionalWhereClause .= ' OR ('.$tableNameOrAlias.'.'.$GLOBALS['TCA'][$tableName]['ctrl']['languageField'].'=0'.
949
+                        ' AND '.$tableNameOrAlias.'.uid NOT IN (SELECT '.$tableName.'.'.$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'].
950
+                        ' FROM '.$tableName.
951
+                        ' WHERE '.$tableName.'.'.$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'].'>0'.
952
+                        ' AND '.$tableName.'.'.$GLOBALS['TCA'][$tableName]['ctrl']['languageField'].'>0';
953 953
 
954 954
                     // Add delete clause to ensure all entries are loaded
955 955
                     if (isset($GLOBALS['TCA'][$tableName]['ctrl']['delete'])) {
956
-                        $additionalWhereClause .= ' AND ' . $tableNameOrAlias . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['delete'] . '=0';
956
+                        $additionalWhereClause .= ' AND '.$tableNameOrAlias.'.'.$GLOBALS['TCA'][$tableName]['ctrl']['delete'].'=0';
957 957
                     }
958 958
                     $additionalWhereClause .= '))';
959 959
                 }
960
-                $statementParts['additionalWhereClause'][$tableNameOrAlias][] = '(' . $additionalWhereClause . ')';
960
+                $statementParts['additionalWhereClause'][$tableNameOrAlias][] = '('.$additionalWhereClause.')';
961 961
             }
962 962
         }
963 963
     }
@@ -984,13 +984,13 @@  discard block
 block discarded – undo
984 984
             $rootLevel = (int)$GLOBALS['TCA'][$tableName]['ctrl']['rootLevel'];
985 985
             if ($rootLevel) {
986 986
                 if ($rootLevel === 1) {
987
-                    $statementParts['additionalWhereClause'][$tableNameOrAlias][] = $tableNameOrAlias . '.pid = 0';
987
+                    $statementParts['additionalWhereClause'][$tableNameOrAlias][] = $tableNameOrAlias.'.pid = 0';
988 988
                 }
989 989
             } else {
990 990
                 if (empty($storagePageIds)) {
991 991
                     throw new Exception\InconsistentQuerySettingsException('Missing storage page ids.', 1365779762);
992 992
                 }
993
-                $statementParts['additionalWhereClause'][$tableNameOrAlias][] = $tableNameOrAlias . '.pid IN (' . implode(', ', $storagePageIds) . ')';
993
+                $statementParts['additionalWhereClause'][$tableNameOrAlias][] = $tableNameOrAlias.'.pid IN ('.implode(', ', $storagePageIds).')';
994 994
             }
995 995
         }
996 996
     }
@@ -1035,7 +1035,7 @@  discard block
 block discarded – undo
1035 1035
     protected function parseLimitAndOffset($limit, $offset, array &$sql)
1036 1036
     {
1037 1037
         if ($limit !== NULL && $offset !== NULL) {
1038
-            $sql['limit'] = intval($offset) . ', ' . intval($limit);
1038
+            $sql['limit'] = intval($offset).', '.intval($limit);
1039 1039
         } elseif ($limit !== NULL) {
1040 1040
             $sql['limit'] = intval($limit);
1041 1041
         }
@@ -1102,10 +1102,10 @@  discard block
 block discarded – undo
1102 1102
                 && $row[$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']] > 0
1103 1103
             ) {
1104 1104
                 $row = $this->databaseHandle->exec_SELECTgetSingleRow(
1105
-                    $tableName . '.*',
1105
+                    $tableName.'.*',
1106 1106
                     $tableName,
1107
-                    $tableName . '.uid=' . (int)$row[$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']] .
1108
-                    ' AND ' . $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] . '=0'
1107
+                    $tableName.'.uid='.(int)$row[$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']].
1108
+                    ' AND '.$tableName.'.'.$GLOBALS['TCA'][$tableName]['ctrl']['languageField'].'=0'
1109 1109
                 );
1110 1110
             }
1111 1111
         }
@@ -1160,7 +1160,7 @@  discard block
 block discarded – undo
1160 1160
         }
1161 1161
 
1162 1162
         $numberOfAliases = $this->tableNameAliases['aliasIncrement'][$tableName];
1163
-        $tableNameAlias = $tableName . $numberOfAliases;
1163
+        $tableNameAlias = $tableName.$numberOfAliases;
1164 1164
 
1165 1165
         $this->tableNameAliases['aliasIncrement'][$tableName]++;
1166 1166
         $this->tableNameAliases['aliases'][$tableNameAlias] = $tableName;
@@ -1239,7 +1239,7 @@  discard block
 block discarded – undo
1239 1239
     {
1240 1240
         $error = $this->databaseHandle->sql_error();
1241 1241
         if ($error !== '') {
1242
-            $error .= $sql ? ': ' . $sql : '';
1242
+            $error .= $sql ? ': '.$sql : '';
1243 1243
             throw new \TYPO3\CMS\Extbase\Persistence\Generic\Storage\Exception\SqlErrorException($error, 1247602160);
1244 1244
         }
1245 1245
     }
Please login to merge, or discard this patch.
Indentation   +1205 added lines, -1205 removed lines patch added patch discarded remove patch
@@ -32,1209 +32,1209 @@
 block discarded – undo
32 32
 class VidiDbBackend
33 33
 {
34 34
 
35
-    const OPERATOR_EQUAL_TO_NULL = 'operatorEqualToNull';
36
-    const OPERATOR_NOT_EQUAL_TO_NULL = 'operatorNotEqualToNull';
37
-
38
-    /**
39
-     * The TYPO3 database object
40
-     *
41
-     * @var \TYPO3\CMS\Core\Database\DatabaseConnection
42
-     */
43
-    protected $databaseHandle;
44
-
45
-    /**
46
-     * The TYPO3 page repository. Used for language and workspace overlay
47
-     *
48
-     * @var PageRepository
49
-     */
50
-    protected $pageRepository;
51
-
52
-    /**
53
-     * A first-level TypoScript configuration cache
54
-     *
55
-     * @var array
56
-     */
57
-    protected $pageTSConfigCache = array();
58
-
59
-    /**
60
-     * @var \TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface
61
-     * @inject
62
-     */
63
-    protected $configurationManager;
64
-
65
-    /**
66
-     * @var \TYPO3\CMS\Extbase\Service\CacheService
67
-     * @inject
68
-     */
69
-    protected $cacheService;
70
-
71
-    /**
72
-     * @var \TYPO3\CMS\Core\Cache\CacheManager
73
-     * @inject
74
-     */
75
-    protected $cacheManager;
76
-
77
-    /**
78
-     * @var \TYPO3\CMS\Core\Cache\Frontend\VariableFrontend
79
-     */
80
-    protected $tableColumnCache;
81
-
82
-    /**
83
-     * @var \TYPO3\CMS\Extbase\Service\EnvironmentService
84
-     * @inject
85
-     */
86
-    protected $environmentService;
87
-
88
-    /**
89
-     * @var \Fab\Vidi\Persistence\Query
90
-     */
91
-    protected $query;
92
-
93
-    /**
94
-     * Store some info related to table name and its aliases.
95
-     *
96
-     * @var array
97
-     */
98
-    protected $tableNameAliases = array(
99
-        'aliases' => array(),
100
-        'aliasIncrement' => array(),
101
-    );
102
-
103
-    /**
104
-     * Use to store the current foreign table name alias.
105
-     *
106
-     * @var string
107
-     */
108
-    protected $currentChildTableNameAlias = '';
109
-
110
-    /**
111
-     * The default object type being returned.
112
-     *
113
-     * @var string
114
-     */
115
-    protected $objectType = 'Fab\Vidi\Domain\Model\Content';
116
-
117
-    /**
118
-     * Constructor. takes the database handle from $GLOBALS['TYPO3_DB']
119
-     */
120
-    public function __construct(QueryInterface $query)
121
-    {
122
-        $this->query = $query;
123
-        $this->databaseHandle = $GLOBALS['TYPO3_DB'];
124
-    }
125
-
126
-    /**
127
-     * Lifecycle method
128
-     *
129
-     * @return void
130
-     */
131
-    public function initializeObject()
132
-    {
133
-        $this->tableColumnCache = $this->cacheManager->getCache('extbase_typo3dbbackend_tablecolumns');
134
-    }
135
-
136
-    /**
137
-     * @param array $identifier
138
-     * @return string
139
-     */
140
-    protected function parseIdentifier(array $identifier)
141
-    {
142
-        $fieldNames = array_keys($identifier);
143
-        $suffixedFieldNames = array();
144
-        foreach ($fieldNames as $fieldName) {
145
-            $suffixedFieldNames[] = $fieldName . '=?';
146
-        }
147
-        return implode(' AND ', $suffixedFieldNames);
148
-    }
149
-
150
-    /**
151
-     * Returns the result of the query
152
-     */
153
-    public function fetchResult()
154
-    {
155
-
156
-        $parameters = array();
157
-        $statementParts = $this->parseQuery($this->query, $parameters);
158
-        $statementParts = $this->processStatementStructureForRecursiveMMRelation($statementParts); // Mmm... check if that is the right way of doing that.
159
-
160
-        $sql = $this->buildQuery($statementParts);
161
-        $tableName = '';
162
-        if (is_array($statementParts) && !empty(reset($statementParts['tables']))) {
163
-            $tableName = reset($statementParts['tables']);
164
-        }
165
-        $this->replacePlaceholders($sql, $parameters, $tableName);
166
-        #print $sql; exit(); // @debug
167
-
168
-        $result = $this->databaseHandle->sql_query($sql);
169
-        $this->checkSqlErrors($sql);
170
-        $rows = $this->getRowsFromResult($result);
171
-        $this->databaseHandle->sql_free_result($result);
172
-
173
-        return $rows;
174
-    }
175
-
176
-    /**
177
-     * Returns the number of tuples matching the query.
178
-     *
179
-     * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Storage\Exception\BadConstraintException
180
-     * @return int The number of matching tuples
181
-     */
182
-    public function countResult()
183
-    {
184
-
185
-        $parameters = array();
186
-        $statementParts = $this->parseQuery($this->query, $parameters);
187
-        $statementParts = $this->processStatementStructureForRecursiveMMRelation($statementParts); // Mmm... check if that is the right way of doing that.
188
-        // Reset $statementParts for valid table return
189
-        reset($statementParts);
190
-
191
-        // if limit is set, we need to count the rows "manually" as COUNT(*) ignores LIMIT constraints
192
-        if (!empty($statementParts['limit'])) {
193
-            $statement = $this->buildQuery($statementParts);
194
-            $this->replacePlaceholders($statement, $parameters, current($statementParts['tables']));
195
-            #print $statement; exit(); // @debug
196
-            $result = $this->databaseHandle->sql_query($statement);
197
-            $this->checkSqlErrors($statement);
198
-            $count = $this->databaseHandle->sql_num_rows($result);
199
-        } else {
200
-            $statementParts['fields'] = array('COUNT(*)');
201
-            // having orderings without grouping is not compatible with non-MySQL DBMS
202
-            $statementParts['orderings'] = array();
203
-            if (isset($statementParts['keywords']['distinct'])) {
204
-                unset($statementParts['keywords']['distinct']);
205
-                $distinctField = $this->query->getDistinct() ? $this->query->getDistinct() : 'uid';
206
-                $statementParts['fields'] = array('COUNT(DISTINCT ' . reset($statementParts['tables']) . '.' . $distinctField . ')');
207
-            }
208
-
209
-            $statement = $this->buildQuery($statementParts);
210
-            $this->replacePlaceholders($statement, $parameters, current($statementParts['tables']));
211
-
212
-            #print $statement; exit(); // @debug
213
-            $result = $this->databaseHandle->sql_query($statement);
214
-            $this->checkSqlErrors($statement);
215
-            $count = 0;
216
-            if ($result) {
217
-                $row = $this->databaseHandle->sql_fetch_assoc($result);
218
-                $count = current($row);
219
-            }
220
-        }
221
-        $this->databaseHandle->sql_free_result($result);
222
-        return (int)$count;
223
-    }
224
-
225
-    /**
226
-     * Parses the query and returns the SQL statement parts.
227
-     *
228
-     * @param QueryInterface $query The query
229
-     * @param array &$parameters
230
-     * @return array The SQL statement parts
231
-     */
232
-    public function parseQuery(QueryInterface $query, array &$parameters)
233
-    {
234
-        $statementParts = array();
235
-        $statementParts['keywords'] = array();
236
-        $statementParts['tables'] = array();
237
-        $statementParts['unions'] = array();
238
-        $statementParts['fields'] = array();
239
-        $statementParts['where'] = array();
240
-        $statementParts['additionalWhereClause'] = array();
241
-        $statementParts['orderings'] = array();
242
-        $statementParts['limit'] = array();
243
-        $source = $query->getSource();
244
-        $this->parseSource($source, $statementParts);
245
-        $this->parseConstraint($query->getConstraint(), $source, $statementParts, $parameters);
246
-        $this->parseOrderings($query->getOrderings(), $source, $statementParts);
247
-        $this->parseLimitAndOffset($query->getLimit(), $query->getOffset(), $statementParts);
248
-        $tableNames = array_unique(array_keys($statementParts['tables'] + $statementParts['unions']));
249
-        foreach ($tableNames as $tableNameOrAlias) {
250
-            if (is_string($tableNameOrAlias) && strlen($tableNameOrAlias) > 0) {
251
-                $this->addAdditionalWhereClause($query->getQuerySettings(), $tableNameOrAlias, $statementParts);
252
-            }
253
-        }
254
-
255
-        return $statementParts;
256
-    }
257
-
258
-    /**
259
-     * Fiddle with the statement structure to handle recursive MM relations.
260
-     * For the recursive MM query to work, we must invert some values.
261
-     * Let see if that is the best way of doing that...
262
-     *
263
-     * @param array $statementParts
264
-     * @return array
265
-     */
266
-    public function processStatementStructureForRecursiveMMRelation(array $statementParts)
267
-    {
268
-
269
-        if ($this->hasRecursiveMMRelation()) {
270
-            $tableName = $this->query->getType();
271
-
272
-            // In order the MM query to work for a recursive MM query, we must invert some values.
273
-            // tx_domain_model_foo0 (the alias) <--> tx_domain_model_foo (the origin table name)
274
-            $values = array();
275
-            foreach ($statementParts['fields'] as $key => $value) {
276
-                $values[$key] = str_replace($tableName, $tableName . '0', $value);
277
-            }
278
-            $statementParts['fields'] = $values;
279
-
280
-            // Same comment as above.
281
-            $values = array();
282
-            foreach ($statementParts['where'] as $key => $value) {
283
-                $values[$key] = str_replace($tableName . '0', $tableName, $value);
284
-            }
285
-            $statementParts['where'] = $values;
286
-
287
-            // We must be more restrictive by transforming the "left" union by "inner"
288
-            $values = array();
289
-            foreach ($statementParts['unions'] as $key => $value) {
290
-                $values[$key] = str_replace('LEFT JOIN', 'INNER JOIN', $value);
291
-            }
292
-            $statementParts['unions'] = $values;
293
-        }
294
-
295
-        return $statementParts;
296
-    }
297
-
298
-    /**
299
-     * Tell whether there is a recursive MM relation.
300
-     *
301
-     * @return bool
302
-     */
303
-    public function hasRecursiveMMRelation()
304
-    {
305
-        return isset($this->tableNameAliases['aliasIncrement'][$this->query->getType()]);
306
-
307
-    }
308
-
309
-    /**
310
-     * Returns the statement, ready to be executed.
311
-     *
312
-     * @param array $statementParts The SQL statement parts
313
-     * @return string The SQL statement
314
-     */
315
-    public function buildQuery(array $statementParts)
316
-    {
317
-
318
-        // Add more statement to the UNION part.
319
-        if (!empty($statementParts['unions'])) {
320
-            foreach ($statementParts['unions'] as $tableName => $unionPart) {
321
-                if (!empty($statementParts['additionalWhereClause'][$tableName])) {
322
-                    $statementParts['unions'][$tableName] .= ' AND ' . implode(' AND ', $statementParts['additionalWhereClause'][$tableName]);
323
-                }
324
-            }
325
-        }
326
-
327
-        $statement = 'SELECT ' . implode(' ', $statementParts['keywords']) . ' ' . implode(',', $statementParts['fields']) . ' FROM ' . implode(' ', $statementParts['tables']) . ' ' . implode(' ', $statementParts['unions']);
328
-        if (!empty($statementParts['where'])) {
329
-            $statement .= ' WHERE ' . implode('', $statementParts['where']);
330
-            if (!empty($statementParts['additionalWhereClause'][$this->query->getType()])) {
331
-                $statement .= ' AND ' . implode(' AND ', $statementParts['additionalWhereClause'][$this->query->getType()]);
332
-            }
333
-        } elseif (!empty($statementParts['additionalWhereClause'])) {
334
-            $statement .= ' WHERE ' . implode(' AND ', $statementParts['additionalWhereClause'][$this->query->getType()]);
335
-        }
336
-        if (!empty($statementParts['orderings'])) {
337
-            $statement .= ' ORDER BY ' . implode(', ', $statementParts['orderings']);
338
-        }
339
-        if (!empty($statementParts['limit'])) {
340
-            $statement .= ' LIMIT ' . $statementParts['limit'];
341
-        }
342
-
343
-        return $statement;
344
-    }
345
-
346
-    /**
347
-     * Transforms a Query Source into SQL and parameter arrays
348
-     *
349
-     * @param SourceInterface $source The source
350
-     * @param array &$sql
351
-     * @return void
352
-     */
353
-    protected function parseSource(SourceInterface $source, array &$sql)
354
-    {
355
-        if ($source instanceof SelectorInterface) {
356
-            $tableName = $source->getNodeTypeName();
357
-            $sql['fields'][$tableName] = $tableName . '.*';
358
-            $sql['tables'][$tableName] = $tableName;
359
-            if ($this->query->getDistinct()) {
360
-                $sql['fields'][$tableName] = $tableName . '.' . $this->query->getDistinct();
361
-                $sql['keywords']['distinct'] = 'DISTINCT';
362
-            }
363
-        } elseif ($source instanceof JoinInterface) {
364
-            $this->parseJoin($source, $sql);
365
-        }
366
-    }
367
-
368
-    /**
369
-     * Transforms a Join into SQL and parameter arrays
370
-     *
371
-     * @param JoinInterface $join The join
372
-     * @param array &$sql The query parts
373
-     * @return void
374
-     */
375
-    protected function parseJoin(JoinInterface $join, array &$sql)
376
-    {
377
-        $leftSource = $join->getLeft();
378
-        $leftTableName = $leftSource->getSelectorName();
379
-        // $sql['fields'][$leftTableName] = $leftTableName . '.*';
380
-        $rightSource = $join->getRight();
381
-        if ($rightSource instanceof JoinInterface) {
382
-            $rightTableName = $rightSource->getLeft()->getSelectorName();
383
-        } else {
384
-            $rightTableName = $rightSource->getSelectorName();
385
-            $sql['fields'][$leftTableName] = $rightTableName . '.*';
386
-        }
387
-        $sql['tables'][$leftTableName] = $leftTableName;
388
-        $sql['unions'][$rightTableName] = 'LEFT JOIN ' . $rightTableName;
389
-        $joinCondition = $join->getJoinCondition();
390
-        if ($joinCondition instanceof \TYPO3\CMS\Extbase\Persistence\Generic\Qom\EquiJoinCondition) {
391
-            $column1Name = $joinCondition->getProperty1Name();
392
-            $column2Name = $joinCondition->getProperty2Name();
393
-            $sql['unions'][$rightTableName] .= ' ON ' . $joinCondition->getSelector1Name() . '.' . $column1Name . ' = ' . $joinCondition->getSelector2Name() . '.' . $column2Name;
394
-        }
395
-        if ($rightSource instanceof JoinInterface) {
396
-            $this->parseJoin($rightSource, $sql);
397
-        }
398
-    }
399
-
400
-    /**
401
-     * Transforms a constraint into SQL and parameter arrays
402
-     *
403
-     * @param \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ConstraintInterface $constraint The constraint
404
-     * @param SourceInterface $source The source
405
-     * @param array &$sql The query parts
406
-     * @param array &$parameters The parameters that will replace the markers
407
-     * @return void
408
-     */
409
-    protected function parseConstraint(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\ConstraintInterface $constraint = NULL, SourceInterface $source, array &$sql, array &$parameters)
410
-    {
411
-        if ($constraint instanceof \TYPO3\CMS\Extbase\Persistence\Generic\Qom\AndInterface) {
412
-            $sql['where'][] = '(';
413
-            $this->parseConstraint($constraint->getConstraint1(), $source, $sql, $parameters);
414
-            $sql['where'][] = ' AND ';
415
-            $this->parseConstraint($constraint->getConstraint2(), $source, $sql, $parameters);
416
-            $sql['where'][] = ')';
417
-        } elseif ($constraint instanceof \TYPO3\CMS\Extbase\Persistence\Generic\Qom\OrInterface) {
418
-            $sql['where'][] = '(';
419
-            $this->parseConstraint($constraint->getConstraint1(), $source, $sql, $parameters);
420
-            $sql['where'][] = ' OR ';
421
-            $this->parseConstraint($constraint->getConstraint2(), $source, $sql, $parameters);
422
-            $sql['where'][] = ')';
423
-        } elseif ($constraint instanceof \TYPO3\CMS\Extbase\Persistence\Generic\Qom\NotInterface) {
424
-            $sql['where'][] = 'NOT (';
425
-            $this->parseConstraint($constraint->getConstraint(), $source, $sql, $parameters);
426
-            $sql['where'][] = ')';
427
-        } elseif ($constraint instanceof ComparisonInterface) {
428
-            $this->parseComparison($constraint, $source, $sql, $parameters);
429
-        }
430
-    }
431
-
432
-    /**
433
-     * Parse a Comparison into SQL and parameter arrays.
434
-     *
435
-     * @param ComparisonInterface $comparison The comparison to parse
436
-     * @param SourceInterface $source The source
437
-     * @param array &$sql SQL query parts to add to
438
-     * @param array &$parameters Parameters to bind to the SQL
439
-     * @throws Exception\RepositoryException
440
-     * @return void
441
-     */
442
-    protected function parseComparison(ComparisonInterface $comparison, SourceInterface $source, array &$sql, array &$parameters)
443
-    {
444
-        $operand1 = $comparison->getOperand1();
445
-        $operator = $comparison->getOperator();
446
-        $operand2 = $comparison->getOperand2();
447
-        if ($operator === QueryInterface::OPERATOR_IN) {
448
-            $items = array();
449
-            $hasValue = FALSE;
450
-            foreach ($operand2 as $value) {
451
-                $value = $this->getPlainValue($value);
452
-                if ($value !== NULL) {
453
-                    $items[] = $value;
454
-                    $hasValue = TRUE;
455
-                }
456
-            }
457
-            if ($hasValue === FALSE) {
458
-                $sql['where'][] = '1<>1';
459
-            } else {
460
-                $this->parseDynamicOperand($operand1, $operator, $source, $sql, $parameters, NULL);
461
-                $parameters[] = $items;
462
-            }
463
-        } elseif ($operator === QueryInterface::OPERATOR_CONTAINS) {
464
-            if ($operand2 === NULL) {
465
-                $sql['where'][] = '1<>1';
466
-            } else {
467
-                throw new \Exception('Not implemented! Contact extension author.', 1412931227);
468
-                # @todo re-implement me if necessary.
469
-                #$tableName = $this->query->getType();
470
-                #$propertyName = $operand1->getPropertyName();
471
-                #while (strpos($propertyName, '.') !== FALSE) {
472
-                #	$this->addUnionStatement($tableName, $propertyName, $sql);
473
-                #}
474
-                #$columnName = $propertyName;
475
-                #$columnMap = $propertyName;
476
-                #$typeOfRelation = $columnMap instanceof ColumnMap ? $columnMap->getTypeOfRelation() : NULL;
477
-                #if ($typeOfRelation === ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY) {
478
-                #	$relationTableName = $columnMap->getRelationTableName();
479
-                #	$sql['where'][] = $tableName . '.uid IN (SELECT ' . $columnMap->getParentKeyFieldName() . ' FROM ' . $relationTableName . ' WHERE ' . $columnMap->getChildKeyFieldName() . '=?)';
480
-                #	$parameters[] = intval($this->getPlainValue($operand2));
481
-                #} elseif ($typeOfRelation === ColumnMap::RELATION_HAS_MANY) {
482
-                #	$parentKeyFieldName = $columnMap->getParentKeyFieldName();
483
-                #	if (isset($parentKeyFieldName)) {
484
-                #		$childTableName = $columnMap->getChildTableName();
485
-                #		$sql['where'][] = $tableName . '.uid=(SELECT ' . $childTableName . '.' . $parentKeyFieldName . ' FROM ' . $childTableName . ' WHERE ' . $childTableName . '.uid=?)';
486
-                #		$parameters[] = intval($this->getPlainValue($operand2));
487
-                #	} else {
488
-                #		$sql['where'][] = 'FIND_IN_SET(?,' . $tableName . '.' . $columnName . ')';
489
-                #		$parameters[] = intval($this->getPlainValue($operand2));
490
-                #	}
491
-                #} else {
492
-                #	throw new Exception\RepositoryException('Unsupported or non-existing property name "' . $propertyName . '" used in relation matching.', 1327065745);
493
-                #}
494
-            }
495
-        } else {
496
-            if ($operand2 === NULL) {
497
-                if ($operator === QueryInterface::OPERATOR_EQUAL_TO) {
498
-                    $operator = self::OPERATOR_EQUAL_TO_NULL;
499
-                } elseif ($operator === QueryInterface::OPERATOR_NOT_EQUAL_TO) {
500
-                    $operator = self::OPERATOR_NOT_EQUAL_TO_NULL;
501
-                }
502
-            }
503
-            $this->parseDynamicOperand($operand1, $operator, $source, $sql, $parameters);
504
-            $parameters[] = $this->getPlainValue($operand2);
505
-        }
506
-    }
507
-
508
-    /**
509
-     * Returns a plain value, i.e. objects are flattened out if possible.
510
-     *
511
-     * @param mixed $input
512
-     * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\UnexpectedTypeException
513
-     * @return mixed
514
-     */
515
-    protected function getPlainValue($input)
516
-    {
517
-        if (is_array($input)) {
518
-            throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\UnexpectedTypeException('An array could not be converted to a plain value.', 1274799932);
519
-        }
520
-        if ($input instanceof \DateTime) {
521
-            return $input->format('U');
522
-        } elseif (is_object($input)) {
523
-            if ($input instanceof \TYPO3\CMS\Extbase\Persistence\Generic\LazyLoadingProxy) {
524
-                $realInput = $input->_loadRealInstance();
525
-            } else {
526
-                $realInput = $input;
527
-            }
528
-            if ($realInput instanceof \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface) {
529
-                return $realInput->getUid();
530
-            } else {
531
-                throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\UnexpectedTypeException('An object of class "' . get_class($realInput) . '" could not be converted to a plain value.', 1274799934);
532
-            }
533
-        } elseif (is_bool($input)) {
534
-            return $input === TRUE ? 1 : 0;
535
-        } else {
536
-            return $input;
537
-        }
538
-    }
539
-
540
-    /**
541
-     * Parse a DynamicOperand into SQL and parameter arrays.
542
-     *
543
-     * @param DynamicOperandInterface $operand
544
-     * @param string $operator One of the JCR_OPERATOR_* constants
545
-     * @param SourceInterface $source The source
546
-     * @param array &$sql The query parts
547
-     * @param array &$parameters The parameters that will replace the markers
548
-     * @param string $valueFunction an optional SQL function to apply to the operand value
549
-     * @return void
550
-     */
551
-    protected function parseDynamicOperand(DynamicOperandInterface $operand, $operator, SourceInterface $source, array &$sql, array &$parameters, $valueFunction = NULL)
552
-    {
553
-        if ($operand instanceof LowerCaseInterface) {
554
-            $this->parseDynamicOperand($operand->getOperand(), $operator, $source, $sql, $parameters, 'LOWER');
555
-        } elseif ($operand instanceof UpperCaseInterface) {
556
-            $this->parseDynamicOperand($operand->getOperand(), $operator, $source, $sql, $parameters, 'UPPER');
557
-        } elseif ($operand instanceof PropertyValueInterface) {
558
-            $propertyName = $operand->getPropertyName();
559
-
560
-            // Reset value.
561
-            $this->currentChildTableNameAlias = '';
562
-
563
-            if ($source instanceof SelectorInterface) {
564
-                $tableName = $this->query->getType();
565
-                while (strpos($propertyName, '.') !== FALSE) {
566
-                    $this->addUnionStatement($tableName, $propertyName, $sql);
567
-                }
568
-            } elseif ($source instanceof JoinInterface) {
569
-                $tableName = $source->getJoinCondition()->getSelector1Name();
570
-            }
571
-
572
-            $columnName = $propertyName;
573
-            $operator = $this->resolveOperator($operator);
574
-            $constraintSQL = '';
575
-            if ($valueFunction === NULL) {
576
-                $constraintSQL .= (!empty($tableName) ? $tableName . '.' : '') . $columnName . ' ' . $operator . ' ?';
577
-            } else {
578
-                $constraintSQL .= $valueFunction . '(' . (!empty($tableName) ? $tableName . '.' : '') . $columnName . ') ' . $operator . ' ?';
579
-            }
580
-
581
-            if (isset($tableName) && !empty($this->currentChildTableNameAlias)) {
582
-                $constraintSQL = $this->replaceTableNameByAlias($tableName, $this->currentChildTableNameAlias, $constraintSQL);
583
-            }
584
-            $sql['where'][] = $constraintSQL;
585
-        }
586
-    }
587
-
588
-    /**
589
-     * @param string &$tableName
590
-     * @param array &$propertyPath
591
-     * @param array &$sql
592
-     * @throws Exception
593
-     * @throws Exception\InvalidRelationConfigurationException
594
-     * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\MissingColumnMapException
595
-     */
596
-    protected function addUnionStatement(&$tableName, &$propertyPath, array &$sql)
597
-    {
598
-
599
-        $table = Tca::table($tableName);
600
-
601
-        $explodedPropertyPath = explode('.', $propertyPath, 2);
602
-        $fieldName = $explodedPropertyPath[0];
603
-
604
-        // Field of type "group" are special because property path must contain the table name
605
-        // to determine the relation type. Example for sys_category, property path will look like "items.sys_file"
606
-        if ($table->field($fieldName)->isGroup()) {
607
-            $parts = explode('.', $propertyPath, 3);
608
-            $explodedPropertyPath[0] = $parts[0] . '.' . $parts[1];
609
-            $explodedPropertyPath[1] = $parts[2];
610
-            $fieldName = $explodedPropertyPath[0];
611
-        }
612
-
613
-        $parentKeyFieldName = $table->field($fieldName)->getForeignField();
614
-        $childTableName = $table->field($fieldName)->getForeignTable();
615
-
616
-        if ($childTableName === NULL) {
617
-            throw new Exception\InvalidRelationConfigurationException('The relation information for property "' . $fieldName . '" of class "' . $tableName . '" is missing.', 1353170925);
618
-        }
619
-
620
-        if ($table->field($fieldName)->hasOne()) { // includes relation "one-to-one" and "many-to-one"
621
-            // sometimes the opposite relation is not defined. We don't want to force this config for backward compatibility reasons.
622
-            // $parentKeyFieldName === NULL does the trick somehow. Before condition was if (isset($parentKeyFieldName))
623
-            if ($table->field($fieldName)->hasRelationManyToOne() || $parentKeyFieldName === NULL) {
624
-                $sql['unions'][$childTableName] = 'LEFT JOIN ' . $childTableName . ' ON ' . $tableName . '.' . $fieldName . '=' . $childTableName . '.uid';
625
-            } else {
626
-                $sql['unions'][$childTableName] = 'LEFT JOIN ' . $childTableName . ' ON ' . $tableName . '.uid=' . $childTableName . '.' . $parentKeyFieldName;
627
-            }
628
-        } elseif ($table->field($fieldName)->hasRelationManyToMany()) {
629
-            $relationTableName = $table->field($fieldName)->getManyToManyTable();
630
-
631
-            $parentKeyFieldName = $table->field($fieldName)->isOppositeRelation() ? 'uid_foreign' : 'uid_local';
632
-            $childKeyFieldName = !$table->field($fieldName)->isOppositeRelation() ? 'uid_foreign' : 'uid_local';
633
-
634
-            // MM table e.g sys_category_record_mm
635
-            $relationTableNameAlias = $this->generateAlias($relationTableName);
636
-            $join = sprintf(
637
-                'LEFT JOIN %s AS %s ON %s.uid=%s.%s', $relationTableName,
638
-                $relationTableNameAlias,
639
-                $tableName,
640
-                $relationTableNameAlias,
641
-                $parentKeyFieldName
642
-            );
643
-            $sql['unions'][$relationTableNameAlias] = $join;
644
-
645
-            // Foreign table e.g sys_category
646
-            $childTableNameAlias = $this->generateAlias($childTableName);
647
-            $this->currentChildTableNameAlias = $childTableNameAlias;
648
-            $join = sprintf(
649
-                'LEFT JOIN %s AS %s ON %s.%s=%s.uid',
650
-                $childTableName,
651
-                $childTableNameAlias,
652
-                $relationTableNameAlias,
653
-                $childKeyFieldName,
654
-                $childTableNameAlias
655
-            );
656
-            $sql['unions'][$childTableNameAlias] = $join;
657
-
658
-            // Find a possible table name for a MM condition.
659
-            $tableNameCondition = $table->field($fieldName)->getAdditionalTableNameCondition();
660
-            if ($tableNameCondition) {
661
-
662
-                // If we can find a source file name,  we can then retrieve more MM conditions from the TCA such as a field name.
663
-                $sourceFileName = $this->query->getSourceFieldName();
664
-                if (empty($sourceFileName)) {
665
-                    $additionalMMConditions = array(
666
-                        'tablenames' => $tableNameCondition,
667
-                    );
668
-                } else {
669
-                    $additionalMMConditions = Tca::table($tableNameCondition)->field($sourceFileName)->getAdditionalMMCondition();
670
-                }
671
-
672
-                foreach ($additionalMMConditions as $additionalFieldName => $additionalMMCondition) {
673
-                    $additionalJoin = sprintf(' AND %s.%s = "%s"', $relationTableNameAlias, $additionalFieldName, $additionalMMCondition);
674
-                    $sql['unions'][$relationTableNameAlias] .= $additionalJoin;
675
-
676
-                    $additionalJoin = sprintf(' AND %s.%s = "%s"', $relationTableNameAlias, $additionalFieldName, $additionalMMCondition);
677
-                    $sql['unions'][$childTableNameAlias] .= $additionalJoin;
678
-                }
679
-
680
-            }
681
-
682
-
683
-        } elseif ($table->field($fieldName)->hasMany()) { // includes relations "many-to-one" and "csv" relations
684
-            $childTableNameAlias = $this->generateAlias($childTableName);
685
-            $this->currentChildTableNameAlias = $childTableNameAlias;
686
-
687
-            if (isset($parentKeyFieldName)) {
688
-                $join = sprintf(
689
-                    'LEFT JOIN %s AS %s ON %s.uid=%s.%s',
690
-                    $childTableName,
691
-                    $childTableNameAlias,
692
-                    $tableName,
693
-                    $childTableNameAlias,
694
-                    $parentKeyFieldName
695
-                );
696
-                $sql['unions'][$childTableNameAlias] = $join;
697
-            } else {
698
-                $join = sprintf(
699
-                    'LEFT JOIN %s AS %s ON (FIND_IN_SET(%s.uid, %s.%s))',
700
-                    $childTableName,
701
-                    $childTableNameAlias,
702
-                    $childTableNameAlias,
703
-                    $tableName,
704
-                    $fieldName
705
-                );
706
-                $sql['unions'][$childTableNameAlias] = $join;
707
-            }
708
-        } else {
709
-            throw new Exception('Could not determine type of relation.', 1252502725);
710
-        }
711
-
712
-        // TODO check if there is another solution for this
713
-        $sql['keywords']['distinct'] = 'DISTINCT';
714
-        $propertyPath = $explodedPropertyPath[1];
715
-        $tableName = $childTableName;
716
-    }
717
-
718
-    /**
719
-     * Returns the SQL operator for the given JCR operator type.
720
-     *
721
-     * @param string $operator One of the JCR_OPERATOR_* constants
722
-     * @throws Exception
723
-     * @return string an SQL operator
724
-     */
725
-    protected function resolveOperator($operator)
726
-    {
727
-        switch ($operator) {
728
-            case self::OPERATOR_EQUAL_TO_NULL:
729
-                $operator = 'IS';
730
-                break;
731
-            case self::OPERATOR_NOT_EQUAL_TO_NULL:
732
-                $operator = 'IS NOT';
733
-                break;
734
-            case QueryInterface::OPERATOR_IN:
735
-                $operator = 'IN';
736
-                break;
737
-            case QueryInterface::OPERATOR_EQUAL_TO:
738
-                $operator = '=';
739
-                break;
740
-            case QueryInterface::OPERATOR_NOT_EQUAL_TO:
741
-                $operator = '!=';
742
-                break;
743
-            case QueryInterface::OPERATOR_LESS_THAN:
744
-                $operator = '<';
745
-                break;
746
-            case QueryInterface::OPERATOR_LESS_THAN_OR_EQUAL_TO:
747
-                $operator = '<=';
748
-                break;
749
-            case QueryInterface::OPERATOR_GREATER_THAN:
750
-                $operator = '>';
751
-                break;
752
-            case QueryInterface::OPERATOR_GREATER_THAN_OR_EQUAL_TO:
753
-                $operator = '>=';
754
-                break;
755
-            case QueryInterface::OPERATOR_LIKE:
756
-                $operator = 'LIKE';
757
-                break;
758
-            default:
759
-                throw new Exception('Unsupported operator encountered.', 1242816073);
760
-        }
761
-        return $operator;
762
-    }
763
-
764
-    /**
765
-     * Replace query placeholders in a query part by the given
766
-     * parameters.
767
-     *
768
-     * @param string &$sqlString The query part with placeholders
769
-     * @param array $parameters The parameters
770
-     * @param string $tableName
771
-     *
772
-     * @throws Exception
773
-     */
774
-    protected function replacePlaceholders(&$sqlString, array $parameters, $tableName = 'foo')
775
-    {
776
-        // TODO profile this method again
777
-        if (substr_count($sqlString, '?') !== count($parameters)) {
778
-            throw new Exception('The number of question marks to replace must be equal to the number of parameters.', 1242816074);
779
-        }
780
-        $offset = 0;
781
-        foreach ($parameters as $parameter) {
782
-            $markPosition = strpos($sqlString, '?', $offset);
783
-            if ($markPosition !== FALSE) {
784
-                if ($parameter === NULL) {
785
-                    $parameter = 'NULL';
786
-                } elseif (is_array($parameter) || $parameter instanceof \ArrayAccess || $parameter instanceof \Traversable) {
787
-                    $items = array();
788
-                    foreach ($parameter as $item) {
789
-                        $items[] = $this->databaseHandle->fullQuoteStr($item, $tableName);
790
-                    }
791
-                    $parameter = '(' . implode(',', $items) . ')';
792
-                } else {
793
-                    $parameter = $this->databaseHandle->fullQuoteStr($parameter, $tableName);
794
-                }
795
-                $sqlString = substr($sqlString, 0, $markPosition) . $parameter . substr($sqlString, ($markPosition + 1));
796
-            }
797
-            $offset = $markPosition + strlen($parameter);
798
-        }
799
-    }
800
-
801
-    /**
802
-     * Adds additional WHERE statements according to the query settings.
803
-     *
804
-     * @param QuerySettingsInterface $querySettings The TYPO3 CMS specific query settings
805
-     * @param string $tableNameOrAlias The table name to add the additional where clause for
806
-     * @param array &$statementParts
807
-     * @return void
808
-     */
809
-    protected function addAdditionalWhereClause(QuerySettingsInterface $querySettings, $tableNameOrAlias, &$statementParts)
810
-    {
811
-        $this->addVisibilityConstraintStatement($querySettings, $tableNameOrAlias, $statementParts);
812
-        if ($querySettings->getRespectSysLanguage()) {
813
-            $this->addSysLanguageStatement($tableNameOrAlias, $statementParts, $querySettings);
814
-        }
815
-        if ($querySettings->getRespectStoragePage()) {
816
-            $this->addPageIdStatement($tableNameOrAlias, $statementParts, $querySettings->getStoragePageIds());
817
-        }
818
-    }
819
-
820
-    /**
821
-     * Adds enableFields and deletedClause to the query if necessary
822
-     *
823
-     * @param QuerySettingsInterface $querySettings
824
-     * @param string $tableNameOrAlias The database table name
825
-     * @param array &$statementParts The query parts
826
-     * @return void
827
-     */
828
-    protected function addVisibilityConstraintStatement(QuerySettingsInterface $querySettings, $tableNameOrAlias, array &$statementParts)
829
-    {
830
-        $statement = '';
831
-        $tableName = $this->resolveTableNameAlias($tableNameOrAlias);
832
-        if (is_array($GLOBALS['TCA'][$tableName]['ctrl'])) {
833
-            $ignoreEnableFields = $querySettings->getIgnoreEnableFields();
834
-            $enableFieldsToBeIgnored = $querySettings->getEnableFieldsToBeIgnored();
835
-            $includeDeleted = $querySettings->getIncludeDeleted();
836
-            if ($this->environmentService->isEnvironmentInFrontendMode()) {
837
-                $statement .= $this->getFrontendConstraintStatement($tableNameOrAlias, $ignoreEnableFields, $enableFieldsToBeIgnored, $includeDeleted);
838
-            } else {
839
-                // TYPO3_MODE === 'BE'
840
-                $statement .= $this->getBackendConstraintStatement($tableNameOrAlias, $ignoreEnableFields, $includeDeleted);
841
-            }
842
-
843
-            // Remove the prefixing "AND" if any.
844
-            if (!empty($statement)) {
845
-                $statement = strtolower(substr($statement, 1, 3)) === 'and' ? substr($statement, 5) : $statement;
846
-                $statementParts['additionalWhereClause'][$tableNameOrAlias][] = $statement;
847
-            }
848
-        }
849
-    }
850
-
851
-    /**
852
-     * Returns constraint statement for frontend context
853
-     *
854
-     * @param string $tableNameOrAlias
855
-     * @param boolean $ignoreEnableFields A flag indicating whether the enable fields should be ignored
856
-     * @param array $enableFieldsToBeIgnored If $ignoreEnableFields is true, this array specifies enable fields to be ignored. If it is NULL or an empty array (default) all enable fields are ignored.
857
-     * @param boolean $includeDeleted A flag indicating whether deleted records should be included
858
-     * @return string
859
-     * @throws Exception\InconsistentQuerySettingsException
860
-     */
861
-    protected function getFrontendConstraintStatement($tableNameOrAlias, $ignoreEnableFields, $enableFieldsToBeIgnored = array(), $includeDeleted)
862
-    {
863
-        $statement = '';
864
-        $tableName = $this->resolveTableNameAlias($tableNameOrAlias);
865
-        if ($ignoreEnableFields && !$includeDeleted) {
866
-            if (count($enableFieldsToBeIgnored)) {
867
-                // array_combine() is necessary because of the way \TYPO3\CMS\Frontend\Page\PageRepository::enableFields() is implemented
868
-                $statement .= $this->getPageRepository()->enableFields($tableName, -1, array_combine($enableFieldsToBeIgnored, $enableFieldsToBeIgnored));
869
-            } else {
870
-                $statement .= $this->getPageRepository()->deleteClause($tableName);
871
-            }
872
-        } elseif (!$ignoreEnableFields && !$includeDeleted) {
873
-            $statement .= $this->getPageRepository()->enableFields($tableName);
874
-        } elseif (!$ignoreEnableFields && $includeDeleted) {
875
-            throw new Exception\InconsistentQuerySettingsException('Query setting "ignoreEnableFields=FALSE" can not be used together with "includeDeleted=TRUE" in frontend context.', 1327678173);
876
-        }
877
-        return $this->replaceTableNameByAlias($tableName, $tableNameOrAlias, $statement);
878
-    }
879
-
880
-    /**
881
-     * Returns constraint statement for backend context
882
-     *
883
-     * @param string $tableNameOrAlias
884
-     * @param boolean $ignoreEnableFields A flag indicating whether the enable fields should be ignored
885
-     * @param boolean $includeDeleted A flag indicating whether deleted records should be included
886
-     * @return string
887
-     */
888
-    protected function getBackendConstraintStatement($tableNameOrAlias, $ignoreEnableFields, $includeDeleted)
889
-    {
890
-        $tableName = $this->resolveTableNameAlias($tableNameOrAlias);
891
-        $statement = '';
892
-        if (!$ignoreEnableFields) {
893
-            $statement .= BackendUtility::BEenableFields($tableName);
894
-        }
895
-
896
-        // If the table is found to have "workspace" support, add the corresponding fields in the statement.
897
-        if (Tca::table($tableName)->hasWorkspaceSupport()) {
898
-            if ($this->getBackendUser()->workspace === 0) {
899
-                $statement .= ' AND ' . $tableName . '.t3ver_state<=' . new VersionState(VersionState::DEFAULT_STATE);
900
-            } else {
901
-                // Show only records of live and of the current workspace
902
-                // In case we are in a Versioning preview
903
-                $statement .= ' AND (' .
904
-                    $tableName . '.t3ver_wsid=0 OR ' .
905
-                    $tableName . '.t3ver_wsid=' . (int)$this->getBackendUser()->workspace .
906
-                    ')';
907
-            }
908
-
909
-            // Check if this segment make sense here or whether it should be in the "if" part when we have workspace = 0
910
-            $statement .= ' AND ' . $tableName . '.pid<>-1';
911
-        }
912
-
913
-        if (!$includeDeleted) {
914
-            $statement .= BackendUtility::deleteClause($tableName);
915
-        }
916
-
917
-        return $this->replaceTableNameByAlias($tableName, $tableNameOrAlias, $statement);
918
-    }
919
-
920
-    /**
921
-     * Builds the language field statement
922
-     *
923
-     * @param string $tableNameOrAlias The database table name
924
-     * @param array &$statementParts The query parts
925
-     * @param QuerySettingsInterface $querySettings The TYPO3 CMS specific query settings
926
-     * @throws Exception
927
-     * @return void
928
-     */
929
-    protected function addSysLanguageStatement($tableNameOrAlias, array &$statementParts, $querySettings)
930
-    {
931
-
932
-        $tableName = $this->resolveTableNameAlias($tableNameOrAlias);
933
-        if (is_array($GLOBALS['TCA'][$tableName]['ctrl'])) {
934
-            if (!empty($GLOBALS['TCA'][$tableName]['ctrl']['languageField'])) {
935
-                // Select all entries for the current language
936
-                $additionalWhereClause = $tableNameOrAlias . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] . ' IN (' . intval($querySettings->getLanguageUid()) . ',-1)';
937
-                // If any language is set -> get those entries which are not translated yet
938
-                // They will be removed by t3lib_page::getRecordOverlay if not matching overlay mode
939
-                if (isset($GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'])
940
-                    && $querySettings->getLanguageUid() > 0
941
-                ) {
942
-                    $additionalWhereClause .= ' OR (' . $tableNameOrAlias . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] . '=0' .
943
-                        ' AND ' . $tableNameOrAlias . '.uid NOT IN (SELECT ' . $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'] .
944
-                        ' FROM ' . $tableName .
945
-                        ' WHERE ' . $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'] . '>0' .
946
-                        ' AND ' . $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] . '>0';
947
-
948
-                    // Add delete clause to ensure all entries are loaded
949
-                    if (isset($GLOBALS['TCA'][$tableName]['ctrl']['delete'])) {
950
-                        $additionalWhereClause .= ' AND ' . $tableNameOrAlias . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['delete'] . '=0';
951
-                    }
952
-                    $additionalWhereClause .= '))';
953
-                }
954
-                $statementParts['additionalWhereClause'][$tableNameOrAlias][] = '(' . $additionalWhereClause . ')';
955
-            }
956
-        }
957
-    }
958
-
959
-    /**
960
-     * Builds the page ID checking statement
961
-     *
962
-     * @param string $tableNameOrAlias The database table name
963
-     * @param array &$statementParts The query parts
964
-     * @param array $storagePageIds list of storage page ids
965
-     * @throws Exception\InconsistentQuerySettingsException
966
-     * @return void
967
-     */
968
-    protected function addPageIdStatement($tableNameOrAlias, array &$statementParts, array $storagePageIds)
969
-    {
970
-
971
-        $tableName = $this->resolveTableNameAlias($tableNameOrAlias);
972
-        $tableColumns = $this->tableColumnCache->get($tableName);
973
-        if ($tableColumns === FALSE) {
974
-            $tableColumns = $this->databaseHandle->admin_get_fields($tableName);
975
-            $this->tableColumnCache->set($tableName, $tableColumns);
976
-        }
977
-        if (is_array($GLOBALS['TCA'][$tableName]['ctrl']) && array_key_exists('pid', $tableColumns)) {
978
-            $rootLevel = (int)$GLOBALS['TCA'][$tableName]['ctrl']['rootLevel'];
979
-            if ($rootLevel) {
980
-                if ($rootLevel === 1) {
981
-                    $statementParts['additionalWhereClause'][$tableNameOrAlias][] = $tableNameOrAlias . '.pid = 0';
982
-                }
983
-            } else {
984
-                if (empty($storagePageIds)) {
985
-                    throw new Exception\InconsistentQuerySettingsException('Missing storage page ids.', 1365779762);
986
-                }
987
-                $statementParts['additionalWhereClause'][$tableNameOrAlias][] = $tableNameOrAlias . '.pid IN (' . implode(', ', $storagePageIds) . ')';
988
-            }
989
-        }
990
-    }
991
-
992
-    /**
993
-     * Transforms orderings into SQL.
994
-     *
995
-     * @param array $orderings An array of orderings (Tx_Extbase_Persistence_QOM_Ordering)
996
-     * @param SourceInterface $source The source
997
-     * @param array &$sql The query parts
998
-     * @throws Exception\UnsupportedOrderException
999
-     * @return void
1000
-     */
1001
-    protected function parseOrderings(array $orderings, SourceInterface $source, array &$sql)
1002
-    {
1003
-        foreach ($orderings as $fieldNameAndPath => $order) {
1004
-            switch ($order) {
1005
-                case QueryInterface::ORDER_ASCENDING:
1006
-                    $order = 'ASC';
1007
-                    break;
1008
-                case QueryInterface::ORDER_DESCENDING:
1009
-                    $order = 'DESC';
1010
-                    break;
1011
-                default:
1012
-                    throw new Exception\UnsupportedOrderException('Unsupported order encountered.', 1456845126);
1013
-            }
1014
-
1015
-            $tableName = $this->getFieldPathResolver()->getDataType($fieldNameAndPath, $this->query->getType());
1016
-            $fieldName = $this->getFieldPathResolver()->stripFieldPath($fieldNameAndPath, $tableName);
1017
-            $sql['orderings'][] = sprintf('%s.%s %s', $tableName, $fieldName, $order);
1018
-        }
1019
-    }
1020
-
1021
-    /**
1022
-     * Transforms limit and offset into SQL
1023
-     *
1024
-     * @param int $limit
1025
-     * @param int $offset
1026
-     * @param array &$sql
1027
-     * @return void
1028
-     */
1029
-    protected function parseLimitAndOffset($limit, $offset, array &$sql)
1030
-    {
1031
-        if ($limit !== NULL && $offset !== NULL) {
1032
-            $sql['limit'] = intval($offset) . ', ' . intval($limit);
1033
-        } elseif ($limit !== NULL) {
1034
-            $sql['limit'] = intval($limit);
1035
-        }
1036
-    }
1037
-
1038
-    /**
1039
-     * Transforms a Resource from a database query to an array of rows.
1040
-     *
1041
-     * @param resource $result The result
1042
-     * @return array The result as an array of rows (tuples)
1043
-     */
1044
-    protected function getRowsFromResult($result)
1045
-    {
1046
-        $rows = array();
1047
-        while ($row = $this->databaseHandle->sql_fetch_assoc($result)) {
1048
-            if (is_array($row)) {
1049
-
1050
-                // Get language uid from querySettings.
1051
-                // Ensure the backend handling is not broken (fallback to Get parameter 'L' if needed)
1052
-                $overlaidRow = $this->doLanguageAndWorkspaceOverlay($this->query->getSource(), $row, $this->query->getQuerySettings());
1053
-                $contentObject = GeneralUtility::makeInstance($this->objectType, $this->query->getType(), $overlaidRow);
1054
-                $rows[] = $contentObject;
1055
-            }
1056
-        }
1057
-
1058
-        return $rows;
1059
-    }
1060
-
1061
-    /**
1062
-     * Performs workspace and language overlay on the given row array. The language and workspace id is automatically
1063
-     * detected (depending on FE or BE context). You can also explicitly set the language/workspace id.
1064
-     *
1065
-     * @param SourceInterface $source The source (selector od join)
1066
-     * @param array $row
1067
-     * @param QuerySettingsInterface $querySettings The TYPO3 CMS specific query settings
1068
-     * @return array
1069
-     */
1070
-    protected function doLanguageAndWorkspaceOverlay(SourceInterface $source, array $row, $querySettings)
1071
-    {
1072
-
1073
-        /** @var SelectorInterface $source */
1074
-        $tableName = $source->getSelectorName();
1075
-
1076
-        $pageRepository = $this->getPageRepository();
1077
-        if (is_object($GLOBALS['TSFE'])) {
1078
-            $languageMode = $GLOBALS['TSFE']->sys_language_mode;
1079
-            if ($this->isBackendUserLogged() && $this->getBackendUser()->workspace !== 0) {
1080
-                $pageRepository->versioningWorkspaceId = $this->getBackendUser()->workspace;
1081
-            }
1082
-        } else {
1083
-            $languageMode = '';
1084
-            $workspaceUid = $this->getBackendUser()->workspace;
1085
-            $pageRepository->versioningWorkspaceId = $workspaceUid;
1086
-            if ($this->getBackendUser()->workspace !== 0) {
1087
-                $pageRepository->versioningPreview = 1;
1088
-            }
1089
-        }
1090
-
1091
-        // If current row is a translation select its parent
1092
-        if (isset($GLOBALS['TCA'][$tableName]['ctrl']['languageField'])
1093
-            && isset($GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'])
1094
-        ) {
1095
-            if (isset($row[$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']])
1096
-                && $row[$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']] > 0
1097
-            ) {
1098
-                $row = $this->databaseHandle->exec_SELECTgetSingleRow(
1099
-                    $tableName . '.*',
1100
-                    $tableName,
1101
-                    $tableName . '.uid=' . (int)$row[$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']] .
1102
-                    ' AND ' . $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] . '=0'
1103
-                );
1104
-            }
1105
-        }
1106
-
1107
-        // Retrieve the original uid; Used for Workspaces!
1108
-        $pageRepository->versionOL($tableName, $row, true, true);
1109
-        if ($pageRepository->versioningPreview && isset($row['_ORIG_uid'])) {
1110
-            $row['uid'] = $row['_ORIG_uid'];
1111
-        }
1112
-
1113
-        // Special case for table "pages"
1114
-        if ($tableName == 'pages') {
1115
-            $row = $pageRepository->getPageOverlay($row, $querySettings->getLanguageUid());
1116
-        } elseif (isset($GLOBALS['TCA'][$tableName]['ctrl']['languageField'])
1117
-            && $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] !== ''
1118
-        ) {
1119
-            if (in_array($row[$GLOBALS['TCA'][$tableName]['ctrl']['languageField']], array(-1, 0))) {
1120
-                $overlayMode = $languageMode === 'strict' ? 'hideNonTranslated' : '';
1121
-                $row = $pageRepository->getRecordOverlay($tableName, $row, $querySettings->getLanguageUid(), $overlayMode);
1122
-            }
1123
-        }
1124
-
1125
-        return $row;
1126
-    }
1127
-
1128
-    /**
1129
-     * Return a resolved table name given a possible table name alias.
1130
-     *
1131
-     * @param string $tableNameOrAlias
1132
-     * @return string
1133
-     */
1134
-    protected function resolveTableNameAlias($tableNameOrAlias)
1135
-    {
1136
-        $resolvedTableName = $tableNameOrAlias;
1137
-        if (!empty($this->tableNameAliases['aliases'][$tableNameOrAlias])) {
1138
-            $resolvedTableName = $this->tableNameAliases['aliases'][$tableNameOrAlias];
1139
-        }
1140
-        return $resolvedTableName;
1141
-    }
1142
-
1143
-    /**
1144
-     * Generate a unique table name alias for the given table name.
1145
-     *
1146
-     * @param string $tableName
1147
-     * @return string
1148
-     */
1149
-    protected function generateAlias($tableName)
1150
-    {
1151
-
1152
-        if (!isset($this->tableNameAliases['aliasIncrement'][$tableName])) {
1153
-            $this->tableNameAliases['aliasIncrement'][$tableName] = 0;
1154
-        }
1155
-
1156
-        $numberOfAliases = $this->tableNameAliases['aliasIncrement'][$tableName];
1157
-        $tableNameAlias = $tableName . $numberOfAliases;
1158
-
1159
-        $this->tableNameAliases['aliasIncrement'][$tableName]++;
1160
-        $this->tableNameAliases['aliases'][$tableNameAlias] = $tableName;
1161
-
1162
-        return $tableNameAlias;
1163
-    }
1164
-
1165
-    /**
1166
-     * Replace the table names by its table name alias within the given statement.
1167
-     *
1168
-     * @param string $tableName
1169
-     * @param string $tableNameAlias
1170
-     * @param string $statement
1171
-     * @return string
1172
-     */
1173
-    protected function replaceTableNameByAlias($tableName, $tableNameAlias, $statement)
1174
-    {
1175
-        if ($statement && $tableName !== $tableNameAlias) {
1176
-            $statement = str_replace($tableName, $tableNameAlias, $statement);
1177
-        }
1178
-        return $statement;
1179
-    }
1180
-
1181
-    /**
1182
-     * Returns an instance of the current Backend User.
1183
-     *
1184
-     * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
1185
-     */
1186
-    protected function getBackendUser()
1187
-    {
1188
-        return $GLOBALS['BE_USER'];
1189
-    }
1190
-
1191
-    /**
1192
-     * Tell whether a Backend User is logged in.
1193
-     *
1194
-     * @return bool
1195
-     */
1196
-    protected function isBackendUserLogged()
1197
-    {
1198
-        return is_object($GLOBALS['BE_USER']);
1199
-    }
1200
-
1201
-    /**
1202
-     * @return PageRepository
1203
-     */
1204
-    protected function getPageRepository()
1205
-    {
1206
-        if (!$this->pageRepository instanceof PageRepository) {
1207
-            if ($this->environmentService->isEnvironmentInFrontendMode() && is_object($GLOBALS['TSFE'])) {
1208
-                $this->pageRepository = $GLOBALS['TSFE']->sys_page;
1209
-            } else {
1210
-                $this->pageRepository = GeneralUtility::makeInstance('TYPO3\\CMS\\Frontend\\Page\\PageRepository');
1211
-            }
1212
-        }
1213
-
1214
-        return $this->pageRepository;
1215
-    }
1216
-
1217
-    /**
1218
-     * @return \Fab\Vidi\Resolver\FieldPathResolver
1219
-     */
1220
-    protected function getFieldPathResolver()
1221
-    {
1222
-        return GeneralUtility::makeInstance('Fab\Vidi\Resolver\FieldPathResolver');
1223
-    }
1224
-
1225
-    /**
1226
-     * Checks if there are SQL errors in the last query, and if yes, throw an exception.
1227
-     *
1228
-     * @return void
1229
-     * @param string $sql The SQL statement
1230
-     * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Storage\Exception\SqlErrorException
1231
-     */
1232
-    protected function checkSqlErrors($sql = '')
1233
-    {
1234
-        $error = $this->databaseHandle->sql_error();
1235
-        if ($error !== '') {
1236
-            $error .= $sql ? ': ' . $sql : '';
1237
-            throw new \TYPO3\CMS\Extbase\Persistence\Generic\Storage\Exception\SqlErrorException($error, 1247602160);
1238
-        }
1239
-    }
35
+	const OPERATOR_EQUAL_TO_NULL = 'operatorEqualToNull';
36
+	const OPERATOR_NOT_EQUAL_TO_NULL = 'operatorNotEqualToNull';
37
+
38
+	/**
39
+	 * The TYPO3 database object
40
+	 *
41
+	 * @var \TYPO3\CMS\Core\Database\DatabaseConnection
42
+	 */
43
+	protected $databaseHandle;
44
+
45
+	/**
46
+	 * The TYPO3 page repository. Used for language and workspace overlay
47
+	 *
48
+	 * @var PageRepository
49
+	 */
50
+	protected $pageRepository;
51
+
52
+	/**
53
+	 * A first-level TypoScript configuration cache
54
+	 *
55
+	 * @var array
56
+	 */
57
+	protected $pageTSConfigCache = array();
58
+
59
+	/**
60
+	 * @var \TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface
61
+	 * @inject
62
+	 */
63
+	protected $configurationManager;
64
+
65
+	/**
66
+	 * @var \TYPO3\CMS\Extbase\Service\CacheService
67
+	 * @inject
68
+	 */
69
+	protected $cacheService;
70
+
71
+	/**
72
+	 * @var \TYPO3\CMS\Core\Cache\CacheManager
73
+	 * @inject
74
+	 */
75
+	protected $cacheManager;
76
+
77
+	/**
78
+	 * @var \TYPO3\CMS\Core\Cache\Frontend\VariableFrontend
79
+	 */
80
+	protected $tableColumnCache;
81
+
82
+	/**
83
+	 * @var \TYPO3\CMS\Extbase\Service\EnvironmentService
84
+	 * @inject
85
+	 */
86
+	protected $environmentService;
87
+
88
+	/**
89
+	 * @var \Fab\Vidi\Persistence\Query
90
+	 */
91
+	protected $query;
92
+
93
+	/**
94
+	 * Store some info related to table name and its aliases.
95
+	 *
96
+	 * @var array
97
+	 */
98
+	protected $tableNameAliases = array(
99
+		'aliases' => array(),
100
+		'aliasIncrement' => array(),
101
+	);
102
+
103
+	/**
104
+	 * Use to store the current foreign table name alias.
105
+	 *
106
+	 * @var string
107
+	 */
108
+	protected $currentChildTableNameAlias = '';
109
+
110
+	/**
111
+	 * The default object type being returned.
112
+	 *
113
+	 * @var string
114
+	 */
115
+	protected $objectType = 'Fab\Vidi\Domain\Model\Content';
116
+
117
+	/**
118
+	 * Constructor. takes the database handle from $GLOBALS['TYPO3_DB']
119
+	 */
120
+	public function __construct(QueryInterface $query)
121
+	{
122
+		$this->query = $query;
123
+		$this->databaseHandle = $GLOBALS['TYPO3_DB'];
124
+	}
125
+
126
+	/**
127
+	 * Lifecycle method
128
+	 *
129
+	 * @return void
130
+	 */
131
+	public function initializeObject()
132
+	{
133
+		$this->tableColumnCache = $this->cacheManager->getCache('extbase_typo3dbbackend_tablecolumns');
134
+	}
135
+
136
+	/**
137
+	 * @param array $identifier
138
+	 * @return string
139
+	 */
140
+	protected function parseIdentifier(array $identifier)
141
+	{
142
+		$fieldNames = array_keys($identifier);
143
+		$suffixedFieldNames = array();
144
+		foreach ($fieldNames as $fieldName) {
145
+			$suffixedFieldNames[] = $fieldName . '=?';
146
+		}
147
+		return implode(' AND ', $suffixedFieldNames);
148
+	}
149
+
150
+	/**
151
+	 * Returns the result of the query
152
+	 */
153
+	public function fetchResult()
154
+	{
155
+
156
+		$parameters = array();
157
+		$statementParts = $this->parseQuery($this->query, $parameters);
158
+		$statementParts = $this->processStatementStructureForRecursiveMMRelation($statementParts); // Mmm... check if that is the right way of doing that.
159
+
160
+		$sql = $this->buildQuery($statementParts);
161
+		$tableName = '';
162
+		if (is_array($statementParts) && !empty(reset($statementParts['tables']))) {
163
+			$tableName = reset($statementParts['tables']);
164
+		}
165
+		$this->replacePlaceholders($sql, $parameters, $tableName);
166
+		#print $sql; exit(); // @debug
167
+
168
+		$result = $this->databaseHandle->sql_query($sql);
169
+		$this->checkSqlErrors($sql);
170
+		$rows = $this->getRowsFromResult($result);
171
+		$this->databaseHandle->sql_free_result($result);
172
+
173
+		return $rows;
174
+	}
175
+
176
+	/**
177
+	 * Returns the number of tuples matching the query.
178
+	 *
179
+	 * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Storage\Exception\BadConstraintException
180
+	 * @return int The number of matching tuples
181
+	 */
182
+	public function countResult()
183
+	{
184
+
185
+		$parameters = array();
186
+		$statementParts = $this->parseQuery($this->query, $parameters);
187
+		$statementParts = $this->processStatementStructureForRecursiveMMRelation($statementParts); // Mmm... check if that is the right way of doing that.
188
+		// Reset $statementParts for valid table return
189
+		reset($statementParts);
190
+
191
+		// if limit is set, we need to count the rows "manually" as COUNT(*) ignores LIMIT constraints
192
+		if (!empty($statementParts['limit'])) {
193
+			$statement = $this->buildQuery($statementParts);
194
+			$this->replacePlaceholders($statement, $parameters, current($statementParts['tables']));
195
+			#print $statement; exit(); // @debug
196
+			$result = $this->databaseHandle->sql_query($statement);
197
+			$this->checkSqlErrors($statement);
198
+			$count = $this->databaseHandle->sql_num_rows($result);
199
+		} else {
200
+			$statementParts['fields'] = array('COUNT(*)');
201
+			// having orderings without grouping is not compatible with non-MySQL DBMS
202
+			$statementParts['orderings'] = array();
203
+			if (isset($statementParts['keywords']['distinct'])) {
204
+				unset($statementParts['keywords']['distinct']);
205
+				$distinctField = $this->query->getDistinct() ? $this->query->getDistinct() : 'uid';
206
+				$statementParts['fields'] = array('COUNT(DISTINCT ' . reset($statementParts['tables']) . '.' . $distinctField . ')');
207
+			}
208
+
209
+			$statement = $this->buildQuery($statementParts);
210
+			$this->replacePlaceholders($statement, $parameters, current($statementParts['tables']));
211
+
212
+			#print $statement; exit(); // @debug
213
+			$result = $this->databaseHandle->sql_query($statement);
214
+			$this->checkSqlErrors($statement);
215
+			$count = 0;
216
+			if ($result) {
217
+				$row = $this->databaseHandle->sql_fetch_assoc($result);
218
+				$count = current($row);
219
+			}
220
+		}
221
+		$this->databaseHandle->sql_free_result($result);
222
+		return (int)$count;
223
+	}
224
+
225
+	/**
226
+	 * Parses the query and returns the SQL statement parts.
227
+	 *
228
+	 * @param QueryInterface $query The query
229
+	 * @param array &$parameters
230
+	 * @return array The SQL statement parts
231
+	 */
232
+	public function parseQuery(QueryInterface $query, array &$parameters)
233
+	{
234
+		$statementParts = array();
235
+		$statementParts['keywords'] = array();
236
+		$statementParts['tables'] = array();
237
+		$statementParts['unions'] = array();
238
+		$statementParts['fields'] = array();
239
+		$statementParts['where'] = array();
240
+		$statementParts['additionalWhereClause'] = array();
241
+		$statementParts['orderings'] = array();
242
+		$statementParts['limit'] = array();
243
+		$source = $query->getSource();
244
+		$this->parseSource($source, $statementParts);
245
+		$this->parseConstraint($query->getConstraint(), $source, $statementParts, $parameters);
246
+		$this->parseOrderings($query->getOrderings(), $source, $statementParts);
247
+		$this->parseLimitAndOffset($query->getLimit(), $query->getOffset(), $statementParts);
248
+		$tableNames = array_unique(array_keys($statementParts['tables'] + $statementParts['unions']));
249
+		foreach ($tableNames as $tableNameOrAlias) {
250
+			if (is_string($tableNameOrAlias) && strlen($tableNameOrAlias) > 0) {
251
+				$this->addAdditionalWhereClause($query->getQuerySettings(), $tableNameOrAlias, $statementParts);
252
+			}
253
+		}
254
+
255
+		return $statementParts;
256
+	}
257
+
258
+	/**
259
+	 * Fiddle with the statement structure to handle recursive MM relations.
260
+	 * For the recursive MM query to work, we must invert some values.
261
+	 * Let see if that is the best way of doing that...
262
+	 *
263
+	 * @param array $statementParts
264
+	 * @return array
265
+	 */
266
+	public function processStatementStructureForRecursiveMMRelation(array $statementParts)
267
+	{
268
+
269
+		if ($this->hasRecursiveMMRelation()) {
270
+			$tableName = $this->query->getType();
271
+
272
+			// In order the MM query to work for a recursive MM query, we must invert some values.
273
+			// tx_domain_model_foo0 (the alias) <--> tx_domain_model_foo (the origin table name)
274
+			$values = array();
275
+			foreach ($statementParts['fields'] as $key => $value) {
276
+				$values[$key] = str_replace($tableName, $tableName . '0', $value);
277
+			}
278
+			$statementParts['fields'] = $values;
279
+
280
+			// Same comment as above.
281
+			$values = array();
282
+			foreach ($statementParts['where'] as $key => $value) {
283
+				$values[$key] = str_replace($tableName . '0', $tableName, $value);
284
+			}
285
+			$statementParts['where'] = $values;
286
+
287
+			// We must be more restrictive by transforming the "left" union by "inner"
288
+			$values = array();
289
+			foreach ($statementParts['unions'] as $key => $value) {
290
+				$values[$key] = str_replace('LEFT JOIN', 'INNER JOIN', $value);
291
+			}
292
+			$statementParts['unions'] = $values;
293
+		}
294
+
295
+		return $statementParts;
296
+	}
297
+
298
+	/**
299
+	 * Tell whether there is a recursive MM relation.
300
+	 *
301
+	 * @return bool
302
+	 */
303
+	public function hasRecursiveMMRelation()
304
+	{
305
+		return isset($this->tableNameAliases['aliasIncrement'][$this->query->getType()]);
306
+
307
+	}
308
+
309
+	/**
310
+	 * Returns the statement, ready to be executed.
311
+	 *
312
+	 * @param array $statementParts The SQL statement parts
313
+	 * @return string The SQL statement
314
+	 */
315
+	public function buildQuery(array $statementParts)
316
+	{
317
+
318
+		// Add more statement to the UNION part.
319
+		if (!empty($statementParts['unions'])) {
320
+			foreach ($statementParts['unions'] as $tableName => $unionPart) {
321
+				if (!empty($statementParts['additionalWhereClause'][$tableName])) {
322
+					$statementParts['unions'][$tableName] .= ' AND ' . implode(' AND ', $statementParts['additionalWhereClause'][$tableName]);
323
+				}
324
+			}
325
+		}
326
+
327
+		$statement = 'SELECT ' . implode(' ', $statementParts['keywords']) . ' ' . implode(',', $statementParts['fields']) . ' FROM ' . implode(' ', $statementParts['tables']) . ' ' . implode(' ', $statementParts['unions']);
328
+		if (!empty($statementParts['where'])) {
329
+			$statement .= ' WHERE ' . implode('', $statementParts['where']);
330
+			if (!empty($statementParts['additionalWhereClause'][$this->query->getType()])) {
331
+				$statement .= ' AND ' . implode(' AND ', $statementParts['additionalWhereClause'][$this->query->getType()]);
332
+			}
333
+		} elseif (!empty($statementParts['additionalWhereClause'])) {
334
+			$statement .= ' WHERE ' . implode(' AND ', $statementParts['additionalWhereClause'][$this->query->getType()]);
335
+		}
336
+		if (!empty($statementParts['orderings'])) {
337
+			$statement .= ' ORDER BY ' . implode(', ', $statementParts['orderings']);
338
+		}
339
+		if (!empty($statementParts['limit'])) {
340
+			$statement .= ' LIMIT ' . $statementParts['limit'];
341
+		}
342
+
343
+		return $statement;
344
+	}
345
+
346
+	/**
347
+	 * Transforms a Query Source into SQL and parameter arrays
348
+	 *
349
+	 * @param SourceInterface $source The source
350
+	 * @param array &$sql
351
+	 * @return void
352
+	 */
353
+	protected function parseSource(SourceInterface $source, array &$sql)
354
+	{
355
+		if ($source instanceof SelectorInterface) {
356
+			$tableName = $source->getNodeTypeName();
357
+			$sql['fields'][$tableName] = $tableName . '.*';
358
+			$sql['tables'][$tableName] = $tableName;
359
+			if ($this->query->getDistinct()) {
360
+				$sql['fields'][$tableName] = $tableName . '.' . $this->query->getDistinct();
361
+				$sql['keywords']['distinct'] = 'DISTINCT';
362
+			}
363
+		} elseif ($source instanceof JoinInterface) {
364
+			$this->parseJoin($source, $sql);
365
+		}
366
+	}
367
+
368
+	/**
369
+	 * Transforms a Join into SQL and parameter arrays
370
+	 *
371
+	 * @param JoinInterface $join The join
372
+	 * @param array &$sql The query parts
373
+	 * @return void
374
+	 */
375
+	protected function parseJoin(JoinInterface $join, array &$sql)
376
+	{
377
+		$leftSource = $join->getLeft();
378
+		$leftTableName = $leftSource->getSelectorName();
379
+		// $sql['fields'][$leftTableName] = $leftTableName . '.*';
380
+		$rightSource = $join->getRight();
381
+		if ($rightSource instanceof JoinInterface) {
382
+			$rightTableName = $rightSource->getLeft()->getSelectorName();
383
+		} else {
384
+			$rightTableName = $rightSource->getSelectorName();
385
+			$sql['fields'][$leftTableName] = $rightTableName . '.*';
386
+		}
387
+		$sql['tables'][$leftTableName] = $leftTableName;
388
+		$sql['unions'][$rightTableName] = 'LEFT JOIN ' . $rightTableName;
389
+		$joinCondition = $join->getJoinCondition();
390
+		if ($joinCondition instanceof \TYPO3\CMS\Extbase\Persistence\Generic\Qom\EquiJoinCondition) {
391
+			$column1Name = $joinCondition->getProperty1Name();
392
+			$column2Name = $joinCondition->getProperty2Name();
393
+			$sql['unions'][$rightTableName] .= ' ON ' . $joinCondition->getSelector1Name() . '.' . $column1Name . ' = ' . $joinCondition->getSelector2Name() . '.' . $column2Name;
394
+		}
395
+		if ($rightSource instanceof JoinInterface) {
396
+			$this->parseJoin($rightSource, $sql);
397
+		}
398
+	}
399
+
400
+	/**
401
+	 * Transforms a constraint into SQL and parameter arrays
402
+	 *
403
+	 * @param \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ConstraintInterface $constraint The constraint
404
+	 * @param SourceInterface $source The source
405
+	 * @param array &$sql The query parts
406
+	 * @param array &$parameters The parameters that will replace the markers
407
+	 * @return void
408
+	 */
409
+	protected function parseConstraint(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\ConstraintInterface $constraint = NULL, SourceInterface $source, array &$sql, array &$parameters)
410
+	{
411
+		if ($constraint instanceof \TYPO3\CMS\Extbase\Persistence\Generic\Qom\AndInterface) {
412
+			$sql['where'][] = '(';
413
+			$this->parseConstraint($constraint->getConstraint1(), $source, $sql, $parameters);
414
+			$sql['where'][] = ' AND ';
415
+			$this->parseConstraint($constraint->getConstraint2(), $source, $sql, $parameters);
416
+			$sql['where'][] = ')';
417
+		} elseif ($constraint instanceof \TYPO3\CMS\Extbase\Persistence\Generic\Qom\OrInterface) {
418
+			$sql['where'][] = '(';
419
+			$this->parseConstraint($constraint->getConstraint1(), $source, $sql, $parameters);
420
+			$sql['where'][] = ' OR ';
421
+			$this->parseConstraint($constraint->getConstraint2(), $source, $sql, $parameters);
422
+			$sql['where'][] = ')';
423
+		} elseif ($constraint instanceof \TYPO3\CMS\Extbase\Persistence\Generic\Qom\NotInterface) {
424
+			$sql['where'][] = 'NOT (';
425
+			$this->parseConstraint($constraint->getConstraint(), $source, $sql, $parameters);
426
+			$sql['where'][] = ')';
427
+		} elseif ($constraint instanceof ComparisonInterface) {
428
+			$this->parseComparison($constraint, $source, $sql, $parameters);
429
+		}
430
+	}
431
+
432
+	/**
433
+	 * Parse a Comparison into SQL and parameter arrays.
434
+	 *
435
+	 * @param ComparisonInterface $comparison The comparison to parse
436
+	 * @param SourceInterface $source The source
437
+	 * @param array &$sql SQL query parts to add to
438
+	 * @param array &$parameters Parameters to bind to the SQL
439
+	 * @throws Exception\RepositoryException
440
+	 * @return void
441
+	 */
442
+	protected function parseComparison(ComparisonInterface $comparison, SourceInterface $source, array &$sql, array &$parameters)
443
+	{
444
+		$operand1 = $comparison->getOperand1();
445
+		$operator = $comparison->getOperator();
446
+		$operand2 = $comparison->getOperand2();
447
+		if ($operator === QueryInterface::OPERATOR_IN) {
448
+			$items = array();
449
+			$hasValue = FALSE;
450
+			foreach ($operand2 as $value) {
451
+				$value = $this->getPlainValue($value);
452
+				if ($value !== NULL) {
453
+					$items[] = $value;
454
+					$hasValue = TRUE;
455
+				}
456
+			}
457
+			if ($hasValue === FALSE) {
458
+				$sql['where'][] = '1<>1';
459
+			} else {
460
+				$this->parseDynamicOperand($operand1, $operator, $source, $sql, $parameters, NULL);
461
+				$parameters[] = $items;
462
+			}
463
+		} elseif ($operator === QueryInterface::OPERATOR_CONTAINS) {
464
+			if ($operand2 === NULL) {
465
+				$sql['where'][] = '1<>1';
466
+			} else {
467
+				throw new \Exception('Not implemented! Contact extension author.', 1412931227);
468
+				# @todo re-implement me if necessary.
469
+				#$tableName = $this->query->getType();
470
+				#$propertyName = $operand1->getPropertyName();
471
+				#while (strpos($propertyName, '.') !== FALSE) {
472
+				#	$this->addUnionStatement($tableName, $propertyName, $sql);
473
+				#}
474
+				#$columnName = $propertyName;
475
+				#$columnMap = $propertyName;
476
+				#$typeOfRelation = $columnMap instanceof ColumnMap ? $columnMap->getTypeOfRelation() : NULL;
477
+				#if ($typeOfRelation === ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY) {
478
+				#	$relationTableName = $columnMap->getRelationTableName();
479
+				#	$sql['where'][] = $tableName . '.uid IN (SELECT ' . $columnMap->getParentKeyFieldName() . ' FROM ' . $relationTableName . ' WHERE ' . $columnMap->getChildKeyFieldName() . '=?)';
480
+				#	$parameters[] = intval($this->getPlainValue($operand2));
481
+				#} elseif ($typeOfRelation === ColumnMap::RELATION_HAS_MANY) {
482
+				#	$parentKeyFieldName = $columnMap->getParentKeyFieldName();
483
+				#	if (isset($parentKeyFieldName)) {
484
+				#		$childTableName = $columnMap->getChildTableName();
485
+				#		$sql['where'][] = $tableName . '.uid=(SELECT ' . $childTableName . '.' . $parentKeyFieldName . ' FROM ' . $childTableName . ' WHERE ' . $childTableName . '.uid=?)';
486
+				#		$parameters[] = intval($this->getPlainValue($operand2));
487
+				#	} else {
488
+				#		$sql['where'][] = 'FIND_IN_SET(?,' . $tableName . '.' . $columnName . ')';
489
+				#		$parameters[] = intval($this->getPlainValue($operand2));
490
+				#	}
491
+				#} else {
492
+				#	throw new Exception\RepositoryException('Unsupported or non-existing property name "' . $propertyName . '" used in relation matching.', 1327065745);
493
+				#}
494
+			}
495
+		} else {
496
+			if ($operand2 === NULL) {
497
+				if ($operator === QueryInterface::OPERATOR_EQUAL_TO) {
498
+					$operator = self::OPERATOR_EQUAL_TO_NULL;
499
+				} elseif ($operator === QueryInterface::OPERATOR_NOT_EQUAL_TO) {
500
+					$operator = self::OPERATOR_NOT_EQUAL_TO_NULL;
501
+				}
502
+			}
503
+			$this->parseDynamicOperand($operand1, $operator, $source, $sql, $parameters);
504
+			$parameters[] = $this->getPlainValue($operand2);
505
+		}
506
+	}
507
+
508
+	/**
509
+	 * Returns a plain value, i.e. objects are flattened out if possible.
510
+	 *
511
+	 * @param mixed $input
512
+	 * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\UnexpectedTypeException
513
+	 * @return mixed
514
+	 */
515
+	protected function getPlainValue($input)
516
+	{
517
+		if (is_array($input)) {
518
+			throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\UnexpectedTypeException('An array could not be converted to a plain value.', 1274799932);
519
+		}
520
+		if ($input instanceof \DateTime) {
521
+			return $input->format('U');
522
+		} elseif (is_object($input)) {
523
+			if ($input instanceof \TYPO3\CMS\Extbase\Persistence\Generic\LazyLoadingProxy) {
524
+				$realInput = $input->_loadRealInstance();
525
+			} else {
526
+				$realInput = $input;
527
+			}
528
+			if ($realInput instanceof \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface) {
529
+				return $realInput->getUid();
530
+			} else {
531
+				throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\UnexpectedTypeException('An object of class "' . get_class($realInput) . '" could not be converted to a plain value.', 1274799934);
532
+			}
533
+		} elseif (is_bool($input)) {
534
+			return $input === TRUE ? 1 : 0;
535
+		} else {
536
+			return $input;
537
+		}
538
+	}
539
+
540
+	/**
541
+	 * Parse a DynamicOperand into SQL and parameter arrays.
542
+	 *
543
+	 * @param DynamicOperandInterface $operand
544
+	 * @param string $operator One of the JCR_OPERATOR_* constants
545
+	 * @param SourceInterface $source The source
546
+	 * @param array &$sql The query parts
547
+	 * @param array &$parameters The parameters that will replace the markers
548
+	 * @param string $valueFunction an optional SQL function to apply to the operand value
549
+	 * @return void
550
+	 */
551
+	protected function parseDynamicOperand(DynamicOperandInterface $operand, $operator, SourceInterface $source, array &$sql, array &$parameters, $valueFunction = NULL)
552
+	{
553
+		if ($operand instanceof LowerCaseInterface) {
554
+			$this->parseDynamicOperand($operand->getOperand(), $operator, $source, $sql, $parameters, 'LOWER');
555
+		} elseif ($operand instanceof UpperCaseInterface) {
556
+			$this->parseDynamicOperand($operand->getOperand(), $operator, $source, $sql, $parameters, 'UPPER');
557
+		} elseif ($operand instanceof PropertyValueInterface) {
558
+			$propertyName = $operand->getPropertyName();
559
+
560
+			// Reset value.
561
+			$this->currentChildTableNameAlias = '';
562
+
563
+			if ($source instanceof SelectorInterface) {
564
+				$tableName = $this->query->getType();
565
+				while (strpos($propertyName, '.') !== FALSE) {
566
+					$this->addUnionStatement($tableName, $propertyName, $sql);
567
+				}
568
+			} elseif ($source instanceof JoinInterface) {
569
+				$tableName = $source->getJoinCondition()->getSelector1Name();
570
+			}
571
+
572
+			$columnName = $propertyName;
573
+			$operator = $this->resolveOperator($operator);
574
+			$constraintSQL = '';
575
+			if ($valueFunction === NULL) {
576
+				$constraintSQL .= (!empty($tableName) ? $tableName . '.' : '') . $columnName . ' ' . $operator . ' ?';
577
+			} else {
578
+				$constraintSQL .= $valueFunction . '(' . (!empty($tableName) ? $tableName . '.' : '') . $columnName . ') ' . $operator . ' ?';
579
+			}
580
+
581
+			if (isset($tableName) && !empty($this->currentChildTableNameAlias)) {
582
+				$constraintSQL = $this->replaceTableNameByAlias($tableName, $this->currentChildTableNameAlias, $constraintSQL);
583
+			}
584
+			$sql['where'][] = $constraintSQL;
585
+		}
586
+	}
587
+
588
+	/**
589
+	 * @param string &$tableName
590
+	 * @param array &$propertyPath
591
+	 * @param array &$sql
592
+	 * @throws Exception
593
+	 * @throws Exception\InvalidRelationConfigurationException
594
+	 * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\MissingColumnMapException
595
+	 */
596
+	protected function addUnionStatement(&$tableName, &$propertyPath, array &$sql)
597
+	{
598
+
599
+		$table = Tca::table($tableName);
600
+
601
+		$explodedPropertyPath = explode('.', $propertyPath, 2);
602
+		$fieldName = $explodedPropertyPath[0];
603
+
604
+		// Field of type "group" are special because property path must contain the table name
605
+		// to determine the relation type. Example for sys_category, property path will look like "items.sys_file"
606
+		if ($table->field($fieldName)->isGroup()) {
607
+			$parts = explode('.', $propertyPath, 3);
608
+			$explodedPropertyPath[0] = $parts[0] . '.' . $parts[1];
609
+			$explodedPropertyPath[1] = $parts[2];
610
+			$fieldName = $explodedPropertyPath[0];
611
+		}
612
+
613
+		$parentKeyFieldName = $table->field($fieldName)->getForeignField();
614
+		$childTableName = $table->field($fieldName)->getForeignTable();
615
+
616
+		if ($childTableName === NULL) {
617
+			throw new Exception\InvalidRelationConfigurationException('The relation information for property "' . $fieldName . '" of class "' . $tableName . '" is missing.', 1353170925);
618
+		}
619
+
620
+		if ($table->field($fieldName)->hasOne()) { // includes relation "one-to-one" and "many-to-one"
621
+			// sometimes the opposite relation is not defined. We don't want to force this config for backward compatibility reasons.
622
+			// $parentKeyFieldName === NULL does the trick somehow. Before condition was if (isset($parentKeyFieldName))
623
+			if ($table->field($fieldName)->hasRelationManyToOne() || $parentKeyFieldName === NULL) {
624
+				$sql['unions'][$childTableName] = 'LEFT JOIN ' . $childTableName . ' ON ' . $tableName . '.' . $fieldName . '=' . $childTableName . '.uid';
625
+			} else {
626
+				$sql['unions'][$childTableName] = 'LEFT JOIN ' . $childTableName . ' ON ' . $tableName . '.uid=' . $childTableName . '.' . $parentKeyFieldName;
627
+			}
628
+		} elseif ($table->field($fieldName)->hasRelationManyToMany()) {
629
+			$relationTableName = $table->field($fieldName)->getManyToManyTable();
630
+
631
+			$parentKeyFieldName = $table->field($fieldName)->isOppositeRelation() ? 'uid_foreign' : 'uid_local';
632
+			$childKeyFieldName = !$table->field($fieldName)->isOppositeRelation() ? 'uid_foreign' : 'uid_local';
633
+
634
+			// MM table e.g sys_category_record_mm
635
+			$relationTableNameAlias = $this->generateAlias($relationTableName);
636
+			$join = sprintf(
637
+				'LEFT JOIN %s AS %s ON %s.uid=%s.%s', $relationTableName,
638
+				$relationTableNameAlias,
639
+				$tableName,
640
+				$relationTableNameAlias,
641
+				$parentKeyFieldName
642
+			);
643
+			$sql['unions'][$relationTableNameAlias] = $join;
644
+
645
+			// Foreign table e.g sys_category
646
+			$childTableNameAlias = $this->generateAlias($childTableName);
647
+			$this->currentChildTableNameAlias = $childTableNameAlias;
648
+			$join = sprintf(
649
+				'LEFT JOIN %s AS %s ON %s.%s=%s.uid',
650
+				$childTableName,
651
+				$childTableNameAlias,
652
+				$relationTableNameAlias,
653
+				$childKeyFieldName,
654
+				$childTableNameAlias
655
+			);
656
+			$sql['unions'][$childTableNameAlias] = $join;
657
+
658
+			// Find a possible table name for a MM condition.
659
+			$tableNameCondition = $table->field($fieldName)->getAdditionalTableNameCondition();
660
+			if ($tableNameCondition) {
661
+
662
+				// If we can find a source file name,  we can then retrieve more MM conditions from the TCA such as a field name.
663
+				$sourceFileName = $this->query->getSourceFieldName();
664
+				if (empty($sourceFileName)) {
665
+					$additionalMMConditions = array(
666
+						'tablenames' => $tableNameCondition,
667
+					);
668
+				} else {
669
+					$additionalMMConditions = Tca::table($tableNameCondition)->field($sourceFileName)->getAdditionalMMCondition();
670
+				}
671
+
672
+				foreach ($additionalMMConditions as $additionalFieldName => $additionalMMCondition) {
673
+					$additionalJoin = sprintf(' AND %s.%s = "%s"', $relationTableNameAlias, $additionalFieldName, $additionalMMCondition);
674
+					$sql['unions'][$relationTableNameAlias] .= $additionalJoin;
675
+
676
+					$additionalJoin = sprintf(' AND %s.%s = "%s"', $relationTableNameAlias, $additionalFieldName, $additionalMMCondition);
677
+					$sql['unions'][$childTableNameAlias] .= $additionalJoin;
678
+				}
679
+
680
+			}
681
+
682
+
683
+		} elseif ($table->field($fieldName)->hasMany()) { // includes relations "many-to-one" and "csv" relations
684
+			$childTableNameAlias = $this->generateAlias($childTableName);
685
+			$this->currentChildTableNameAlias = $childTableNameAlias;
686
+
687
+			if (isset($parentKeyFieldName)) {
688
+				$join = sprintf(
689
+					'LEFT JOIN %s AS %s ON %s.uid=%s.%s',
690
+					$childTableName,
691
+					$childTableNameAlias,
692
+					$tableName,
693
+					$childTableNameAlias,
694
+					$parentKeyFieldName
695
+				);
696
+				$sql['unions'][$childTableNameAlias] = $join;
697
+			} else {
698
+				$join = sprintf(
699
+					'LEFT JOIN %s AS %s ON (FIND_IN_SET(%s.uid, %s.%s))',
700
+					$childTableName,
701
+					$childTableNameAlias,
702
+					$childTableNameAlias,
703
+					$tableName,
704
+					$fieldName
705
+				);
706
+				$sql['unions'][$childTableNameAlias] = $join;
707
+			}
708
+		} else {
709
+			throw new Exception('Could not determine type of relation.', 1252502725);
710
+		}
711
+
712
+		// TODO check if there is another solution for this
713
+		$sql['keywords']['distinct'] = 'DISTINCT';
714
+		$propertyPath = $explodedPropertyPath[1];
715
+		$tableName = $childTableName;
716
+	}
717
+
718
+	/**
719
+	 * Returns the SQL operator for the given JCR operator type.
720
+	 *
721
+	 * @param string $operator One of the JCR_OPERATOR_* constants
722
+	 * @throws Exception
723
+	 * @return string an SQL operator
724
+	 */
725
+	protected function resolveOperator($operator)
726
+	{
727
+		switch ($operator) {
728
+			case self::OPERATOR_EQUAL_TO_NULL:
729
+				$operator = 'IS';
730
+				break;
731
+			case self::OPERATOR_NOT_EQUAL_TO_NULL:
732
+				$operator = 'IS NOT';
733
+				break;
734
+			case QueryInterface::OPERATOR_IN:
735
+				$operator = 'IN';
736
+				break;
737
+			case QueryInterface::OPERATOR_EQUAL_TO:
738
+				$operator = '=';
739
+				break;
740
+			case QueryInterface::OPERATOR_NOT_EQUAL_TO:
741
+				$operator = '!=';
742
+				break;
743
+			case QueryInterface::OPERATOR_LESS_THAN:
744
+				$operator = '<';
745
+				break;
746
+			case QueryInterface::OPERATOR_LESS_THAN_OR_EQUAL_TO:
747
+				$operator = '<=';
748
+				break;
749
+			case QueryInterface::OPERATOR_GREATER_THAN:
750
+				$operator = '>';
751
+				break;
752
+			case QueryInterface::OPERATOR_GREATER_THAN_OR_EQUAL_TO:
753
+				$operator = '>=';
754
+				break;
755
+			case QueryInterface::OPERATOR_LIKE:
756
+				$operator = 'LIKE';
757
+				break;
758
+			default:
759
+				throw new Exception('Unsupported operator encountered.', 1242816073);
760
+		}
761
+		return $operator;
762
+	}
763
+
764
+	/**
765
+	 * Replace query placeholders in a query part by the given
766
+	 * parameters.
767
+	 *
768
+	 * @param string &$sqlString The query part with placeholders
769
+	 * @param array $parameters The parameters
770
+	 * @param string $tableName
771
+	 *
772
+	 * @throws Exception
773
+	 */
774
+	protected function replacePlaceholders(&$sqlString, array $parameters, $tableName = 'foo')
775
+	{
776
+		// TODO profile this method again
777
+		if (substr_count($sqlString, '?') !== count($parameters)) {
778
+			throw new Exception('The number of question marks to replace must be equal to the number of parameters.', 1242816074);
779
+		}
780
+		$offset = 0;
781
+		foreach ($parameters as $parameter) {
782
+			$markPosition = strpos($sqlString, '?', $offset);
783
+			if ($markPosition !== FALSE) {
784
+				if ($parameter === NULL) {
785
+					$parameter = 'NULL';
786
+				} elseif (is_array($parameter) || $parameter instanceof \ArrayAccess || $parameter instanceof \Traversable) {
787
+					$items = array();
788
+					foreach ($parameter as $item) {
789
+						$items[] = $this->databaseHandle->fullQuoteStr($item, $tableName);
790
+					}
791
+					$parameter = '(' . implode(',', $items) . ')';
792
+				} else {
793
+					$parameter = $this->databaseHandle->fullQuoteStr($parameter, $tableName);
794
+				}
795
+				$sqlString = substr($sqlString, 0, $markPosition) . $parameter . substr($sqlString, ($markPosition + 1));
796
+			}
797
+			$offset = $markPosition + strlen($parameter);
798
+		}
799
+	}
800
+
801
+	/**
802
+	 * Adds additional WHERE statements according to the query settings.
803
+	 *
804
+	 * @param QuerySettingsInterface $querySettings The TYPO3 CMS specific query settings
805
+	 * @param string $tableNameOrAlias The table name to add the additional where clause for
806
+	 * @param array &$statementParts
807
+	 * @return void
808
+	 */
809
+	protected function addAdditionalWhereClause(QuerySettingsInterface $querySettings, $tableNameOrAlias, &$statementParts)
810
+	{
811
+		$this->addVisibilityConstraintStatement($querySettings, $tableNameOrAlias, $statementParts);
812
+		if ($querySettings->getRespectSysLanguage()) {
813
+			$this->addSysLanguageStatement($tableNameOrAlias, $statementParts, $querySettings);
814
+		}
815
+		if ($querySettings->getRespectStoragePage()) {
816
+			$this->addPageIdStatement($tableNameOrAlias, $statementParts, $querySettings->getStoragePageIds());
817
+		}
818
+	}
819
+
820
+	/**
821
+	 * Adds enableFields and deletedClause to the query if necessary
822
+	 *
823
+	 * @param QuerySettingsInterface $querySettings
824
+	 * @param string $tableNameOrAlias The database table name
825
+	 * @param array &$statementParts The query parts
826
+	 * @return void
827
+	 */
828
+	protected function addVisibilityConstraintStatement(QuerySettingsInterface $querySettings, $tableNameOrAlias, array &$statementParts)
829
+	{
830
+		$statement = '';
831
+		$tableName = $this->resolveTableNameAlias($tableNameOrAlias);
832
+		if (is_array($GLOBALS['TCA'][$tableName]['ctrl'])) {
833
+			$ignoreEnableFields = $querySettings->getIgnoreEnableFields();
834
+			$enableFieldsToBeIgnored = $querySettings->getEnableFieldsToBeIgnored();
835
+			$includeDeleted = $querySettings->getIncludeDeleted();
836
+			if ($this->environmentService->isEnvironmentInFrontendMode()) {
837
+				$statement .= $this->getFrontendConstraintStatement($tableNameOrAlias, $ignoreEnableFields, $enableFieldsToBeIgnored, $includeDeleted);
838
+			} else {
839
+				// TYPO3_MODE === 'BE'
840
+				$statement .= $this->getBackendConstraintStatement($tableNameOrAlias, $ignoreEnableFields, $includeDeleted);
841
+			}
842
+
843
+			// Remove the prefixing "AND" if any.
844
+			if (!empty($statement)) {
845
+				$statement = strtolower(substr($statement, 1, 3)) === 'and' ? substr($statement, 5) : $statement;
846
+				$statementParts['additionalWhereClause'][$tableNameOrAlias][] = $statement;
847
+			}
848
+		}
849
+	}
850
+
851
+	/**
852
+	 * Returns constraint statement for frontend context
853
+	 *
854
+	 * @param string $tableNameOrAlias
855
+	 * @param boolean $ignoreEnableFields A flag indicating whether the enable fields should be ignored
856
+	 * @param array $enableFieldsToBeIgnored If $ignoreEnableFields is true, this array specifies enable fields to be ignored. If it is NULL or an empty array (default) all enable fields are ignored.
857
+	 * @param boolean $includeDeleted A flag indicating whether deleted records should be included
858
+	 * @return string
859
+	 * @throws Exception\InconsistentQuerySettingsException
860
+	 */
861
+	protected function getFrontendConstraintStatement($tableNameOrAlias, $ignoreEnableFields, $enableFieldsToBeIgnored = array(), $includeDeleted)
862
+	{
863
+		$statement = '';
864
+		$tableName = $this->resolveTableNameAlias($tableNameOrAlias);
865
+		if ($ignoreEnableFields && !$includeDeleted) {
866
+			if (count($enableFieldsToBeIgnored)) {
867
+				// array_combine() is necessary because of the way \TYPO3\CMS\Frontend\Page\PageRepository::enableFields() is implemented
868
+				$statement .= $this->getPageRepository()->enableFields($tableName, -1, array_combine($enableFieldsToBeIgnored, $enableFieldsToBeIgnored));
869
+			} else {
870
+				$statement .= $this->getPageRepository()->deleteClause($tableName);
871
+			}
872
+		} elseif (!$ignoreEnableFields && !$includeDeleted) {
873
+			$statement .= $this->getPageRepository()->enableFields($tableName);
874
+		} elseif (!$ignoreEnableFields && $includeDeleted) {
875
+			throw new Exception\InconsistentQuerySettingsException('Query setting "ignoreEnableFields=FALSE" can not be used together with "includeDeleted=TRUE" in frontend context.', 1327678173);
876
+		}
877
+		return $this->replaceTableNameByAlias($tableName, $tableNameOrAlias, $statement);
878
+	}
879
+
880
+	/**
881
+	 * Returns constraint statement for backend context
882
+	 *
883
+	 * @param string $tableNameOrAlias
884
+	 * @param boolean $ignoreEnableFields A flag indicating whether the enable fields should be ignored
885
+	 * @param boolean $includeDeleted A flag indicating whether deleted records should be included
886
+	 * @return string
887
+	 */
888
+	protected function getBackendConstraintStatement($tableNameOrAlias, $ignoreEnableFields, $includeDeleted)
889
+	{
890
+		$tableName = $this->resolveTableNameAlias($tableNameOrAlias);
891
+		$statement = '';
892
+		if (!$ignoreEnableFields) {
893
+			$statement .= BackendUtility::BEenableFields($tableName);
894
+		}
895
+
896
+		// If the table is found to have "workspace" support, add the corresponding fields in the statement.
897
+		if (Tca::table($tableName)->hasWorkspaceSupport()) {
898
+			if ($this->getBackendUser()->workspace === 0) {
899
+				$statement .= ' AND ' . $tableName . '.t3ver_state<=' . new VersionState(VersionState::DEFAULT_STATE);
900
+			} else {
901
+				// Show only records of live and of the current workspace
902
+				// In case we are in a Versioning preview
903
+				$statement .= ' AND (' .
904
+					$tableName . '.t3ver_wsid=0 OR ' .
905
+					$tableName . '.t3ver_wsid=' . (int)$this->getBackendUser()->workspace .
906
+					')';
907
+			}
908
+
909
+			// Check if this segment make sense here or whether it should be in the "if" part when we have workspace = 0
910
+			$statement .= ' AND ' . $tableName . '.pid<>-1';
911
+		}
912
+
913
+		if (!$includeDeleted) {
914
+			$statement .= BackendUtility::deleteClause($tableName);
915
+		}
916
+
917
+		return $this->replaceTableNameByAlias($tableName, $tableNameOrAlias, $statement);
918
+	}
919
+
920
+	/**
921
+	 * Builds the language field statement
922
+	 *
923
+	 * @param string $tableNameOrAlias The database table name
924
+	 * @param array &$statementParts The query parts
925
+	 * @param QuerySettingsInterface $querySettings The TYPO3 CMS specific query settings
926
+	 * @throws Exception
927
+	 * @return void
928
+	 */
929
+	protected function addSysLanguageStatement($tableNameOrAlias, array &$statementParts, $querySettings)
930
+	{
931
+
932
+		$tableName = $this->resolveTableNameAlias($tableNameOrAlias);
933
+		if (is_array($GLOBALS['TCA'][$tableName]['ctrl'])) {
934
+			if (!empty($GLOBALS['TCA'][$tableName]['ctrl']['languageField'])) {
935
+				// Select all entries for the current language
936
+				$additionalWhereClause = $tableNameOrAlias . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] . ' IN (' . intval($querySettings->getLanguageUid()) . ',-1)';
937
+				// If any language is set -> get those entries which are not translated yet
938
+				// They will be removed by t3lib_page::getRecordOverlay if not matching overlay mode
939
+				if (isset($GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'])
940
+					&& $querySettings->getLanguageUid() > 0
941
+				) {
942
+					$additionalWhereClause .= ' OR (' . $tableNameOrAlias . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] . '=0' .
943
+						' AND ' . $tableNameOrAlias . '.uid NOT IN (SELECT ' . $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'] .
944
+						' FROM ' . $tableName .
945
+						' WHERE ' . $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'] . '>0' .
946
+						' AND ' . $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] . '>0';
947
+
948
+					// Add delete clause to ensure all entries are loaded
949
+					if (isset($GLOBALS['TCA'][$tableName]['ctrl']['delete'])) {
950
+						$additionalWhereClause .= ' AND ' . $tableNameOrAlias . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['delete'] . '=0';
951
+					}
952
+					$additionalWhereClause .= '))';
953
+				}
954
+				$statementParts['additionalWhereClause'][$tableNameOrAlias][] = '(' . $additionalWhereClause . ')';
955
+			}
956
+		}
957
+	}
958
+
959
+	/**
960
+	 * Builds the page ID checking statement
961
+	 *
962
+	 * @param string $tableNameOrAlias The database table name
963
+	 * @param array &$statementParts The query parts
964
+	 * @param array $storagePageIds list of storage page ids
965
+	 * @throws Exception\InconsistentQuerySettingsException
966
+	 * @return void
967
+	 */
968
+	protected function addPageIdStatement($tableNameOrAlias, array &$statementParts, array $storagePageIds)
969
+	{
970
+
971
+		$tableName = $this->resolveTableNameAlias($tableNameOrAlias);
972
+		$tableColumns = $this->tableColumnCache->get($tableName);
973
+		if ($tableColumns === FALSE) {
974
+			$tableColumns = $this->databaseHandle->admin_get_fields($tableName);
975
+			$this->tableColumnCache->set($tableName, $tableColumns);
976
+		}
977
+		if (is_array($GLOBALS['TCA'][$tableName]['ctrl']) && array_key_exists('pid', $tableColumns)) {
978
+			$rootLevel = (int)$GLOBALS['TCA'][$tableName]['ctrl']['rootLevel'];
979
+			if ($rootLevel) {
980
+				if ($rootLevel === 1) {
981
+					$statementParts['additionalWhereClause'][$tableNameOrAlias][] = $tableNameOrAlias . '.pid = 0';
982
+				}
983
+			} else {
984
+				if (empty($storagePageIds)) {
985
+					throw new Exception\InconsistentQuerySettingsException('Missing storage page ids.', 1365779762);
986
+				}
987
+				$statementParts['additionalWhereClause'][$tableNameOrAlias][] = $tableNameOrAlias . '.pid IN (' . implode(', ', $storagePageIds) . ')';
988
+			}
989
+		}
990
+	}
991
+
992
+	/**
993
+	 * Transforms orderings into SQL.
994
+	 *
995
+	 * @param array $orderings An array of orderings (Tx_Extbase_Persistence_QOM_Ordering)
996
+	 * @param SourceInterface $source The source
997
+	 * @param array &$sql The query parts
998
+	 * @throws Exception\UnsupportedOrderException
999
+	 * @return void
1000
+	 */
1001
+	protected function parseOrderings(array $orderings, SourceInterface $source, array &$sql)
1002
+	{
1003
+		foreach ($orderings as $fieldNameAndPath => $order) {
1004
+			switch ($order) {
1005
+				case QueryInterface::ORDER_ASCENDING:
1006
+					$order = 'ASC';
1007
+					break;
1008
+				case QueryInterface::ORDER_DESCENDING:
1009
+					$order = 'DESC';
1010
+					break;
1011
+				default:
1012
+					throw new Exception\UnsupportedOrderException('Unsupported order encountered.', 1456845126);
1013
+			}
1014
+
1015
+			$tableName = $this->getFieldPathResolver()->getDataType($fieldNameAndPath, $this->query->getType());
1016
+			$fieldName = $this->getFieldPathResolver()->stripFieldPath($fieldNameAndPath, $tableName);
1017
+			$sql['orderings'][] = sprintf('%s.%s %s', $tableName, $fieldName, $order);
1018
+		}
1019
+	}
1020
+
1021
+	/**
1022
+	 * Transforms limit and offset into SQL
1023
+	 *
1024
+	 * @param int $limit
1025
+	 * @param int $offset
1026
+	 * @param array &$sql
1027
+	 * @return void
1028
+	 */
1029
+	protected function parseLimitAndOffset($limit, $offset, array &$sql)
1030
+	{
1031
+		if ($limit !== NULL && $offset !== NULL) {
1032
+			$sql['limit'] = intval($offset) . ', ' . intval($limit);
1033
+		} elseif ($limit !== NULL) {
1034
+			$sql['limit'] = intval($limit);
1035
+		}
1036
+	}
1037
+
1038
+	/**
1039
+	 * Transforms a Resource from a database query to an array of rows.
1040
+	 *
1041
+	 * @param resource $result The result
1042
+	 * @return array The result as an array of rows (tuples)
1043
+	 */
1044
+	protected function getRowsFromResult($result)
1045
+	{
1046
+		$rows = array();
1047
+		while ($row = $this->databaseHandle->sql_fetch_assoc($result)) {
1048
+			if (is_array($row)) {
1049
+
1050
+				// Get language uid from querySettings.
1051
+				// Ensure the backend handling is not broken (fallback to Get parameter 'L' if needed)
1052
+				$overlaidRow = $this->doLanguageAndWorkspaceOverlay($this->query->getSource(), $row, $this->query->getQuerySettings());
1053
+				$contentObject = GeneralUtility::makeInstance($this->objectType, $this->query->getType(), $overlaidRow);
1054
+				$rows[] = $contentObject;
1055
+			}
1056
+		}
1057
+
1058
+		return $rows;
1059
+	}
1060
+
1061
+	/**
1062
+	 * Performs workspace and language overlay on the given row array. The language and workspace id is automatically
1063
+	 * detected (depending on FE or BE context). You can also explicitly set the language/workspace id.
1064
+	 *
1065
+	 * @param SourceInterface $source The source (selector od join)
1066
+	 * @param array $row
1067
+	 * @param QuerySettingsInterface $querySettings The TYPO3 CMS specific query settings
1068
+	 * @return array
1069
+	 */
1070
+	protected function doLanguageAndWorkspaceOverlay(SourceInterface $source, array $row, $querySettings)
1071
+	{
1072
+
1073
+		/** @var SelectorInterface $source */
1074
+		$tableName = $source->getSelectorName();
1075
+
1076
+		$pageRepository = $this->getPageRepository();
1077
+		if (is_object($GLOBALS['TSFE'])) {
1078
+			$languageMode = $GLOBALS['TSFE']->sys_language_mode;
1079
+			if ($this->isBackendUserLogged() && $this->getBackendUser()->workspace !== 0) {
1080
+				$pageRepository->versioningWorkspaceId = $this->getBackendUser()->workspace;
1081
+			}
1082
+		} else {
1083
+			$languageMode = '';
1084
+			$workspaceUid = $this->getBackendUser()->workspace;
1085
+			$pageRepository->versioningWorkspaceId = $workspaceUid;
1086
+			if ($this->getBackendUser()->workspace !== 0) {
1087
+				$pageRepository->versioningPreview = 1;
1088
+			}
1089
+		}
1090
+
1091
+		// If current row is a translation select its parent
1092
+		if (isset($GLOBALS['TCA'][$tableName]['ctrl']['languageField'])
1093
+			&& isset($GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'])
1094
+		) {
1095
+			if (isset($row[$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']])
1096
+				&& $row[$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']] > 0
1097
+			) {
1098
+				$row = $this->databaseHandle->exec_SELECTgetSingleRow(
1099
+					$tableName . '.*',
1100
+					$tableName,
1101
+					$tableName . '.uid=' . (int)$row[$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']] .
1102
+					' AND ' . $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] . '=0'
1103
+				);
1104
+			}
1105
+		}
1106
+
1107
+		// Retrieve the original uid; Used for Workspaces!
1108
+		$pageRepository->versionOL($tableName, $row, true, true);
1109
+		if ($pageRepository->versioningPreview && isset($row['_ORIG_uid'])) {
1110
+			$row['uid'] = $row['_ORIG_uid'];
1111
+		}
1112
+
1113
+		// Special case for table "pages"
1114
+		if ($tableName == 'pages') {
1115
+			$row = $pageRepository->getPageOverlay($row, $querySettings->getLanguageUid());
1116
+		} elseif (isset($GLOBALS['TCA'][$tableName]['ctrl']['languageField'])
1117
+			&& $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] !== ''
1118
+		) {
1119
+			if (in_array($row[$GLOBALS['TCA'][$tableName]['ctrl']['languageField']], array(-1, 0))) {
1120
+				$overlayMode = $languageMode === 'strict' ? 'hideNonTranslated' : '';
1121
+				$row = $pageRepository->getRecordOverlay($tableName, $row, $querySettings->getLanguageUid(), $overlayMode);
1122
+			}
1123
+		}
1124
+
1125
+		return $row;
1126
+	}
1127
+
1128
+	/**
1129
+	 * Return a resolved table name given a possible table name alias.
1130
+	 *
1131
+	 * @param string $tableNameOrAlias
1132
+	 * @return string
1133
+	 */
1134
+	protected function resolveTableNameAlias($tableNameOrAlias)
1135
+	{
1136
+		$resolvedTableName = $tableNameOrAlias;
1137
+		if (!empty($this->tableNameAliases['aliases'][$tableNameOrAlias])) {
1138
+			$resolvedTableName = $this->tableNameAliases['aliases'][$tableNameOrAlias];
1139
+		}
1140
+		return $resolvedTableName;
1141
+	}
1142
+
1143
+	/**
1144
+	 * Generate a unique table name alias for the given table name.
1145
+	 *
1146
+	 * @param string $tableName
1147
+	 * @return string
1148
+	 */
1149
+	protected function generateAlias($tableName)
1150
+	{
1151
+
1152
+		if (!isset($this->tableNameAliases['aliasIncrement'][$tableName])) {
1153
+			$this->tableNameAliases['aliasIncrement'][$tableName] = 0;
1154
+		}
1155
+
1156
+		$numberOfAliases = $this->tableNameAliases['aliasIncrement'][$tableName];
1157
+		$tableNameAlias = $tableName . $numberOfAliases;
1158
+
1159
+		$this->tableNameAliases['aliasIncrement'][$tableName]++;
1160
+		$this->tableNameAliases['aliases'][$tableNameAlias] = $tableName;
1161
+
1162
+		return $tableNameAlias;
1163
+	}
1164
+
1165
+	/**
1166
+	 * Replace the table names by its table name alias within the given statement.
1167
+	 *
1168
+	 * @param string $tableName
1169
+	 * @param string $tableNameAlias
1170
+	 * @param string $statement
1171
+	 * @return string
1172
+	 */
1173
+	protected function replaceTableNameByAlias($tableName, $tableNameAlias, $statement)
1174
+	{
1175
+		if ($statement && $tableName !== $tableNameAlias) {
1176
+			$statement = str_replace($tableName, $tableNameAlias, $statement);
1177
+		}
1178
+		return $statement;
1179
+	}
1180
+
1181
+	/**
1182
+	 * Returns an instance of the current Backend User.
1183
+	 *
1184
+	 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
1185
+	 */
1186
+	protected function getBackendUser()
1187
+	{
1188
+		return $GLOBALS['BE_USER'];
1189
+	}
1190
+
1191
+	/**
1192
+	 * Tell whether a Backend User is logged in.
1193
+	 *
1194
+	 * @return bool
1195
+	 */
1196
+	protected function isBackendUserLogged()
1197
+	{
1198
+		return is_object($GLOBALS['BE_USER']);
1199
+	}
1200
+
1201
+	/**
1202
+	 * @return PageRepository
1203
+	 */
1204
+	protected function getPageRepository()
1205
+	{
1206
+		if (!$this->pageRepository instanceof PageRepository) {
1207
+			if ($this->environmentService->isEnvironmentInFrontendMode() && is_object($GLOBALS['TSFE'])) {
1208
+				$this->pageRepository = $GLOBALS['TSFE']->sys_page;
1209
+			} else {
1210
+				$this->pageRepository = GeneralUtility::makeInstance('TYPO3\\CMS\\Frontend\\Page\\PageRepository');
1211
+			}
1212
+		}
1213
+
1214
+		return $this->pageRepository;
1215
+	}
1216
+
1217
+	/**
1218
+	 * @return \Fab\Vidi\Resolver\FieldPathResolver
1219
+	 */
1220
+	protected function getFieldPathResolver()
1221
+	{
1222
+		return GeneralUtility::makeInstance('Fab\Vidi\Resolver\FieldPathResolver');
1223
+	}
1224
+
1225
+	/**
1226
+	 * Checks if there are SQL errors in the last query, and if yes, throw an exception.
1227
+	 *
1228
+	 * @return void
1229
+	 * @param string $sql The SQL statement
1230
+	 * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Storage\Exception\SqlErrorException
1231
+	 */
1232
+	protected function checkSqlErrors($sql = '')
1233
+	{
1234
+		$error = $this->databaseHandle->sql_error();
1235
+		if ($error !== '') {
1236
+			$error .= $sql ? ': ' . $sql : '';
1237
+			throw new \TYPO3\CMS\Extbase\Persistence\Generic\Storage\Exception\SqlErrorException($error, 1247602160);
1238
+		}
1239
+	}
1240 1240
 }
Please login to merge, or discard this patch.
Classes/Processor/ContentObjectProcessor.php 3 patches
Doc Comments   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -30,7 +30,7 @@  discard block
 block discarded – undo
30 30
 
31 31
     /**
32 32
      * @param ProcessContentDataSignalArguments $signalArguments
33
-     * @return array
33
+     * @return ProcessContentDataSignalArguments[]
34 34
      */
35 35
     public function processRelations(ProcessContentDataSignalArguments $signalArguments)
36 36
     {
@@ -50,7 +50,7 @@  discard block
 block discarded – undo
50 50
 
51 51
     /**
52 52
      * @param \Fab\Vidi\Domain\Model\Content $object
53
-     * @param $fieldNameAndPath
53
+     * @param string $fieldNameAndPath
54 54
      * @param array $contentData
55 55
      * @param string $savingBehavior
56 56
      * @return array
Please login to merge, or discard this patch.
Indentation   +117 added lines, -117 removed lines patch added patch discarded remove patch
@@ -28,121 +28,121 @@
 block discarded – undo
28 28
 class ContentObjectProcessor implements SingletonInterface
29 29
 {
30 30
 
31
-    /**
32
-     * @param ProcessContentDataSignalArguments $signalArguments
33
-     * @return array
34
-     */
35
-    public function processRelations(ProcessContentDataSignalArguments $signalArguments)
36
-    {
37
-
38
-        $contentObject = $signalArguments->getContentObject();
39
-        $fieldNameAndPath = $signalArguments->getFieldNameAndPath();
40
-        $contentData = $signalArguments->getContentData();
41
-        $savingBehavior = $signalArguments->getSavingBehavior();
42
-
43
-        if ($savingBehavior !== SavingBehavior::REPLACE) {
44
-            $contentData = $this->appendOrRemoveRelations($contentObject, $fieldNameAndPath, $contentData, $savingBehavior);
45
-            $signalArguments->setContentData($contentData);
46
-        }
47
-
48
-        return array($signalArguments);
49
-    }
50
-
51
-    /**
52
-     * @param \Fab\Vidi\Domain\Model\Content $object
53
-     * @param $fieldNameAndPath
54
-     * @param array $contentData
55
-     * @param string $savingBehavior
56
-     * @return array
57
-     */
58
-    protected function appendOrRemoveRelations(Content $object, $fieldNameAndPath, array $contentData, $savingBehavior)
59
-    {
60
-
61
-        foreach ($contentData as $fieldName => $values) {
62
-
63
-            $resolvedObject = $this->getContentObjectResolver()->getObject($object, $fieldNameAndPath);
64
-
65
-            if (Tca::table($resolvedObject)->field($fieldName)->hasMany()) {
66
-
67
-                // TRUE means CSV values must be converted to array.
68
-                if (!is_array($values)) {
69
-                    $values = GeneralUtility::trimExplode(',', $values);
70
-                }
71
-                $relatedValues = $this->getRelatedValues($object, $fieldNameAndPath, $fieldName);
72
-
73
-                foreach ($values as $value) {
74
-                    $appendOrRemove = $savingBehavior . 'Relations';
75
-                    $relatedValues = $this->$appendOrRemove($value, $relatedValues);
76
-                }
77
-
78
-                $contentData[$fieldName] = $relatedValues;
79
-            }
80
-        }
81
-        return $contentData;
82
-    }
83
-
84
-    /**
85
-     * @param $value
86
-     * @param array $relatedValues
87
-     * @return array
88
-     */
89
-    protected function appendRelations($value, array $relatedValues)
90
-    {
91
-        if (!in_array($value, $relatedValues)) {
92
-            $relatedValues[] = $value;
93
-        }
94
-        return $relatedValues;
95
-    }
96
-
97
-    /**
98
-     * @param $value
99
-     * @param array $relatedValues
100
-     * @return array
101
-     */
102
-    protected function removeRelations($value, array $relatedValues)
103
-    {
104
-        if (in_array($value, $relatedValues)) {
105
-            $key = array_search($value, $relatedValues);
106
-            unset($relatedValues[$key]);
107
-        }
108
-        return $relatedValues;
109
-    }
110
-
111
-    /**
112
-     * @param \Fab\Vidi\Domain\Model\Content $object
113
-     * @param string $fieldNameAndPath
114
-     * @param string $fieldName
115
-     * @return array
116
-     */
117
-    protected function getRelatedValues(Content $object, $fieldNameAndPath, $fieldName)
118
-    {
119
-
120
-        $values = array();
121
-        $relatedContentObjects = $this->getContentObjectResolver()->getValue($object, $fieldNameAndPath, $fieldName);
122
-
123
-        if (is_array($relatedContentObjects)) {
124
-            /** @var Content $relatedContentObject */
125
-            foreach ($relatedContentObjects as $relatedContentObject) {
126
-                $values[] = $relatedContentObject->getUid();
127
-            }
128
-        }
129
-
130
-        return $values;
131
-    }
132
-
133
-    /**
134
-     * @return \Fab\Vidi\Resolver\ContentObjectResolver
135
-     */
136
-    protected function getContentObjectResolver()
137
-    {
138
-        return GeneralUtility::makeInstance('Fab\Vidi\Resolver\ContentObjectResolver');
139
-    }
140
-
141
-    /**
142
-     * @return \Fab\Vidi\Resolver\FieldPathResolver
143
-     */
144
-    protected function getFieldPathResolver()
145
-    {
146
-        return GeneralUtility::makeInstance('Fab\Vidi\Resolver\FieldPathResolver');
147
-    }
31
+	/**
32
+	 * @param ProcessContentDataSignalArguments $signalArguments
33
+	 * @return array
34
+	 */
35
+	public function processRelations(ProcessContentDataSignalArguments $signalArguments)
36
+	{
37
+
38
+		$contentObject = $signalArguments->getContentObject();
39
+		$fieldNameAndPath = $signalArguments->getFieldNameAndPath();
40
+		$contentData = $signalArguments->getContentData();
41
+		$savingBehavior = $signalArguments->getSavingBehavior();
42
+
43
+		if ($savingBehavior !== SavingBehavior::REPLACE) {
44
+			$contentData = $this->appendOrRemoveRelations($contentObject, $fieldNameAndPath, $contentData, $savingBehavior);
45
+			$signalArguments->setContentData($contentData);
46
+		}
47
+
48
+		return array($signalArguments);
49
+	}
50
+
51
+	/**
52
+	 * @param \Fab\Vidi\Domain\Model\Content $object
53
+	 * @param $fieldNameAndPath
54
+	 * @param array $contentData
55
+	 * @param string $savingBehavior
56
+	 * @return array
57
+	 */
58
+	protected function appendOrRemoveRelations(Content $object, $fieldNameAndPath, array $contentData, $savingBehavior)
59
+	{
60
+
61
+		foreach ($contentData as $fieldName => $values) {
62
+
63
+			$resolvedObject = $this->getContentObjectResolver()->getObject($object, $fieldNameAndPath);
64
+
65
+			if (Tca::table($resolvedObject)->field($fieldName)->hasMany()) {
66
+
67
+				// TRUE means CSV values must be converted to array.
68
+				if (!is_array($values)) {
69
+					$values = GeneralUtility::trimExplode(',', $values);
70
+				}
71
+				$relatedValues = $this->getRelatedValues($object, $fieldNameAndPath, $fieldName);
72
+
73
+				foreach ($values as $value) {
74
+					$appendOrRemove = $savingBehavior . 'Relations';
75
+					$relatedValues = $this->$appendOrRemove($value, $relatedValues);
76
+				}
77
+
78
+				$contentData[$fieldName] = $relatedValues;
79
+			}
80
+		}
81
+		return $contentData;
82
+	}
83
+
84
+	/**
85
+	 * @param $value
86
+	 * @param array $relatedValues
87
+	 * @return array
88
+	 */
89
+	protected function appendRelations($value, array $relatedValues)
90
+	{
91
+		if (!in_array($value, $relatedValues)) {
92
+			$relatedValues[] = $value;
93
+		}
94
+		return $relatedValues;
95
+	}
96
+
97
+	/**
98
+	 * @param $value
99
+	 * @param array $relatedValues
100
+	 * @return array
101
+	 */
102
+	protected function removeRelations($value, array $relatedValues)
103
+	{
104
+		if (in_array($value, $relatedValues)) {
105
+			$key = array_search($value, $relatedValues);
106
+			unset($relatedValues[$key]);
107
+		}
108
+		return $relatedValues;
109
+	}
110
+
111
+	/**
112
+	 * @param \Fab\Vidi\Domain\Model\Content $object
113
+	 * @param string $fieldNameAndPath
114
+	 * @param string $fieldName
115
+	 * @return array
116
+	 */
117
+	protected function getRelatedValues(Content $object, $fieldNameAndPath, $fieldName)
118
+	{
119
+
120
+		$values = array();
121
+		$relatedContentObjects = $this->getContentObjectResolver()->getValue($object, $fieldNameAndPath, $fieldName);
122
+
123
+		if (is_array($relatedContentObjects)) {
124
+			/** @var Content $relatedContentObject */
125
+			foreach ($relatedContentObjects as $relatedContentObject) {
126
+				$values[] = $relatedContentObject->getUid();
127
+			}
128
+		}
129
+
130
+		return $values;
131
+	}
132
+
133
+	/**
134
+	 * @return \Fab\Vidi\Resolver\ContentObjectResolver
135
+	 */
136
+	protected function getContentObjectResolver()
137
+	{
138
+		return GeneralUtility::makeInstance('Fab\Vidi\Resolver\ContentObjectResolver');
139
+	}
140
+
141
+	/**
142
+	 * @return \Fab\Vidi\Resolver\FieldPathResolver
143
+	 */
144
+	protected function getFieldPathResolver()
145
+	{
146
+		return GeneralUtility::makeInstance('Fab\Vidi\Resolver\FieldPathResolver');
147
+	}
148 148
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -71,7 +71,7 @@
 block discarded – undo
71 71
                 $relatedValues = $this->getRelatedValues($object, $fieldNameAndPath, $fieldName);
72 72
 
73 73
                 foreach ($values as $value) {
74
-                    $appendOrRemove = $savingBehavior . 'Relations';
74
+                    $appendOrRemove = $savingBehavior.'Relations';
75 75
                     $relatedValues = $this->$appendOrRemove($value, $relatedValues);
76 76
                 }
77 77
 
Please login to merge, or discard this patch.
Classes/Processor/MarkerProcessor.php 3 patches
Doc Comments   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -37,7 +37,7 @@  discard block
 block discarded – undo
37 37
 
38 38
     /**
39 39
      * @param ProcessContentDataSignalArguments $signalArguments
40
-     * @return array
40
+     * @return ProcessContentDataSignalArguments[]
41 41
      */
42 42
     public function processMarkers(ProcessContentDataSignalArguments $signalArguments)
43 43
     {
@@ -72,7 +72,7 @@  discard block
 block discarded – undo
72 72
      * @param string $updateValue
73 73
      * @param string $currentValue
74 74
      * @param int $counter
75
-     * @param $creationTime
75
+     * @param integer $creationTime
76 76
      * @return string
77 77
      */
78 78
     protected function replaceWellKnownMarkers($updateValue, $currentValue, $counter, $creationTime)
Please login to merge, or discard this patch.
Indentation   +109 added lines, -109 removed lines patch added patch discarded remove patch
@@ -26,114 +26,114 @@
 block discarded – undo
26 26
 class MarkerProcessor implements SingletonInterface
27 27
 {
28 28
 
29
-    /**
30
-     * @var array
31
-     */
32
-    protected $wellKnownMarkers = array(
33
-        '{*}',
34
-        '{counter}',
35
-        '{date}',
36
-        '{creation_date}'
37
-    );
38
-
39
-    /**
40
-     * @param ProcessContentDataSignalArguments $signalArguments
41
-     * @return array
42
-     */
43
-    public function processMarkers(ProcessContentDataSignalArguments $signalArguments)
44
-    {
45
-
46
-        $contentData = $signalArguments->getContentData();
47
-        $creationTime = $this->getCreationTime($signalArguments);
48
-
49
-        // Process markers
50
-        foreach ($signalArguments->getContentData() as $fieldName => $updateValue) {
51
-            if (is_scalar($updateValue)) {
52
-
53
-                $currentValue = $this->getContentObjectResolver()->getValue(
54
-                    $signalArguments->getContentObject(),
55
-                    $signalArguments->getFieldNameAndPath(),
56
-                    $fieldName,
57
-                    $signalArguments->getLanguage()
58
-                );
59
-                $counter = $signalArguments->getCounter();
60
-
61
-                $updateValue = $this->searchAndReplace($updateValue, $currentValue);
62
-                $updateValue = $this->replaceWellKnownMarkers($updateValue, $currentValue, $counter, $creationTime);
63
-
64
-                $contentData[$fieldName] = $updateValue;
65
-            }
66
-        }
67
-
68
-        $signalArguments->setContentData($contentData);
69
-        return array($signalArguments);
70
-    }
71
-
72
-    /**
73
-     * @param string $updateValue
74
-     * @param string $currentValue
75
-     * @param int $counter
76
-     * @param $creationTime
77
-     * @return string
78
-     */
79
-    protected function replaceWellKnownMarkers($updateValue, $currentValue, $counter, $creationTime)
80
-    {
81
-
82
-        // Replaces values.
83
-        $replaces = array(
84
-            $currentValue,
85
-            $counter,
86
-            date($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy']),
87
-            date($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'], $creationTime),
88
-        );
89
-
90
-        // Replace me!
91
-        return str_replace($this->wellKnownMarkers, $replaces, $updateValue);
92
-    }
93
-
94
-    /**
95
-     * @param string $updateValue
96
-     * @param string $currentValue
97
-     * @return string
98
-     */
99
-    protected function searchAndReplace($updateValue, $currentValue)
100
-    {
101
-
102
-        if (strpos($updateValue, 's/') !== FALSE) {
103
-            $structure = explode('/', $updateValue);
104
-            $search = $structure[1];
105
-            $replace = $structure[2];
106
-
107
-            // Perhaps needs to be improved here if $search contains "/" precisely.
108
-            $updateValue = preg_replace('/' . $search . '/isU', $replace, $currentValue);
109
-        }
110
-        return $updateValue;
111
-    }
112
-
113
-    /**
114
-     * @param ProcessContentDataSignalArguments $signalArguments
115
-     * @return int
116
-     */
117
-    protected function getCreationTime(ProcessContentDataSignalArguments $signalArguments)
118
-    {
119
-        $creationTime = 0;
120
-        $creationTimeField = Tca::table($signalArguments->getContentObject()->getDataType())->getTimeCreationField();
121
-        if ($creationTimeField) {
122
-            $creationTime = $this->getContentObjectResolver()->getValue(
123
-                $signalArguments->getContentObject(),
124
-                $signalArguments->getFieldNameAndPath(),
125
-                $creationTimeField
126
-            );
127
-        }
128
-        return $creationTime;
129
-    }
130
-
131
-    /**
132
-     * @return ContentObjectResolver
133
-     */
134
-    protected function getContentObjectResolver()
135
-    {
136
-        return GeneralUtility::makeInstance(ContentObjectResolver::class);
137
-    }
29
+	/**
30
+	 * @var array
31
+	 */
32
+	protected $wellKnownMarkers = array(
33
+		'{*}',
34
+		'{counter}',
35
+		'{date}',
36
+		'{creation_date}'
37
+	);
38
+
39
+	/**
40
+	 * @param ProcessContentDataSignalArguments $signalArguments
41
+	 * @return array
42
+	 */
43
+	public function processMarkers(ProcessContentDataSignalArguments $signalArguments)
44
+	{
45
+
46
+		$contentData = $signalArguments->getContentData();
47
+		$creationTime = $this->getCreationTime($signalArguments);
48
+
49
+		// Process markers
50
+		foreach ($signalArguments->getContentData() as $fieldName => $updateValue) {
51
+			if (is_scalar($updateValue)) {
52
+
53
+				$currentValue = $this->getContentObjectResolver()->getValue(
54
+					$signalArguments->getContentObject(),
55
+					$signalArguments->getFieldNameAndPath(),
56
+					$fieldName,
57
+					$signalArguments->getLanguage()
58
+				);
59
+				$counter = $signalArguments->getCounter();
60
+
61
+				$updateValue = $this->searchAndReplace($updateValue, $currentValue);
62
+				$updateValue = $this->replaceWellKnownMarkers($updateValue, $currentValue, $counter, $creationTime);
63
+
64
+				$contentData[$fieldName] = $updateValue;
65
+			}
66
+		}
67
+
68
+		$signalArguments->setContentData($contentData);
69
+		return array($signalArguments);
70
+	}
71
+
72
+	/**
73
+	 * @param string $updateValue
74
+	 * @param string $currentValue
75
+	 * @param int $counter
76
+	 * @param $creationTime
77
+	 * @return string
78
+	 */
79
+	protected function replaceWellKnownMarkers($updateValue, $currentValue, $counter, $creationTime)
80
+	{
81
+
82
+		// Replaces values.
83
+		$replaces = array(
84
+			$currentValue,
85
+			$counter,
86
+			date($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy']),
87
+			date($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'], $creationTime),
88
+		);
89
+
90
+		// Replace me!
91
+		return str_replace($this->wellKnownMarkers, $replaces, $updateValue);
92
+	}
93
+
94
+	/**
95
+	 * @param string $updateValue
96
+	 * @param string $currentValue
97
+	 * @return string
98
+	 */
99
+	protected function searchAndReplace($updateValue, $currentValue)
100
+	{
101
+
102
+		if (strpos($updateValue, 's/') !== FALSE) {
103
+			$structure = explode('/', $updateValue);
104
+			$search = $structure[1];
105
+			$replace = $structure[2];
106
+
107
+			// Perhaps needs to be improved here if $search contains "/" precisely.
108
+			$updateValue = preg_replace('/' . $search . '/isU', $replace, $currentValue);
109
+		}
110
+		return $updateValue;
111
+	}
112
+
113
+	/**
114
+	 * @param ProcessContentDataSignalArguments $signalArguments
115
+	 * @return int
116
+	 */
117
+	protected function getCreationTime(ProcessContentDataSignalArguments $signalArguments)
118
+	{
119
+		$creationTime = 0;
120
+		$creationTimeField = Tca::table($signalArguments->getContentObject()->getDataType())->getTimeCreationField();
121
+		if ($creationTimeField) {
122
+			$creationTime = $this->getContentObjectResolver()->getValue(
123
+				$signalArguments->getContentObject(),
124
+				$signalArguments->getFieldNameAndPath(),
125
+				$creationTimeField
126
+			);
127
+		}
128
+		return $creationTime;
129
+	}
130
+
131
+	/**
132
+	 * @return ContentObjectResolver
133
+	 */
134
+	protected function getContentObjectResolver()
135
+	{
136
+		return GeneralUtility::makeInstance(ContentObjectResolver::class);
137
+	}
138 138
 
139 139
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -105,7 +105,7 @@
 block discarded – undo
105 105
             $replace = $structure[2];
106 106
 
107 107
             // Perhaps needs to be improved here if $search contains "/" precisely.
108
-            $updateValue = preg_replace('/' . $search . '/isU', $replace, $currentValue);
108
+            $updateValue = preg_replace('/'.$search.'/isU', $replace, $currentValue);
109 109
         }
110 110
         return $updateValue;
111 111
     }
Please login to merge, or discard this patch.
Classes/Tca/GridService.php 3 patches
Doc Comments   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -460,7 +460,7 @@  discard block
 block discarded – undo
460 460
      *
461 461
      * @param string $fieldName
462 462
      * @param string $key
463
-     * @param mixed $defaultValue
463
+     * @param boolean|string $defaultValue
464 464
      * @return NULL|mixed
465 465
      */
466 466
     public function get($fieldName, $key, $defaultValue = NULL)
@@ -652,7 +652,7 @@  discard block
 block discarded – undo
652 652
     /**
653 653
      * Returns a "facet" service instance.
654 654
      *
655
-     * @param string|FacetInterface $facetName
655
+     * @param string $facetName
656 656
      * @return FacetInterface
657 657
      */
658 658
     public function facet($facetName = '')
Please login to merge, or discard this patch.
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -78,7 +78,7 @@  discard block
 block discarded – undo
78 78
         $this->tableName = $tableName;
79 79
 
80 80
         if (empty($GLOBALS['TCA'][$this->tableName])) {
81
-            throw new InvalidKeyInArrayException('No TCA existence for table name: ' . $this->tableName, 1356945108);
81
+            throw new InvalidKeyInArrayException('No TCA existence for table name: '.$this->tableName, 1356945108);
82 82
         }
83 83
 
84 84
         $this->tca = $GLOBALS['TCA'][$this->tableName]['grid'];
@@ -178,7 +178,7 @@  discard block
 block discarded – undo
178 178
     {
179 179
         $fields = array_keys($this->getFields());
180 180
         if (empty($fields[$position])) {
181
-            throw new InvalidKeyInArrayException('No field exist for position: ' . $position, 1356945119);
181
+            throw new InvalidKeyInArrayException('No field exist for position: '.$position, 1356945119);
182 182
         }
183 183
 
184 184
         return $fields[$position];
@@ -644,7 +644,7 @@  discard block
 block discarded – undo
644 644
         $facet = GeneralUtility::makeInstance('Fab\Vidi\Facet\StandardFacet', $facetName, $label);
645 645
 
646 646
         if (!$facet instanceof StandardFacet) {
647
-            throw new \RuntimeException('I could not instantiate a facet for facet name "' . (string)$facet . '""', 1445856345);
647
+            throw new \RuntimeException('I could not instantiate a facet for facet name "'.(string)$facet.'""', 1445856345);
648 648
         }
649 649
         return $facet;
650 650
     }
Please login to merge, or discard this patch.
Indentation   +679 added lines, -679 removed lines patch added patch discarded remove patch
@@ -31,684 +31,684 @@
 block discarded – undo
31 31
 class GridService extends AbstractTca
32 32
 {
33 33
 
34
-    /**
35
-     * @var array
36
-     */
37
-    protected $tca;
38
-
39
-    /**
40
-     * @var string
41
-     */
42
-    protected $tableName;
43
-
44
-    /**
45
-     * All fields available in the Grid.
46
-     *
47
-     * @var array
48
-     */
49
-    protected $fields;
50
-
51
-    /**
52
-     * All fields regardless whether they have been excluded or not.
53
-     *
54
-     * @var array
55
-     */
56
-    protected $allFields;
57
-
58
-    /**
59
-     * @var array
60
-     */
61
-    protected $instances;
62
-
63
-    /**
64
-     * @var array
65
-     */
66
-    protected $facets;
67
-
68
-    /**
69
-     * __construct
70
-     *
71
-     * @throws InvalidKeyInArrayException
72
-     * @param string $tableName
73
-     * @return \Fab\Vidi\Tca\GridService
74
-     */
75
-    public function __construct($tableName)
76
-    {
77
-
78
-        $this->tableName = $tableName;
79
-
80
-        if (empty($GLOBALS['TCA'][$this->tableName])) {
81
-            throw new InvalidKeyInArrayException('No TCA existence for table name: ' . $this->tableName, 1356945108);
82
-        }
83
-
84
-        $this->tca = $GLOBALS['TCA'][$this->tableName]['grid'];
85
-    }
86
-
87
-    /**
88
-     * Returns an array containing column names.
89
-     *
90
-     * @return array
91
-     */
92
-    public function getFieldNames()
93
-    {
94
-        $fields = $this->getFields();
95
-        return array_keys($fields);
96
-    }
97
-
98
-    /**
99
-     * Returns an array containing column names.
100
-     *
101
-     * @return array
102
-     */
103
-    public function getAllFieldNames()
104
-    {
105
-        $allFields = $this->getAllFields();
106
-        return array_keys($allFields);
107
-    }
108
-
109
-    /**
110
-     * Get the label key.
111
-     *
112
-     * @param string $fieldNameAndPath
113
-     * @return string
114
-     * @throws \Fab\Vidi\Exception\InvalidKeyInArrayException
115
-     */
116
-    public function getLabelKey($fieldNameAndPath)
117
-    {
118
-
119
-        $field = $this->getField($fieldNameAndPath);
120
-
121
-        // First option is to get the label from the Grid TCA.
122
-        $rawLabel = '';
123
-        if (isset($field['label'])) {
124
-            $rawLabel = $field['label'];
125
-        }
126
-
127
-        // Second option is to fetch the label from the Column Renderer object.
128
-        if (!$rawLabel && $this->hasRenderers($fieldNameAndPath)) {
129
-            $renderers = $this->getRenderers($fieldNameAndPath);
130
-            /** @var $renderer ColumnRendererInterface */
131
-            foreach ($renderers as $renderer) {
132
-                if (isset($renderer['label'])) {
133
-                    $rawLabel = $renderer['label'];
134
-                    break;
135
-                }
136
-            }
137
-        }
138
-        return $rawLabel;
139
-    }
140
-
141
-    /**
142
-     * Get the translation of a label given a column name.
143
-     *
144
-     * @param string $fieldNameAndPath
145
-     * @return string
146
-     */
147
-    public function getLabel($fieldNameAndPath)
148
-    {
149
-        $label = '';
150
-        if ($this->hasLabel($fieldNameAndPath)) {
151
-            $labelKey = $this->getLabelKey($fieldNameAndPath);
152
-            $label = LocalizationUtility::translate($labelKey, '');
153
-            if (is_null($label)) {
154
-                $label = $labelKey;
155
-            }
156
-        } else {
157
-
158
-            // Important to notice the label can contains a path, e.g. metadata.categories and must be resolved.
159
-            $dataType = $this->getFieldPathResolver()->getDataType($fieldNameAndPath, $this->tableName);
160
-            $fieldName = $this->getFieldPathResolver()->stripFieldPath($fieldNameAndPath, $this->tableName);
161
-            $table = Tca::table($dataType);
162
-
163
-            if ($table->hasField($fieldName) && $table->field($fieldName)->hasLabel()) {
164
-                $label = $table->field($fieldName)->getLabel();
165
-            }
166
-        }
167
-
168
-        return $label;
169
-    }
170
-
171
-    /**
172
-     * Returns the field name given its position.
173
-     *
174
-     * @param string $position the position of the field in the grid
175
-     * @throws InvalidKeyInArrayException
176
-     * @return int
177
-     */
178
-    public function getFieldNameByPosition($position)
179
-    {
180
-        $fields = array_keys($this->getFields());
181
-        if (empty($fields[$position])) {
182
-            throw new InvalidKeyInArrayException('No field exist for position: ' . $position, 1356945119);
183
-        }
184
-
185
-        return $fields[$position];
186
-    }
187
-
188
-    /**
189
-     * Returns a field name.
190
-     *
191
-     * @param string $fieldName
192
-     * @return array
193
-     * @throws InvalidKeyInArrayException
194
-     */
195
-    public function getField($fieldName)
196
-    {
197
-        $fields = $this->getFields();
198
-        return $fields[$fieldName];
199
-    }
200
-
201
-    /**
202
-     * Returns an array containing column names for the Grid.
203
-     *
204
-     * @return array
205
-     * @throws \Exception
206
-     */
207
-    public function getFields()
208
-    {
209
-        // Cache this operation since it can take some time.
210
-        if (is_null($this->fields)) {
211
-
212
-            // Fetch all available fields first.
213
-            $fields = $this->getAllFields();
214
-
215
-            if ($this->isBackendMode()) {
216
-
217
-                // Then remove the not allowed.
218
-                $fields = $this->filterByIncludedFields($fields);
219
-                $fields = $this->filterByBackendUser($fields);
220
-                $fields = $this->filterByExcludedFields($fields);
221
-            }
222
-
223
-            $this->fields = $fields;
224
-        }
225
-
226
-        return $this->fields;
227
-    }
228
-
229
-    /**
230
-     * Remove fields according to Grid configuration.
231
-     *
232
-     * @param $fields
233
-     * @return array
234
-     */
235
-    protected function filterByIncludedFields($fields)
236
-    {
237
-
238
-        $filteredFields = $fields;
239
-        $includedFields = $this->getIncludedFields();
240
-        if (count($includedFields) > 0) {
241
-            $filteredFields = [];
242
-            foreach ($fields as $fieldNameAndPath => $configuration) {
243
-                if (in_array($fieldNameAndPath, $includedFields, true) || !Tca::table($this->tableName)->hasField($fieldNameAndPath)) {
244
-                    $filteredFields[$fieldNameAndPath] = $configuration;
245
-                }
246
-            }
247
-        }
248
-        return $filteredFields;
249
-    }
250
-
251
-    /**
252
-     * Remove fields according to BE User permission.
253
-     *
254
-     * @param $fields
255
-     * @return array
256
-     * @throws \Exception
257
-     */
258
-    protected function filterByBackendUser($fields)
259
-    {
260
-        if (!$this->getBackendUser()->isAdmin()) {
261
-            foreach ($fields as $fieldName => $field) {
262
-                if (Tca::table($this->tableName)->hasField($fieldName) && !Tca::table($this->tableName)->field($fieldName)->hasAccess()) {
263
-                    unset($fields[$fieldName]);
264
-                }
265
-            }
266
-        }
267
-        return $fields;
268
-    }
269
-
270
-    /**
271
-     * Remove fields according to Grid configuration.
272
-     *
273
-     * @param $fields
274
-     * @return array
275
-     */
276
-    protected function filterByExcludedFields($fields)
277
-    {
278
-
279
-        // Unset excluded fields.
280
-        foreach ($this->getExcludedFields() as $excludedField) {
281
-            if (isset($fields[$excludedField])) {
282
-                unset($fields[$excludedField]);
283
-            }
284
-        }
285
-
286
-        return $fields;
287
-    }
288
-
289
-    /**
290
-     * Returns an array containing column names for the Grid.
291
-     *
292
-     * @return array
293
-     */
294
-    public function getAllFields()
295
-    {
296
-
297
-        // Cache this operation since it can take some time.
298
-        if (is_null($this->allFields)) {
299
-
300
-            $fields = is_array($this->tca['columns']) ? $this->tca['columns'] : array();
301
-            $gridFieldNames = array_keys($fields);
302
-
303
-            // Fetch all fields of the TCA and merge it back to the fields configured for Grid.
304
-            $tableFieldNames = Tca::table($this->tableName)->getFields();
305
-
306
-            // Just remove system fields from the Grid.
307
-            foreach ($tableFieldNames as $key => $fieldName) {
308
-                if (in_array($fieldName, Tca::getSystemFields())) {
309
-                    unset($tableFieldNames[$key]);
310
-                }
311
-            }
312
-
313
-            $additionalFields = array_diff($tableFieldNames, $gridFieldNames);
314
-
315
-            if (!empty($additionalFields)) {
316
-
317
-                // Pop out last element of the key
318
-                // Idea is to place new un-configured columns in between. By default, they will be hidden.
319
-                end($fields);
320
-                $lastColumnKey = key($fields);
321
-                $lastColumn = array_pop($fields);
322
-
323
-                // Feed up the grid fields with un configured elements
324
-                foreach ($additionalFields as $additionalField) {
325
-                    $fields[$additionalField] = array(
326
-                        'visible' => FALSE
327
-                    );
328
-
329
-                    // Try to guess the format of the field.
330
-                    $fieldType = Tca::table($this->tableName)->field($additionalField)->getType();
331
-                    if ($fieldType === FieldType::DATE) {
332
-                        $fields[$additionalField]['format'] = 'Fab\Vidi\Formatter\Date';
333
-                    } elseif ($fieldType === FieldType::DATETIME) {
334
-                        $fields[$additionalField]['format'] = 'Fab\Vidi\Formatter\Datetime';
335
-                    }
336
-                }
337
-                $fields[$lastColumnKey] = $lastColumn;
338
-            }
339
-
340
-            $this->allFields = $fields;
341
-        }
342
-
343
-        return $this->allFields;
344
-    }
345
-
346
-    /**
347
-     * Tell whether the field exists in the grid or not.
348
-     *
349
-     * @param string $fieldName
350
-     * @return bool
351
-     */
352
-    public function hasField($fieldName)
353
-    {
354
-        $fields = $this->getFields();
355
-        return isset($fields[$fieldName]);
356
-    }
357
-
358
-    /**
359
-     * Tell whether the facet exists in the grid or not.
360
-     *
361
-     * @param string $facetName
362
-     * @return bool
363
-     */
364
-    public function hasFacet($facetName)
365
-    {
366
-        $facets = $this->getFacets();
367
-        return isset($facets[$facetName]);
368
-    }
369
-
370
-    /**
371
-     * Returns an array containing facets fields.
372
-     *
373
-     * @return FacetInterface[]
374
-     */
375
-    public function getFacets()
376
-    {
377
-        if (is_null($this->facets)) {
378
-            $this->facets = array();
379
-
380
-            if (is_array($this->tca['facets'])) {
381
-                foreach ($this->tca['facets'] as $facetNameOrObject) {
382
-                    if ($facetNameOrObject instanceof FacetInterface) {
383
-                        $this->facets[$facetNameOrObject->getName()] = $facetNameOrObject;
384
-                    } else {
385
-                        $this->facets[$facetNameOrObject] = $this->instantiateStandardFacet($facetNameOrObject);
386
-                    }
387
-                }
388
-            }
389
-        }
390
-        return $this->facets;
391
-    }
392
-
393
-    /**
394
-     * Returns the "sortable" value of the column.
395
-     *
396
-     * @param string $fieldName
397
-     * @return int|string
398
-     */
399
-    public function isSortable($fieldName)
400
-    {
401
-        $defaultValue = true;
402
-        $hasSortableField = Tca::table($this->tableName)->hasSortableField();
403
-        if ($hasSortableField) {
404
-            $isSortable = false;
405
-        } else {
406
-            $isSortable = $this->get($fieldName, 'sortable', $defaultValue);
407
-        }
408
-        return $isSortable;
409
-    }
410
-
411
-    /**
412
-     * Returns the "canBeHidden" value of the column.
413
-     *
414
-     * @param string $fieldName
415
-     * @return bool
416
-     */
417
-    public function canBeHidden($fieldName)
418
-    {
419
-        $defaultValue = TRUE;
420
-        return $this->get($fieldName, 'canBeHidden', $defaultValue);
421
-    }
422
-
423
-    /**
424
-     * Returns the "width" value of the column.
425
-     *
426
-     * @param string $fieldName
427
-     * @return int|string
428
-     */
429
-    public function getWidth($fieldName)
430
-    {
431
-        $defaultValue = 'auto';
432
-        return $this->get($fieldName, 'width', $defaultValue);
433
-    }
434
-
435
-    /**
436
-     * Returns the "visible" value of the column.
437
-     *
438
-     * @param string $fieldName
439
-     * @return bool
440
-     */
441
-    public function isVisible($fieldName)
442
-    {
443
-        $defaultValue = TRUE;
444
-        return $this->get($fieldName, 'visible', $defaultValue);
445
-    }
446
-
447
-    /**
448
-     * Returns the "editable" value of the column.
449
-     *
450
-     * @param string $columnName
451
-     * @return bool
452
-     */
453
-    public function isEditable($columnName)
454
-    {
455
-        $defaultValue = FALSE;
456
-        return $this->get($columnName, 'editable', $defaultValue);
457
-    }
458
-
459
-    /**
460
-     * Returns the "localized" value of the column.
461
-     *
462
-     * @param string $columnName
463
-     * @return bool
464
-     */
465
-    public function isLocalized($columnName)
466
-    {
467
-        $defaultValue = TRUE;
468
-        return $this->get($columnName, 'localized', $defaultValue);
469
-    }
470
-
471
-    /**
472
-     *
473
-     * Returns the "html" value of the column.
474
-     *
475
-     * @param string $fieldName
476
-     * @return string
477
-     */
478
-    public function getHeader($fieldName)
479
-    {
480
-        $defaultValue = '';
481
-        return $this->get($fieldName, 'html', $defaultValue);
482
-    }
483
-
484
-    /**
485
-     * Fetch a possible from a Grid Renderer. If no value is found, returns NULL
486
-     *
487
-     * @param string $fieldName
488
-     * @param string $key
489
-     * @param mixed $defaultValue
490
-     * @return NULL|mixed
491
-     */
492
-    public function get($fieldName, $key, $defaultValue = NULL)
493
-    {
494
-        $value = $defaultValue;
495
-
496
-        $field = $this->getField($fieldName);
497
-        if (isset($field[$key])) {
498
-            $value = $field[$key];
499
-        } elseif ($this->hasRenderers($fieldName)) {
500
-            $renderers = $this->getRenderers($fieldName);
501
-            foreach ($renderers as $rendererConfiguration) {
502
-                if (isset($rendererConfiguration[$key])) {
503
-                    $value = $rendererConfiguration[$key];
504
-                }
505
-            }
506
-        }
507
-        return $value;
508
-    }
509
-
510
-    /**
511
-     * Returns whether the column has a renderer.
512
-     *
513
-     * @param string $fieldName
514
-     * @return bool
515
-     */
516
-    public function hasRenderers($fieldName)
517
-    {
518
-        $field = $this->getField($fieldName);
519
-        return empty($field['renderer']) && empty($field['renderers']) ? FALSE : TRUE;
520
-    }
521
-
522
-    /**
523
-     * Returns a renderer.
524
-     *
525
-     * @param string $fieldName
526
-     * @return array
527
-     */
528
-    public function getRenderers($fieldName)
529
-    {
530
-        $field = $this->getField($fieldName);
531
-        $renderers = array();
532
-        if (!empty($field['renderer'])) {
533
-            $renderers = $this->convertRendererToArray($field['renderer']);
534
-        } elseif (!empty($field['renderers']) && is_array($field['renderers'])) {
535
-            foreach ($field['renderers'] as $renderer) {
536
-                $rendererNameAndConfiguration = $this->convertRendererToArray($renderer);
537
-                $renderers = array_merge($renderers, $rendererNameAndConfiguration);
538
-            }
539
-        }
540
-
541
-        return $renderers;
542
-    }
543
-
544
-    /**
545
-     * @param string|GenericColumn $renderer
546
-     * @return array
547
-     */
548
-    public function convertRendererToArray($renderer)
549
-    {
550
-        $result = array();
551
-        if (is_string($renderer)) {
552
-            $result[$renderer] = array();
553
-        } elseif ($renderer instanceof ColumnInterface || $renderer instanceof ColumnRendererInterface) {
554
-            /** @var GenericColumn $renderer */
555
-            $result[get_class($renderer)] = $renderer->getConfiguration();
556
-        }
557
-        return $result;
558
-    }
559
-
560
-    /**
561
-     * Returns the class names applied to a cell
562
-     *
563
-     * @param string $fieldName
564
-     * @return bool
565
-     */
566
-    public function getClass($fieldName)
567
-    {
568
-        $field = $this->getField($fieldName);
569
-        return isset($field['class']) ? $field['class'] : '';
570
-    }
571
-
572
-    /**
573
-     * Returns whether the column has a label.
574
-     *
575
-     * @param string $fieldNameAndPath
576
-     * @return bool
577
-     */
578
-    public function hasLabel($fieldNameAndPath)
579
-    {
580
-        $field = $this->getField($fieldNameAndPath);
581
-
582
-        $hasLabel = empty($field['label']) ? FALSE : TRUE;
583
-
584
-        if (!$hasLabel && $this->hasRenderers($fieldNameAndPath)) {
585
-            $renderers = $this->getRenderers($fieldNameAndPath);
586
-            /** @var $renderer ColumnRendererInterface */
587
-            foreach ($renderers as $renderer) {
588
-                if (isset($renderer['label'])) {
589
-                    $hasLabel = TRUE;
590
-                    break;
591
-                }
592
-            }
593
-        }
594
-        return $hasLabel;
595
-    }
596
-
597
-    /**
598
-     * @return array
599
-     */
600
-    public function getTca()
601
-    {
602
-        return $this->tca;
603
-    }
604
-
605
-    /**
606
-     * @return array
607
-     */
608
-    public function getIncludedFields()
609
-    {
610
-        return empty($this->tca['included_fields']) ? [] : GeneralUtility::trimExplode(',', $this->tca['included_fields'], true);
611
-    }
612
-
613
-    /**
614
-     * Return excluded fields from configuration + preferences.
615
-     *
616
-     * @return array
617
-     */
618
-    public function getExcludedFields()
619
-    {
620
-        $configurationFields = $this->getExcludedFieldsFromConfiguration();
621
-        $preferencesFields = $this->getExcludedFieldsFromPreferences();
622
-
623
-        return array_merge($configurationFields, $preferencesFields);
624
-    }
625
-
626
-    /**
627
-     * Fetch excluded fields from configuration.
628
-     *
629
-     * @return array
630
-     */
631
-    protected function getExcludedFieldsFromConfiguration()
632
-    {
633
-        $excludedFields = array();
634
-        if (!empty($this->tca['excluded_fields'])) {
635
-            $excludedFields = GeneralUtility::trimExplode(',', $this->tca['excluded_fields'], TRUE);
636
-        } elseif (!empty($this->tca['export']['excluded_fields'])) { // only for export for legacy reason.
637
-            $excludedFields = GeneralUtility::trimExplode(',', $this->tca['export']['excluded_fields'], TRUE);
638
-        }
639
-        return $excludedFields;
640
-
641
-    }
642
-
643
-    /**
644
-     * Fetch excluded fields from preferences.
645
-     *
646
-     * @return array
647
-     */
648
-    protected function getExcludedFieldsFromPreferences()
649
-    {
650
-        $excludedFields = $this->getModulePreferences()->get(ConfigurablePart::EXCLUDED_FIELDS, $this->tableName);
651
-        return is_array($excludedFields) ? $excludedFields : array();
652
-    }
653
-
654
-    /**
655
-     * @return array
656
-     */
657
-    public function areFilesIncludedInExport()
658
-    {
659
-        $isIncluded = TRUE;
660
-
661
-        if (isset($this->tca['export']['include_files'])) {
662
-            $isIncluded = $this->tca['export']['include_files'];
663
-        }
664
-        return $isIncluded;
665
-    }
666
-
667
-    /**
668
-     * Returns a "facet" service instance.
669
-     *
670
-     * @param string|FacetInterface $facetName
671
-     * @return StandardFacet
672
-     */
673
-    protected function instantiateStandardFacet($facetName)
674
-    {
675
-        $label = $this->getLabel($facetName);
676
-
677
-        /** @var StandardFacet $facetName */
678
-        $facet = GeneralUtility::makeInstance('Fab\Vidi\Facet\StandardFacet', $facetName, $label);
679
-
680
-        if (!$facet instanceof StandardFacet) {
681
-            throw new \RuntimeException('I could not instantiate a facet for facet name "' . (string)$facet . '""', 1445856345);
682
-        }
683
-        return $facet;
684
-    }
685
-
686
-    /**
687
-     * Returns a "facet" service instance.
688
-     *
689
-     * @param string|FacetInterface $facetName
690
-     * @return FacetInterface
691
-     */
692
-    public function facet($facetName = '')
693
-    {
694
-        $facets = $this->getFacets();
695
-        return $facets[$facetName];
696
-    }
697
-
698
-    /**
699
-     * @return \Fab\Vidi\Resolver\FieldPathResolver
700
-     */
701
-    protected function getFieldPathResolver()
702
-    {
703
-        return GeneralUtility::makeInstance('Fab\Vidi\Resolver\FieldPathResolver');
704
-    }
705
-
706
-    /**
707
-     * @return ModulePreferences
708
-     */
709
-    protected function getModulePreferences()
710
-    {
711
-        return GeneralUtility::makeInstance('Fab\Vidi\Module\ModulePreferences');
712
-    }
34
+	/**
35
+	 * @var array
36
+	 */
37
+	protected $tca;
38
+
39
+	/**
40
+	 * @var string
41
+	 */
42
+	protected $tableName;
43
+
44
+	/**
45
+	 * All fields available in the Grid.
46
+	 *
47
+	 * @var array
48
+	 */
49
+	protected $fields;
50
+
51
+	/**
52
+	 * All fields regardless whether they have been excluded or not.
53
+	 *
54
+	 * @var array
55
+	 */
56
+	protected $allFields;
57
+
58
+	/**
59
+	 * @var array
60
+	 */
61
+	protected $instances;
62
+
63
+	/**
64
+	 * @var array
65
+	 */
66
+	protected $facets;
67
+
68
+	/**
69
+	 * __construct
70
+	 *
71
+	 * @throws InvalidKeyInArrayException
72
+	 * @param string $tableName
73
+	 * @return \Fab\Vidi\Tca\GridService
74
+	 */
75
+	public function __construct($tableName)
76
+	{
77
+
78
+		$this->tableName = $tableName;
79
+
80
+		if (empty($GLOBALS['TCA'][$this->tableName])) {
81
+			throw new InvalidKeyInArrayException('No TCA existence for table name: ' . $this->tableName, 1356945108);
82
+		}
83
+
84
+		$this->tca = $GLOBALS['TCA'][$this->tableName]['grid'];
85
+	}
86
+
87
+	/**
88
+	 * Returns an array containing column names.
89
+	 *
90
+	 * @return array
91
+	 */
92
+	public function getFieldNames()
93
+	{
94
+		$fields = $this->getFields();
95
+		return array_keys($fields);
96
+	}
97
+
98
+	/**
99
+	 * Returns an array containing column names.
100
+	 *
101
+	 * @return array
102
+	 */
103
+	public function getAllFieldNames()
104
+	{
105
+		$allFields = $this->getAllFields();
106
+		return array_keys($allFields);
107
+	}
108
+
109
+	/**
110
+	 * Get the label key.
111
+	 *
112
+	 * @param string $fieldNameAndPath
113
+	 * @return string
114
+	 * @throws \Fab\Vidi\Exception\InvalidKeyInArrayException
115
+	 */
116
+	public function getLabelKey($fieldNameAndPath)
117
+	{
118
+
119
+		$field = $this->getField($fieldNameAndPath);
120
+
121
+		// First option is to get the label from the Grid TCA.
122
+		$rawLabel = '';
123
+		if (isset($field['label'])) {
124
+			$rawLabel = $field['label'];
125
+		}
126
+
127
+		// Second option is to fetch the label from the Column Renderer object.
128
+		if (!$rawLabel && $this->hasRenderers($fieldNameAndPath)) {
129
+			$renderers = $this->getRenderers($fieldNameAndPath);
130
+			/** @var $renderer ColumnRendererInterface */
131
+			foreach ($renderers as $renderer) {
132
+				if (isset($renderer['label'])) {
133
+					$rawLabel = $renderer['label'];
134
+					break;
135
+				}
136
+			}
137
+		}
138
+		return $rawLabel;
139
+	}
140
+
141
+	/**
142
+	 * Get the translation of a label given a column name.
143
+	 *
144
+	 * @param string $fieldNameAndPath
145
+	 * @return string
146
+	 */
147
+	public function getLabel($fieldNameAndPath)
148
+	{
149
+		$label = '';
150
+		if ($this->hasLabel($fieldNameAndPath)) {
151
+			$labelKey = $this->getLabelKey($fieldNameAndPath);
152
+			$label = LocalizationUtility::translate($labelKey, '');
153
+			if (is_null($label)) {
154
+				$label = $labelKey;
155
+			}
156
+		} else {
157
+
158
+			// Important to notice the label can contains a path, e.g. metadata.categories and must be resolved.
159
+			$dataType = $this->getFieldPathResolver()->getDataType($fieldNameAndPath, $this->tableName);
160
+			$fieldName = $this->getFieldPathResolver()->stripFieldPath($fieldNameAndPath, $this->tableName);
161
+			$table = Tca::table($dataType);
162
+
163
+			if ($table->hasField($fieldName) && $table->field($fieldName)->hasLabel()) {
164
+				$label = $table->field($fieldName)->getLabel();
165
+			}
166
+		}
167
+
168
+		return $label;
169
+	}
170
+
171
+	/**
172
+	 * Returns the field name given its position.
173
+	 *
174
+	 * @param string $position the position of the field in the grid
175
+	 * @throws InvalidKeyInArrayException
176
+	 * @return int
177
+	 */
178
+	public function getFieldNameByPosition($position)
179
+	{
180
+		$fields = array_keys($this->getFields());
181
+		if (empty($fields[$position])) {
182
+			throw new InvalidKeyInArrayException('No field exist for position: ' . $position, 1356945119);
183
+		}
184
+
185
+		return $fields[$position];
186
+	}
187
+
188
+	/**
189
+	 * Returns a field name.
190
+	 *
191
+	 * @param string $fieldName
192
+	 * @return array
193
+	 * @throws InvalidKeyInArrayException
194
+	 */
195
+	public function getField($fieldName)
196
+	{
197
+		$fields = $this->getFields();
198
+		return $fields[$fieldName];
199
+	}
200
+
201
+	/**
202
+	 * Returns an array containing column names for the Grid.
203
+	 *
204
+	 * @return array
205
+	 * @throws \Exception
206
+	 */
207
+	public function getFields()
208
+	{
209
+		// Cache this operation since it can take some time.
210
+		if (is_null($this->fields)) {
211
+
212
+			// Fetch all available fields first.
213
+			$fields = $this->getAllFields();
214
+
215
+			if ($this->isBackendMode()) {
216
+
217
+				// Then remove the not allowed.
218
+				$fields = $this->filterByIncludedFields($fields);
219
+				$fields = $this->filterByBackendUser($fields);
220
+				$fields = $this->filterByExcludedFields($fields);
221
+			}
222
+
223
+			$this->fields = $fields;
224
+		}
225
+
226
+		return $this->fields;
227
+	}
228
+
229
+	/**
230
+	 * Remove fields according to Grid configuration.
231
+	 *
232
+	 * @param $fields
233
+	 * @return array
234
+	 */
235
+	protected function filterByIncludedFields($fields)
236
+	{
237
+
238
+		$filteredFields = $fields;
239
+		$includedFields = $this->getIncludedFields();
240
+		if (count($includedFields) > 0) {
241
+			$filteredFields = [];
242
+			foreach ($fields as $fieldNameAndPath => $configuration) {
243
+				if (in_array($fieldNameAndPath, $includedFields, true) || !Tca::table($this->tableName)->hasField($fieldNameAndPath)) {
244
+					$filteredFields[$fieldNameAndPath] = $configuration;
245
+				}
246
+			}
247
+		}
248
+		return $filteredFields;
249
+	}
250
+
251
+	/**
252
+	 * Remove fields according to BE User permission.
253
+	 *
254
+	 * @param $fields
255
+	 * @return array
256
+	 * @throws \Exception
257
+	 */
258
+	protected function filterByBackendUser($fields)
259
+	{
260
+		if (!$this->getBackendUser()->isAdmin()) {
261
+			foreach ($fields as $fieldName => $field) {
262
+				if (Tca::table($this->tableName)->hasField($fieldName) && !Tca::table($this->tableName)->field($fieldName)->hasAccess()) {
263
+					unset($fields[$fieldName]);
264
+				}
265
+			}
266
+		}
267
+		return $fields;
268
+	}
269
+
270
+	/**
271
+	 * Remove fields according to Grid configuration.
272
+	 *
273
+	 * @param $fields
274
+	 * @return array
275
+	 */
276
+	protected function filterByExcludedFields($fields)
277
+	{
278
+
279
+		// Unset excluded fields.
280
+		foreach ($this->getExcludedFields() as $excludedField) {
281
+			if (isset($fields[$excludedField])) {
282
+				unset($fields[$excludedField]);
283
+			}
284
+		}
285
+
286
+		return $fields;
287
+	}
288
+
289
+	/**
290
+	 * Returns an array containing column names for the Grid.
291
+	 *
292
+	 * @return array
293
+	 */
294
+	public function getAllFields()
295
+	{
296
+
297
+		// Cache this operation since it can take some time.
298
+		if (is_null($this->allFields)) {
299
+
300
+			$fields = is_array($this->tca['columns']) ? $this->tca['columns'] : array();
301
+			$gridFieldNames = array_keys($fields);
302
+
303
+			// Fetch all fields of the TCA and merge it back to the fields configured for Grid.
304
+			$tableFieldNames = Tca::table($this->tableName)->getFields();
305
+
306
+			// Just remove system fields from the Grid.
307
+			foreach ($tableFieldNames as $key => $fieldName) {
308
+				if (in_array($fieldName, Tca::getSystemFields())) {
309
+					unset($tableFieldNames[$key]);
310
+				}
311
+			}
312
+
313
+			$additionalFields = array_diff($tableFieldNames, $gridFieldNames);
314
+
315
+			if (!empty($additionalFields)) {
316
+
317
+				// Pop out last element of the key
318
+				// Idea is to place new un-configured columns in between. By default, they will be hidden.
319
+				end($fields);
320
+				$lastColumnKey = key($fields);
321
+				$lastColumn = array_pop($fields);
322
+
323
+				// Feed up the grid fields with un configured elements
324
+				foreach ($additionalFields as $additionalField) {
325
+					$fields[$additionalField] = array(
326
+						'visible' => FALSE
327
+					);
328
+
329
+					// Try to guess the format of the field.
330
+					$fieldType = Tca::table($this->tableName)->field($additionalField)->getType();
331
+					if ($fieldType === FieldType::DATE) {
332
+						$fields[$additionalField]['format'] = 'Fab\Vidi\Formatter\Date';
333
+					} elseif ($fieldType === FieldType::DATETIME) {
334
+						$fields[$additionalField]['format'] = 'Fab\Vidi\Formatter\Datetime';
335
+					}
336
+				}
337
+				$fields[$lastColumnKey] = $lastColumn;
338
+			}
339
+
340
+			$this->allFields = $fields;
341
+		}
342
+
343
+		return $this->allFields;
344
+	}
345
+
346
+	/**
347
+	 * Tell whether the field exists in the grid or not.
348
+	 *
349
+	 * @param string $fieldName
350
+	 * @return bool
351
+	 */
352
+	public function hasField($fieldName)
353
+	{
354
+		$fields = $this->getFields();
355
+		return isset($fields[$fieldName]);
356
+	}
357
+
358
+	/**
359
+	 * Tell whether the facet exists in the grid or not.
360
+	 *
361
+	 * @param string $facetName
362
+	 * @return bool
363
+	 */
364
+	public function hasFacet($facetName)
365
+	{
366
+		$facets = $this->getFacets();
367
+		return isset($facets[$facetName]);
368
+	}
369
+
370
+	/**
371
+	 * Returns an array containing facets fields.
372
+	 *
373
+	 * @return FacetInterface[]
374
+	 */
375
+	public function getFacets()
376
+	{
377
+		if (is_null($this->facets)) {
378
+			$this->facets = array();
379
+
380
+			if (is_array($this->tca['facets'])) {
381
+				foreach ($this->tca['facets'] as $facetNameOrObject) {
382
+					if ($facetNameOrObject instanceof FacetInterface) {
383
+						$this->facets[$facetNameOrObject->getName()] = $facetNameOrObject;
384
+					} else {
385
+						$this->facets[$facetNameOrObject] = $this->instantiateStandardFacet($facetNameOrObject);
386
+					}
387
+				}
388
+			}
389
+		}
390
+		return $this->facets;
391
+	}
392
+
393
+	/**
394
+	 * Returns the "sortable" value of the column.
395
+	 *
396
+	 * @param string $fieldName
397
+	 * @return int|string
398
+	 */
399
+	public function isSortable($fieldName)
400
+	{
401
+		$defaultValue = true;
402
+		$hasSortableField = Tca::table($this->tableName)->hasSortableField();
403
+		if ($hasSortableField) {
404
+			$isSortable = false;
405
+		} else {
406
+			$isSortable = $this->get($fieldName, 'sortable', $defaultValue);
407
+		}
408
+		return $isSortable;
409
+	}
410
+
411
+	/**
412
+	 * Returns the "canBeHidden" value of the column.
413
+	 *
414
+	 * @param string $fieldName
415
+	 * @return bool
416
+	 */
417
+	public function canBeHidden($fieldName)
418
+	{
419
+		$defaultValue = TRUE;
420
+		return $this->get($fieldName, 'canBeHidden', $defaultValue);
421
+	}
422
+
423
+	/**
424
+	 * Returns the "width" value of the column.
425
+	 *
426
+	 * @param string $fieldName
427
+	 * @return int|string
428
+	 */
429
+	public function getWidth($fieldName)
430
+	{
431
+		$defaultValue = 'auto';
432
+		return $this->get($fieldName, 'width', $defaultValue);
433
+	}
434
+
435
+	/**
436
+	 * Returns the "visible" value of the column.
437
+	 *
438
+	 * @param string $fieldName
439
+	 * @return bool
440
+	 */
441
+	public function isVisible($fieldName)
442
+	{
443
+		$defaultValue = TRUE;
444
+		return $this->get($fieldName, 'visible', $defaultValue);
445
+	}
446
+
447
+	/**
448
+	 * Returns the "editable" value of the column.
449
+	 *
450
+	 * @param string $columnName
451
+	 * @return bool
452
+	 */
453
+	public function isEditable($columnName)
454
+	{
455
+		$defaultValue = FALSE;
456
+		return $this->get($columnName, 'editable', $defaultValue);
457
+	}
458
+
459
+	/**
460
+	 * Returns the "localized" value of the column.
461
+	 *
462
+	 * @param string $columnName
463
+	 * @return bool
464
+	 */
465
+	public function isLocalized($columnName)
466
+	{
467
+		$defaultValue = TRUE;
468
+		return $this->get($columnName, 'localized', $defaultValue);
469
+	}
470
+
471
+	/**
472
+	 *
473
+	 * Returns the "html" value of the column.
474
+	 *
475
+	 * @param string $fieldName
476
+	 * @return string
477
+	 */
478
+	public function getHeader($fieldName)
479
+	{
480
+		$defaultValue = '';
481
+		return $this->get($fieldName, 'html', $defaultValue);
482
+	}
483
+
484
+	/**
485
+	 * Fetch a possible from a Grid Renderer. If no value is found, returns NULL
486
+	 *
487
+	 * @param string $fieldName
488
+	 * @param string $key
489
+	 * @param mixed $defaultValue
490
+	 * @return NULL|mixed
491
+	 */
492
+	public function get($fieldName, $key, $defaultValue = NULL)
493
+	{
494
+		$value = $defaultValue;
495
+
496
+		$field = $this->getField($fieldName);
497
+		if (isset($field[$key])) {
498
+			$value = $field[$key];
499
+		} elseif ($this->hasRenderers($fieldName)) {
500
+			$renderers = $this->getRenderers($fieldName);
501
+			foreach ($renderers as $rendererConfiguration) {
502
+				if (isset($rendererConfiguration[$key])) {
503
+					$value = $rendererConfiguration[$key];
504
+				}
505
+			}
506
+		}
507
+		return $value;
508
+	}
509
+
510
+	/**
511
+	 * Returns whether the column has a renderer.
512
+	 *
513
+	 * @param string $fieldName
514
+	 * @return bool
515
+	 */
516
+	public function hasRenderers($fieldName)
517
+	{
518
+		$field = $this->getField($fieldName);
519
+		return empty($field['renderer']) && empty($field['renderers']) ? FALSE : TRUE;
520
+	}
521
+
522
+	/**
523
+	 * Returns a renderer.
524
+	 *
525
+	 * @param string $fieldName
526
+	 * @return array
527
+	 */
528
+	public function getRenderers($fieldName)
529
+	{
530
+		$field = $this->getField($fieldName);
531
+		$renderers = array();
532
+		if (!empty($field['renderer'])) {
533
+			$renderers = $this->convertRendererToArray($field['renderer']);
534
+		} elseif (!empty($field['renderers']) && is_array($field['renderers'])) {
535
+			foreach ($field['renderers'] as $renderer) {
536
+				$rendererNameAndConfiguration = $this->convertRendererToArray($renderer);
537
+				$renderers = array_merge($renderers, $rendererNameAndConfiguration);
538
+			}
539
+		}
540
+
541
+		return $renderers;
542
+	}
543
+
544
+	/**
545
+	 * @param string|GenericColumn $renderer
546
+	 * @return array
547
+	 */
548
+	public function convertRendererToArray($renderer)
549
+	{
550
+		$result = array();
551
+		if (is_string($renderer)) {
552
+			$result[$renderer] = array();
553
+		} elseif ($renderer instanceof ColumnInterface || $renderer instanceof ColumnRendererInterface) {
554
+			/** @var GenericColumn $renderer */
555
+			$result[get_class($renderer)] = $renderer->getConfiguration();
556
+		}
557
+		return $result;
558
+	}
559
+
560
+	/**
561
+	 * Returns the class names applied to a cell
562
+	 *
563
+	 * @param string $fieldName
564
+	 * @return bool
565
+	 */
566
+	public function getClass($fieldName)
567
+	{
568
+		$field = $this->getField($fieldName);
569
+		return isset($field['class']) ? $field['class'] : '';
570
+	}
571
+
572
+	/**
573
+	 * Returns whether the column has a label.
574
+	 *
575
+	 * @param string $fieldNameAndPath
576
+	 * @return bool
577
+	 */
578
+	public function hasLabel($fieldNameAndPath)
579
+	{
580
+		$field = $this->getField($fieldNameAndPath);
581
+
582
+		$hasLabel = empty($field['label']) ? FALSE : TRUE;
583
+
584
+		if (!$hasLabel && $this->hasRenderers($fieldNameAndPath)) {
585
+			$renderers = $this->getRenderers($fieldNameAndPath);
586
+			/** @var $renderer ColumnRendererInterface */
587
+			foreach ($renderers as $renderer) {
588
+				if (isset($renderer['label'])) {
589
+					$hasLabel = TRUE;
590
+					break;
591
+				}
592
+			}
593
+		}
594
+		return $hasLabel;
595
+	}
596
+
597
+	/**
598
+	 * @return array
599
+	 */
600
+	public function getTca()
601
+	{
602
+		return $this->tca;
603
+	}
604
+
605
+	/**
606
+	 * @return array
607
+	 */
608
+	public function getIncludedFields()
609
+	{
610
+		return empty($this->tca['included_fields']) ? [] : GeneralUtility::trimExplode(',', $this->tca['included_fields'], true);
611
+	}
612
+
613
+	/**
614
+	 * Return excluded fields from configuration + preferences.
615
+	 *
616
+	 * @return array
617
+	 */
618
+	public function getExcludedFields()
619
+	{
620
+		$configurationFields = $this->getExcludedFieldsFromConfiguration();
621
+		$preferencesFields = $this->getExcludedFieldsFromPreferences();
622
+
623
+		return array_merge($configurationFields, $preferencesFields);
624
+	}
625
+
626
+	/**
627
+	 * Fetch excluded fields from configuration.
628
+	 *
629
+	 * @return array
630
+	 */
631
+	protected function getExcludedFieldsFromConfiguration()
632
+	{
633
+		$excludedFields = array();
634
+		if (!empty($this->tca['excluded_fields'])) {
635
+			$excludedFields = GeneralUtility::trimExplode(',', $this->tca['excluded_fields'], TRUE);
636
+		} elseif (!empty($this->tca['export']['excluded_fields'])) { // only for export for legacy reason.
637
+			$excludedFields = GeneralUtility::trimExplode(',', $this->tca['export']['excluded_fields'], TRUE);
638
+		}
639
+		return $excludedFields;
640
+
641
+	}
642
+
643
+	/**
644
+	 * Fetch excluded fields from preferences.
645
+	 *
646
+	 * @return array
647
+	 */
648
+	protected function getExcludedFieldsFromPreferences()
649
+	{
650
+		$excludedFields = $this->getModulePreferences()->get(ConfigurablePart::EXCLUDED_FIELDS, $this->tableName);
651
+		return is_array($excludedFields) ? $excludedFields : array();
652
+	}
653
+
654
+	/**
655
+	 * @return array
656
+	 */
657
+	public function areFilesIncludedInExport()
658
+	{
659
+		$isIncluded = TRUE;
660
+
661
+		if (isset($this->tca['export']['include_files'])) {
662
+			$isIncluded = $this->tca['export']['include_files'];
663
+		}
664
+		return $isIncluded;
665
+	}
666
+
667
+	/**
668
+	 * Returns a "facet" service instance.
669
+	 *
670
+	 * @param string|FacetInterface $facetName
671
+	 * @return StandardFacet
672
+	 */
673
+	protected function instantiateStandardFacet($facetName)
674
+	{
675
+		$label = $this->getLabel($facetName);
676
+
677
+		/** @var StandardFacet $facetName */
678
+		$facet = GeneralUtility::makeInstance('Fab\Vidi\Facet\StandardFacet', $facetName, $label);
679
+
680
+		if (!$facet instanceof StandardFacet) {
681
+			throw new \RuntimeException('I could not instantiate a facet for facet name "' . (string)$facet . '""', 1445856345);
682
+		}
683
+		return $facet;
684
+	}
685
+
686
+	/**
687
+	 * Returns a "facet" service instance.
688
+	 *
689
+	 * @param string|FacetInterface $facetName
690
+	 * @return FacetInterface
691
+	 */
692
+	public function facet($facetName = '')
693
+	{
694
+		$facets = $this->getFacets();
695
+		return $facets[$facetName];
696
+	}
697
+
698
+	/**
699
+	 * @return \Fab\Vidi\Resolver\FieldPathResolver
700
+	 */
701
+	protected function getFieldPathResolver()
702
+	{
703
+		return GeneralUtility::makeInstance('Fab\Vidi\Resolver\FieldPathResolver');
704
+	}
705
+
706
+	/**
707
+	 * @return ModulePreferences
708
+	 */
709
+	protected function getModulePreferences()
710
+	{
711
+		return GeneralUtility::makeInstance('Fab\Vidi\Module\ModulePreferences');
712
+	}
713 713
 
714 714
 }
Please login to merge, or discard this patch.