Completed
Push — master ( a99a7b...23898a )
by Fabien
51:24
created
Classes/Language/LanguageService.php 2 patches
Doc Comments   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -97,7 +97,7 @@  discard block
 block discarded – undo
97 97
      *
98 98
      * @param Content $object
99 99
      * @param int $language
100
-     * @return string
100
+     * @return boolean
101 101
      */
102 102
     public function hasLocalization(Content $object, $language)
103 103
     {
@@ -178,7 +178,7 @@  discard block
 block discarded – undo
178 178
     }
179 179
 
180 180
     /**
181
-     * @return object|DataService
181
+     * @return DataService
182 182
      */
183 183
     protected function getDataService(): DataService
184 184
     {
Please login to merge, or discard this patch.
Indentation   +163 added lines, -163 removed lines patch added patch discarded remove patch
@@ -21,168 +21,168 @@
 block discarded – undo
21 21
 class LanguageService implements SingletonInterface
22 22
 {
23 23
 
24
-    /**
25
-     * @var array
26
-     */
27
-    protected $languages;
28
-
29
-    /**
30
-     * @var array
31
-     */
32
-    protected $defaultIcon;
33
-
34
-    /**
35
-     * Store the localized records to boost up performance.
36
-     *
37
-     * @var array
38
-     */
39
-    protected $localizedRecordStorage;
40
-
41
-    /**
42
-     * Returns available language records.
43
-     * The method stores the records in the property to speed up the process as the method can be often called.
44
-     *
45
-     * @return array
46
-     */
47
-    public function getLanguages()
48
-    {
49
-        if ($this->languages === null) {
50
-            $this->languages = $this->getDataService()->getRecords('sys_language');
51
-        }
52
-        return $this->languages;
53
-    }
54
-
55
-    /**
56
-     * Returns a localized record according to a Content object and a language identifier.
57
-     * Notice! This method does not overlay anything but simply returns the raw localized record.
58
-     *
59
-     * @param Content $object
60
-     * @param int $language
61
-     * @return Content
62
-     */
63
-    public function getLocalizedContent(Content $object, $language)
64
-    {
65
-
66
-        // We want to cache data per Content object. Retrieve the Object hash.
67
-        $objectHash = spl_object_hash($object);
68
-
69
-        // Initialize the storage
70
-        if (empty($this->localizedRecordStorage[$objectHash])) {
71
-            $this->localizedRecordStorage[$objectHash] = [];
72
-        }
73
-
74
-        if (empty($this->localizedRecordStorage[$objectHash][$language])) {
75
-
76
-            $localizedRecord = $this->getDataService()->getRecord(
77
-                $object->getDataType(),
78
-                [
79
-                    Tca::table($object)->getLanguageParentField() => $object->getUid(), // e.g. l10n_parent
80
-                    Tca::table($object)->getLanguageField() => $language, // e.g. sys_language_uid
81
-                ]
82
-            );
83
-
84
-            if ($localizedRecord) {
85
-                $localizedContent = GeneralUtility::makeInstance(\Fab\Vidi\Domain\Model\Content::class, $object->getDataType(), $localizedRecord);
86
-                $this->localizedRecordStorage[$objectHash][$language] = $localizedContent;
87
-            } else {
88
-                $this->localizedRecordStorage[$objectHash][$language] = []; // We want an array at least, even if empty.
89
-            }
90
-        }
91
-
92
-        return $this->localizedRecordStorage[$objectHash][$language];
93
-    }
94
-
95
-    /**
96
-     * Tell whether the given Content object has a localization.
97
-     *
98
-     * @param Content $object
99
-     * @param int $language
100
-     * @return string
101
-     */
102
-    public function hasLocalization(Content $object, $language)
103
-    {
104
-        $localizedRecord = $this->getLocalizedContent($object, $language);
105
-        return !empty($localizedRecord);
106
-    }
107
-
108
-    /**
109
-     * Returns a localized field according to a Content object and a language identifier.
110
-     * Notice! If there is not translation, simply returns an empty string.
111
-     *
112
-     * @param Content $object
113
-     * @param int $language
114
-     * @param string $fieldName
115
-     * @return string
116
-     */
117
-    public function getLocalizedFieldName(Content $object, $language, $fieldName)
118
-    {
119
-        $localizedRecord = $this->getLocalizedContent($object, $language);
120
-        return empty($localizedRecord) ? '' : $localizedRecord[$fieldName];
121
-    }
122
-
123
-    /**
124
-     * Returns the default language configured by TSConfig.
125
-     *
126
-     * @return array
127
-     */
128
-    public function getDefaultFlag()
129
-    {
130
-
131
-        if ($this->defaultIcon === null) {
132
-
133
-            $defaultFlag = ''; // default value
134
-
135
-            $tsConfig = \TYPO3\CMS\Backend\Utility\BackendUtility::getPagesTSconfig(0, 'mod.SHARED');
136
-
137
-            // Fallback non sprite-configuration
138
-            if (($pos = strrpos($tsConfig['properties']['defaultLanguageFlag'], '.')) !== false) {
139
-                $defaultFlag = substr($tsConfig['properties']['defaultLanguageFlag'], 0, $pos);
140
-            }
141
-
142
-            $this->defaultIcon = $defaultFlag;
143
-        }
144
-
145
-        return $this->defaultIcon;
146
-    }
147
-
148
-    /**
149
-     * Returns whether the system includes language records.
150
-     *
151
-     * @return bool
152
-     */
153
-    public function hasLanguages()
154
-    {
155
-        $languages = $this->getLanguages();
156
-        return !empty($languages);
157
-    }
158
-
159
-    /**
160
-     * Tell whether the given language exists.
161
-     *
162
-     * @param int $language
163
-     * @return bool
164
-     */
165
-    public function languageExists($language)
166
-    {
167
-        $languages = $this->getLanguages();
168
-
169
-        $LanguageExists = false;
170
-        foreach ($languages as $_language) {
171
-            if ((int)$_language['uid'] === (int)$language) {
172
-                $LanguageExists = true;
173
-                break;
174
-            }
175
-        }
176
-
177
-        return $LanguageExists;
178
-    }
179
-
180
-    /**
181
-     * @return object|DataService
182
-     */
183
-    protected function getDataService(): DataService
184
-    {
185
-        return GeneralUtility::makeInstance(DataService::class);
186
-    }
24
+	/**
25
+	 * @var array
26
+	 */
27
+	protected $languages;
28
+
29
+	/**
30
+	 * @var array
31
+	 */
32
+	protected $defaultIcon;
33
+
34
+	/**
35
+	 * Store the localized records to boost up performance.
36
+	 *
37
+	 * @var array
38
+	 */
39
+	protected $localizedRecordStorage;
40
+
41
+	/**
42
+	 * Returns available language records.
43
+	 * The method stores the records in the property to speed up the process as the method can be often called.
44
+	 *
45
+	 * @return array
46
+	 */
47
+	public function getLanguages()
48
+	{
49
+		if ($this->languages === null) {
50
+			$this->languages = $this->getDataService()->getRecords('sys_language');
51
+		}
52
+		return $this->languages;
53
+	}
54
+
55
+	/**
56
+	 * Returns a localized record according to a Content object and a language identifier.
57
+	 * Notice! This method does not overlay anything but simply returns the raw localized record.
58
+	 *
59
+	 * @param Content $object
60
+	 * @param int $language
61
+	 * @return Content
62
+	 */
63
+	public function getLocalizedContent(Content $object, $language)
64
+	{
65
+
66
+		// We want to cache data per Content object. Retrieve the Object hash.
67
+		$objectHash = spl_object_hash($object);
68
+
69
+		// Initialize the storage
70
+		if (empty($this->localizedRecordStorage[$objectHash])) {
71
+			$this->localizedRecordStorage[$objectHash] = [];
72
+		}
73
+
74
+		if (empty($this->localizedRecordStorage[$objectHash][$language])) {
75
+
76
+			$localizedRecord = $this->getDataService()->getRecord(
77
+				$object->getDataType(),
78
+				[
79
+					Tca::table($object)->getLanguageParentField() => $object->getUid(), // e.g. l10n_parent
80
+					Tca::table($object)->getLanguageField() => $language, // e.g. sys_language_uid
81
+				]
82
+			);
83
+
84
+			if ($localizedRecord) {
85
+				$localizedContent = GeneralUtility::makeInstance(\Fab\Vidi\Domain\Model\Content::class, $object->getDataType(), $localizedRecord);
86
+				$this->localizedRecordStorage[$objectHash][$language] = $localizedContent;
87
+			} else {
88
+				$this->localizedRecordStorage[$objectHash][$language] = []; // We want an array at least, even if empty.
89
+			}
90
+		}
91
+
92
+		return $this->localizedRecordStorage[$objectHash][$language];
93
+	}
94
+
95
+	/**
96
+	 * Tell whether the given Content object has a localization.
97
+	 *
98
+	 * @param Content $object
99
+	 * @param int $language
100
+	 * @return string
101
+	 */
102
+	public function hasLocalization(Content $object, $language)
103
+	{
104
+		$localizedRecord = $this->getLocalizedContent($object, $language);
105
+		return !empty($localizedRecord);
106
+	}
107
+
108
+	/**
109
+	 * Returns a localized field according to a Content object and a language identifier.
110
+	 * Notice! If there is not translation, simply returns an empty string.
111
+	 *
112
+	 * @param Content $object
113
+	 * @param int $language
114
+	 * @param string $fieldName
115
+	 * @return string
116
+	 */
117
+	public function getLocalizedFieldName(Content $object, $language, $fieldName)
118
+	{
119
+		$localizedRecord = $this->getLocalizedContent($object, $language);
120
+		return empty($localizedRecord) ? '' : $localizedRecord[$fieldName];
121
+	}
122
+
123
+	/**
124
+	 * Returns the default language configured by TSConfig.
125
+	 *
126
+	 * @return array
127
+	 */
128
+	public function getDefaultFlag()
129
+	{
130
+
131
+		if ($this->defaultIcon === null) {
132
+
133
+			$defaultFlag = ''; // default value
134
+
135
+			$tsConfig = \TYPO3\CMS\Backend\Utility\BackendUtility::getPagesTSconfig(0, 'mod.SHARED');
136
+
137
+			// Fallback non sprite-configuration
138
+			if (($pos = strrpos($tsConfig['properties']['defaultLanguageFlag'], '.')) !== false) {
139
+				$defaultFlag = substr($tsConfig['properties']['defaultLanguageFlag'], 0, $pos);
140
+			}
141
+
142
+			$this->defaultIcon = $defaultFlag;
143
+		}
144
+
145
+		return $this->defaultIcon;
146
+	}
147
+
148
+	/**
149
+	 * Returns whether the system includes language records.
150
+	 *
151
+	 * @return bool
152
+	 */
153
+	public function hasLanguages()
154
+	{
155
+		$languages = $this->getLanguages();
156
+		return !empty($languages);
157
+	}
158
+
159
+	/**
160
+	 * Tell whether the given language exists.
161
+	 *
162
+	 * @param int $language
163
+	 * @return bool
164
+	 */
165
+	public function languageExists($language)
166
+	{
167
+		$languages = $this->getLanguages();
168
+
169
+		$LanguageExists = false;
170
+		foreach ($languages as $_language) {
171
+			if ((int)$_language['uid'] === (int)$language) {
172
+				$LanguageExists = true;
173
+				break;
174
+			}
175
+		}
176
+
177
+		return $LanguageExists;
178
+	}
179
+
180
+	/**
181
+	 * @return object|DataService
182
+	 */
183
+	protected function getDataService(): DataService
184
+	{
185
+		return GeneralUtility::makeInstance(DataService::class);
186
+	}
187 187
 
188 188
 }
Please login to merge, or discard this patch.
Classes/Module/ModuleService.php 4 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -107,7 +107,7 @@
 block discarded – undo
107 107
     }
108 108
 
109 109
     /**
110
-     * @return DataService
110
+     * @return string
111 111
      */
112 112
     protected function getDataService(): string
113 113
     {
Please login to merge, or discard this patch.
Unused Use Statements   -1 removed lines patch added patch discarded remove patch
@@ -9,7 +9,6 @@
 block discarded – undo
9 9
  */
10 10
 
11 11
 use Fab\Vidi\Service\DataService;
12
-use Fab\Vidi\Utility\BackendUtility;
13 12
 use TYPO3\CMS\Core\SingletonInterface;
14 13
 use TYPO3\CMS\Core\Utility\GeneralUtility;
15 14
 use Fab\Vidi\Tca\Tca;
Please login to merge, or discard this patch.
Indentation   +93 added lines, -93 removed lines patch added patch discarded remove patch
@@ -21,106 +21,106 @@
 block discarded – undo
21 21
 class ModuleService implements SingletonInterface
22 22
 {
23 23
 
24
-    /**
25
-     * @var array
26
-     */
27
-    protected $storage = [];
24
+	/**
25
+	 * @var array
26
+	 */
27
+	protected $storage = [];
28 28
 
29
-    /**
30
-     * Returns a class instance
31
-     *
32
-     * @return \Fab\Vidi\Module\ModuleService|object
33
-     */
34
-    static public function getInstance()
35
-    {
36
-        return GeneralUtility::makeInstance(\Fab\Vidi\Module\ModuleService::class);
37
-    }
29
+	/**
30
+	 * Returns a class instance
31
+	 *
32
+	 * @return \Fab\Vidi\Module\ModuleService|object
33
+	 */
34
+	static public function getInstance()
35
+	{
36
+		return GeneralUtility::makeInstance(\Fab\Vidi\Module\ModuleService::class);
37
+	}
38 38
 
39
-    /**
40
-     * Fetch all modules to be displayed on the current pid.
41
-     *
42
-     * @return array
43
-     */
44
-    public function getModulesForCurrentPid(): array
45
-    {
46
-        $pid = $this->getModuleLoader()->getCurrentPid();
47
-        return $this->getModulesForPid($pid);
48
-    }
39
+	/**
40
+	 * Fetch all modules to be displayed on the current pid.
41
+	 *
42
+	 * @return array
43
+	 */
44
+	public function getModulesForCurrentPid(): array
45
+	{
46
+		$pid = $this->getModuleLoader()->getCurrentPid();
47
+		return $this->getModulesForPid($pid);
48
+	}
49 49
 
50
-    /**
51
-     * Fetch all modules displayed given a pid.
52
-     *
53
-     * @param int $pid
54
-     * @return array
55
-     */
56
-    public function getModulesForPid($pid = null): array
57
-    {
58
-        if (!isset($this->storage[$pid])) {
50
+	/**
51
+	 * Fetch all modules displayed given a pid.
52
+	 *
53
+	 * @param int $pid
54
+	 * @return array
55
+	 */
56
+	public function getModulesForPid($pid = null): array
57
+	{
58
+		if (!isset($this->storage[$pid])) {
59 59
 
60
-            $modules = [];
61
-            foreach ($GLOBALS['TCA'] as $dataType => $configuration) {
62
-                if (Tca::table($dataType)->isNotHidden()) {
63
-                    $record = $this->getDataService()->getRecord(
64
-                        $dataType,
65
-                        [
66
-                            'pid' => $pid
67
-                        ]
68
-                    );
69
-                    if (!empty($record)) {
70
-                        $moduleName = 'Vidi' . GeneralUtility::underscoredToUpperCamelCase($dataType) . 'M1';
71
-                        $title = Tca::table($dataType)->getTitle();
72
-                        $modules[$moduleName] = $title;
73
-                    }
74
-                }
75
-            }
76
-            $this->storage[$pid] = $modules;
77
-        }
78
-        return $this->storage[$pid];
79
-    }
60
+			$modules = [];
61
+			foreach ($GLOBALS['TCA'] as $dataType => $configuration) {
62
+				if (Tca::table($dataType)->isNotHidden()) {
63
+					$record = $this->getDataService()->getRecord(
64
+						$dataType,
65
+						[
66
+							'pid' => $pid
67
+						]
68
+					);
69
+					if (!empty($record)) {
70
+						$moduleName = 'Vidi' . GeneralUtility::underscoredToUpperCamelCase($dataType) . 'M1';
71
+						$title = Tca::table($dataType)->getTitle();
72
+						$modules[$moduleName] = $title;
73
+					}
74
+				}
75
+			}
76
+			$this->storage[$pid] = $modules;
77
+		}
78
+		return $this->storage[$pid];
79
+	}
80 80
 
81
-    /**
82
-     * Fetch the first module for the current pid.
83
-     *
84
-     * @return string
85
-     */
86
-    public function getFirstModuleForCurrentPid(): string
87
-    {
88
-        $pid = $this->getModuleLoader()->getCurrentPid();
89
-        return $this->getFirstModuleForPid($pid);
90
-    }
81
+	/**
82
+	 * Fetch the first module for the current pid.
83
+	 *
84
+	 * @return string
85
+	 */
86
+	public function getFirstModuleForCurrentPid(): string
87
+	{
88
+		$pid = $this->getModuleLoader()->getCurrentPid();
89
+		return $this->getFirstModuleForPid($pid);
90
+	}
91 91
 
92
-    /**
93
-     * Fetch the module given a pid.
94
-     *
95
-     * @param int $pid
96
-     * @return string
97
-     */
98
-    public function getFirstModuleForPid($pid): string
99
-    {
100
-        $firstModule = '';
101
-        $modules = $this->getModulesForPid($pid);
102
-        if (!empty($modules)) {
103
-            $firstModule = key($modules);
104
-        }
92
+	/**
93
+	 * Fetch the module given a pid.
94
+	 *
95
+	 * @param int $pid
96
+	 * @return string
97
+	 */
98
+	public function getFirstModuleForPid($pid): string
99
+	{
100
+		$firstModule = '';
101
+		$modules = $this->getModulesForPid($pid);
102
+		if (!empty($modules)) {
103
+			$firstModule = key($modules);
104
+		}
105 105
 
106
-        return $firstModule;
107
-    }
106
+		return $firstModule;
107
+	}
108 108
 
109
-    /**
110
-     * @return DataService
111
-     */
112
-    protected function getDataService(): string
113
-    {
114
-        return GeneralUtility::makeInstance(DataService::class);
115
-    }
109
+	/**
110
+	 * @return DataService
111
+	 */
112
+	protected function getDataService(): string
113
+	{
114
+		return GeneralUtility::makeInstance(DataService::class);
115
+	}
116 116
 
117
-    /**
118
-     * Get the Vidi Module Loader.
119
-     *
120
-     * @return \Fab\Vidi\Module\ModuleLoader|object
121
-     */
122
-    protected function getModuleLoader()
123
-    {
124
-        return GeneralUtility::makeInstance(\Fab\Vidi\Module\ModuleLoader::class);
125
-    }
117
+	/**
118
+	 * Get the Vidi Module Loader.
119
+	 *
120
+	 * @return \Fab\Vidi\Module\ModuleLoader|object
121
+	 */
122
+	protected function getModuleLoader()
123
+	{
124
+		return GeneralUtility::makeInstance(\Fab\Vidi\Module\ModuleLoader::class);
125
+	}
126 126
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -67,7 +67,7 @@
 block discarded – undo
67 67
                         ]
68 68
                     );
69 69
                     if (!empty($record)) {
70
-                        $moduleName = 'Vidi' . GeneralUtility::underscoredToUpperCamelCase($dataType) . 'M1';
70
+                        $moduleName = 'Vidi'.GeneralUtility::underscoredToUpperCamelCase($dataType).'M1';
71 71
                         $title = Tca::table($dataType)->getTitle();
72 72
                         $modules[$moduleName] = $title;
73 73
                     }
Please login to merge, or discard this patch.
Classes/Persistence/Query.php 2 patches
Doc Comments   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -379,7 +379,7 @@  discard block
 block discarded – undo
379 379
     /**
380 380
      * Gets the constraint for this query.
381 381
      *
382
-     * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ConstraintInterface the constraint, or null if none
382
+     * @return null|ConstraintInterface the constraint, or null if none
383 383
      * @api
384 384
      */
385 385
     public function getConstraint()
@@ -476,7 +476,7 @@  discard block
 block discarded – undo
476 476
      * Returns a like criterion used for matching objects against a query
477 477
      *
478 478
      * @param string $propertyName The name of the property to compare against
479
-     * @param mixed $operand The value to compare with
479
+     * @param string $operand The value to compare with
480 480
      * @param boolean $caseSensitive Whether the matching should be done case-sensitive
481 481
      * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
482 482
      * @api
Please login to merge, or discard this patch.
Indentation   +643 added lines, -643 removed lines patch added patch discarded remove patch
@@ -23,648 +23,648 @@
 block discarded – undo
23 23
 class Query implements QueryInterface
24 24
 {
25 25
 
26
-    /**
27
-     * An inner join.
28
-     */
29
-    const JCR_JOIN_TYPE_INNER = '{http://www.jcp.org/jcr/1.0}joinTypeInner';
30
-
31
-    /**
32
-     * A left-outer join.
33
-     */
34
-    const JCR_JOIN_TYPE_LEFT_OUTER = '{http://www.jcp.org/jcr/1.0}joinTypeLeftOuter';
35
-
36
-    /**
37
-     * A right-outer join.
38
-     */
39
-    const JCR_JOIN_TYPE_RIGHT_OUTER = '{http://www.jcp.org/jcr/1.0}joinTypeRightOuter';
40
-
41
-    /**
42
-     * Charset of strings in QOM
43
-     */
44
-    const CHARSET = 'utf-8';
45
-
46
-    /**
47
-     * @var string
48
-     */
49
-    protected $sourceFieldName;
50
-
51
-    /**
52
-     * @var string
53
-     */
54
-    protected $type;
55
-
56
-    /**
57
-     * @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
58
-     */
59
-    protected $objectManager;
60
-
61
-    /**
62
-     * @var \TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface
63
-     */
64
-    protected $persistenceManager;
65
-
66
-    /**
67
-     * @var \TYPO3\CMS\Extbase\Persistence\Generic\Qom\QueryObjectModelFactory
68
-     */
69
-    protected $qomFactory;
70
-
71
-    /**
72
-     * @var \TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInterface
73
-     */
74
-    protected $source;
75
-
76
-    /**
77
-     * @var ConstraintInterface
78
-     */
79
-    protected $constraint;
80
-
81
-    /**
82
-     * @var \TYPO3\CMS\Extbase\Persistence\Generic\Qom\Statement
83
-     */
84
-    protected $statement;
85
-
86
-    /**
87
-     * @var array
88
-     */
89
-    protected $orderings = [];
90
-
91
-    /**
92
-     * @var int
93
-     */
94
-    protected $limit;
95
-
96
-    /**
97
-     * @var int
98
-     */
99
-    protected $offset;
100
-
101
-    /**
102
-     * Apply DISTINCT upon property.
103
-     *
104
-     * @var string
105
-     */
106
-    protected $distinct;
107
-
108
-    /**
109
-     * The query settings.
110
-     *
111
-     * @var \Fab\Vidi\Persistence\QuerySettings
112
-     * @inject
113
-     */
114
-    protected $querySettings;
115
-
116
-    /**
117
-     * Constructs a query object working on the given class name
118
-     *
119
-     * @param string $type
120
-     */
121
-    public function __construct($type)
122
-    {
123
-        $this->type = $type;
124
-    }
125
-
126
-    /**
127
-     * @param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager
128
-     * @return void
129
-     */
130
-    public function injectObjectManager(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager)
131
-    {
132
-        $this->objectManager = $objectManager;
133
-    }
134
-
135
-    /**
136
-     * Injects the persistence manager, used to fetch the CR session
137
-     *
138
-     * @param \TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface $persistenceManager
139
-     * @return void
140
-     */
141
-    public function injectPersistenceManager(\TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface $persistenceManager)
142
-    {
143
-        $this->persistenceManager = $persistenceManager;
144
-    }
145
-
146
-    /**
147
-     * Injects the Query Object Model Factory
148
-     *
149
-     * @param \TYPO3\CMS\Extbase\Persistence\Generic\Qom\QueryObjectModelFactory $qomFactory
150
-     * @return void
151
-     */
152
-    public function injectQomFactory(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\QueryObjectModelFactory $qomFactory)
153
-    {
154
-        $this->qomFactory = $qomFactory;
155
-    }
156
-
157
-    /**
158
-     * Sets the Query Settings. These Query settings must match the settings expected by
159
-     * the specific Storage Backend.
160
-     *
161
-     * @param \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface $querySettings The Query Settings
162
-     * @return void
163
-     * @api This method is not part of FLOW3 API
164
-     */
165
-    public function setQuerySettings(\TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface $querySettings)
166
-    {
167
-        $this->querySettings = $querySettings;
168
-    }
169
-
170
-    /**
171
-     * Returns the Query Settings.
172
-     *
173
-     * @throws \Exception
174
-     * @return \Fab\Vidi\Persistence\QuerySettings $querySettings The Query Settings
175
-     * @api This method is not part of FLOW3 API
176
-     */
177
-    public function getQuerySettings()
178
-    {
179
-        if (!$this->querySettings instanceof \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface) {
180
-            throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception('Tried to get the query settings without setting them before.', 1248689115);
181
-        }
182
-
183
-        // Apply possible settings to the query.
184
-        if ($this->isBackendMode()) {
185
-            /** @var \TYPO3\CMS\Extbase\Configuration\BackendConfigurationManager $backendConfigurationManager */
186
-            $backendConfigurationManager = $this->objectManager->get('TYPO3\CMS\Extbase\Configuration\BackendConfigurationManager');
187
-            $configuration = $backendConfigurationManager->getTypoScriptSetup();
188
-            $querySettings = array('respectSysLanguage');
189
-            foreach ($querySettings as $setting) {
190
-                if (isset($configuration['config.']['tx_vidi.']['persistence.']['backend.'][$this->type . '.'][$setting])) {
191
-                    $value = (bool)$configuration['config.']['tx_vidi.']['persistence.']['backend.'][$this->type . '.'][$setting];
192
-                    ObjectAccess::setProperty($this->querySettings, $setting, $value);
193
-                }
194
-            }
195
-        }
196
-
197
-        return $this->querySettings;
198
-    }
199
-
200
-    /**
201
-     * Returns the type this query cares for.
202
-     *
203
-     * @return string
204
-     * @api
205
-     */
206
-    public function getType()
207
-    {
208
-        return $this->type;
209
-    }
210
-
211
-    /**
212
-     * Sets the source to fetch the result from
213
-     *
214
-     * @param \TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInterface $source
215
-     */
216
-    public function setSource(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInterface $source)
217
-    {
218
-        $this->source = $source;
219
-    }
220
-
221
-    /**
222
-     * Returns the selectorn name or an empty string, if the source is not a selector
223
-     * TODO This has to be checked at another place
224
-     *
225
-     * @return string The selector name
226
-     */
227
-    protected function getSelectorName()
228
-    {
229
-        if ($this->getSource() instanceof \TYPO3\CMS\Extbase\Persistence\Generic\Qom\SelectorInterface) {
230
-            return $this->source->getSelectorName();
231
-        } else {
232
-            return '';
233
-        }
234
-    }
235
-
236
-    /**
237
-     * Gets the node-tuple source for this query.
238
-     *
239
-     * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInterface the node-tuple source; non-null
240
-     */
241
-    public function getSource()
242
-    {
243
-        if ($this->source === null) {
244
-            $this->source = $this->qomFactory->selector($this->getType());
245
-        }
246
-        return $this->source;
247
-    }
248
-
249
-    /**
250
-     * Executes the query against the database and returns the result
251
-     *
252
-     * @return \TYPO3\CMS\Extbase\Persistence\QueryResultInterface|array The query result object or an array if $this->getQuerySettings()->getReturnRawQueryResult() is true
253
-     * @api
254
-     */
255
-    public function execute($returnRawQueryResult = false)
256
-    {
257
-        /** @var VidiDbBackend $backend */
258
-        $backend = $this->objectManager->get(VidiDbBackend::class, $this);
259
-        return $backend->fetchResult();
260
-    }
261
-
262
-    /**
263
-     * Sets the property names to order the result by. Expected like this:
264
-     * array(
265
-     * 'foo' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_ASCENDING,
266
-     * 'bar' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_DESCENDING
267
-     * )
268
-     * where 'foo' and 'bar' are property names.
269
-     *
270
-     * @param array $orderings The property names to order by
271
-     * @return QueryInterface
272
-     * @api
273
-     */
274
-    public function setOrderings(array $orderings)
275
-    {
276
-        $this->orderings = $orderings;
277
-        return $this;
278
-    }
279
-
280
-    /**
281
-     * Returns the property names to order the result by. Like this:
282
-     * array(
283
-     * 'foo' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_ASCENDING,
284
-     * 'bar' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_DESCENDING
285
-     * )
286
-     *
287
-     * @return array
288
-     */
289
-    public function getOrderings()
290
-    {
291
-        return $this->orderings;
292
-    }
293
-
294
-    /**
295
-     * Sets the maximum size of the result set to limit. Returns $this to allow
296
-     * for chaining (fluid interface)
297
-     *
298
-     * @param integer $limit
299
-     * @throws \InvalidArgumentException
300
-     * @return QueryInterface
301
-     * @api
302
-     */
303
-    public function setLimit($limit)
304
-    {
305
-        if (!is_int($limit) || $limit < 1) {
306
-            throw new \InvalidArgumentException('The limit must be an integer >= 1', 1245071870);
307
-        }
308
-        $this->limit = $limit;
309
-        return $this;
310
-    }
311
-
312
-    /**
313
-     * Resets a previously set maximum size of the result set. Returns $this to allow
314
-     * for chaining (fluid interface)
315
-     *
316
-     * @return QueryInterface
317
-     * @api
318
-     */
319
-    public function unsetLimit()
320
-    {
321
-        unset($this->limit);
322
-        return $this;
323
-    }
324
-
325
-    /**
326
-     * Returns the maximum size of the result set to limit.
327
-     *
328
-     * @return integer
329
-     * @api
330
-     */
331
-    public function getLimit()
332
-    {
333
-        return $this->limit;
334
-    }
335
-
336
-    /**
337
-     * Sets the start offset of the result set to offset. Returns $this to
338
-     * allow for chaining (fluid interface)
339
-     *
340
-     * @param integer $offset
341
-     * @throws \InvalidArgumentException
342
-     * @return QueryInterface
343
-     * @api
344
-     */
345
-    public function setOffset($offset)
346
-    {
347
-        if (!is_int($offset) || $offset < 0) {
348
-            throw new \InvalidArgumentException('The offset must be a positive integer', 1245071872);
349
-        }
350
-        $this->offset = $offset;
351
-        return $this;
352
-    }
353
-
354
-    /**
355
-     * Returns the start offset of the result set.
356
-     *
357
-     * @return integer
358
-     * @api
359
-     */
360
-    public function getOffset()
361
-    {
362
-        return $this->offset;
363
-    }
364
-
365
-    /**
366
-     * The constraint used to limit the result set. Returns $this to allow
367
-     * for chaining (fluid interface)
368
-     *
369
-     * @param ConstraintInterface $constraint
370
-     * @return QueryInterface
371
-     * @api
372
-     */
373
-    public function matching($constraint)
374
-    {
375
-        $this->constraint = $constraint;
376
-        return $this;
377
-    }
378
-
379
-    /**
380
-     * Gets the constraint for this query.
381
-     *
382
-     * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ConstraintInterface the constraint, or null if none
383
-     * @api
384
-     */
385
-    public function getConstraint()
386
-    {
387
-        return $this->constraint;
388
-    }
389
-
390
-    /**
391
-     * Performs a logical conjunction of the given constraints. The method takes one or more contraints and concatenates them with a boolean AND.
392
-     * It also scepts a single array of constraints to be concatenated.
393
-     *
394
-     * @param mixed $constraint1 The first of multiple constraints or an array of constraints.
395
-     * @throws InvalidNumberOfConstraintsException
396
-     * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\AndInterface
397
-     * @api
398
-     */
399
-    public function logicalAnd($constraint1)
400
-    {
401
-        if (is_array($constraint1)) {
402
-            $resultingConstraint = array_shift($constraint1);
403
-            $constraints = $constraint1;
404
-        } else {
405
-            $constraints = func_get_args();
406
-            $resultingConstraint = array_shift($constraints);
407
-        }
408
-        if ($resultingConstraint === null) {
409
-            throw new InvalidNumberOfConstraintsException('There must be at least one constraint or a non-empty array of constraints given.', 1401289500);
410
-        }
411
-        foreach ($constraints as $constraint) {
412
-            $resultingConstraint = $this->qomFactory->_and($resultingConstraint, $constraint);
413
-        }
414
-        return $resultingConstraint;
415
-    }
416
-
417
-    /**
418
-     * Performs a logical disjunction of the two given constraints
419
-     *
420
-     * @param mixed $constraint1 The first of multiple constraints or an array of constraints.
421
-     * @throws InvalidNumberOfConstraintsException
422
-     * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\OrInterface
423
-     * @api
424
-     */
425
-    public function logicalOr($constraint1)
426
-    {
427
-        if (is_array($constraint1)) {
428
-            $resultingConstraint = array_shift($constraint1);
429
-            $constraints = $constraint1;
430
-        } else {
431
-            $constraints = func_get_args();
432
-            $resultingConstraint = array_shift($constraints);
433
-        }
434
-        if ($resultingConstraint === null) {
435
-            throw new InvalidNumberOfConstraintsException('There must be at least one constraint or a non-empty array of constraints given.', 1401289501);
436
-        }
437
-        foreach ($constraints as $constraint) {
438
-            $resultingConstraint = $this->qomFactory->_or($resultingConstraint, $constraint);
439
-        }
440
-        return $resultingConstraint;
441
-    }
442
-
443
-    /**
444
-     * Performs a logical negation of the given constraint
445
-     *
446
-     * @param ConstraintInterface $constraint Constraint to negate
447
-     * @throws \RuntimeException
448
-     * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\NotInterface
449
-     * @api
450
-     */
451
-    public function logicalNot(ConstraintInterface $constraint)
452
-    {
453
-        return $this->qomFactory->not($constraint);
454
-    }
455
-
456
-    /**
457
-     * Returns an equals criterion used for matching objects against a query
458
-     *
459
-     * @param string $propertyName The name of the property to compare against
460
-     * @param mixed $operand The value to compare with
461
-     * @param boolean $caseSensitive Whether the equality test should be done case-sensitive
462
-     * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
463
-     * @api
464
-     */
465
-    public function equals($propertyName, $operand, $caseSensitive = true)
466
-    {
467
-        if (is_object($operand) || $caseSensitive) {
468
-            $comparison = $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_EQUAL_TO, $operand);
469
-        } else {
470
-            $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::class)->conv_case(\TYPO3\CMS\Extbase\Persistence\Generic\Query::CHARSET, $operand, 'toLower'));
471
-        }
472
-        return $comparison;
473
-    }
474
-
475
-    /**
476
-     * Returns a like criterion used for matching objects against a query
477
-     *
478
-     * @param string $propertyName The name of the property to compare against
479
-     * @param mixed $operand The value to compare with
480
-     * @param boolean $caseSensitive Whether the matching should be done case-sensitive
481
-     * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
482
-     * @api
483
-     */
484
-    public function like($propertyName, $operand, $caseSensitive = true)
485
-    {
486
-        return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_LIKE, $operand);
487
-    }
488
-
489
-    /**
490
-     * Returns a "contains" criterion used for matching objects against a query.
491
-     * It matches if the multivalued property contains the given operand.
492
-     *
493
-     * @param string $propertyName The name of the (multivalued) property to compare against
494
-     * @param mixed $operand The value to compare with
495
-     * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
496
-     * @api
497
-     */
498
-    public function contains($propertyName, $operand)
499
-    {
500
-        return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_CONTAINS, $operand);
501
-    }
502
-
503
-    /**
504
-     * Returns an "in" criterion used for matching objects against a query. It
505
-     * matches if the property's value is contained in the multivalued operand.
506
-     *
507
-     * @param string $propertyName The name of the property to compare against
508
-     * @param mixed $operand The value to compare with, multivalued
509
-     * @throws UnexpectedTypeException
510
-     * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
511
-     * @api
512
-     */
513
-    public function in($propertyName, $operand)
514
-    {
515
-        if (!is_array($operand) && !$operand instanceof \ArrayAccess && !$operand instanceof \Traversable) {
516
-            throw new UnexpectedTypeException('The "in" operator must be given a mutlivalued operand (array, ArrayAccess, Traversable).', 1264678095);
517
-        }
518
-        return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_IN, $operand);
519
-    }
520
-
521
-    /**
522
-     * Returns a less than criterion used for matching objects against a query
523
-     *
524
-     * @param string $propertyName The name of the property to compare against
525
-     * @param mixed $operand The value to compare with
526
-     * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
527
-     * @api
528
-     */
529
-    public function lessThan($propertyName, $operand)
530
-    {
531
-        return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_LESS_THAN, $operand);
532
-    }
533
-
534
-    /**
535
-     * Returns a less or equal than criterion used for matching objects against a query
536
-     *
537
-     * @param string $propertyName The name of the property to compare against
538
-     * @param mixed $operand The value to compare with
539
-     * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
540
-     * @api
541
-     */
542
-    public function lessThanOrEqual($propertyName, $operand)
543
-    {
544
-        return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_LESS_THAN_OR_EQUAL_TO, $operand);
545
-    }
546
-
547
-    /**
548
-     * Returns a greater than criterion used for matching objects against a query
549
-     *
550
-     * @param string $propertyName The name of the property to compare against
551
-     * @param mixed $operand The value to compare with
552
-     * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
553
-     * @api
554
-     */
555
-    public function greaterThan($propertyName, $operand)
556
-    {
557
-        return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_GREATER_THAN, $operand);
558
-    }
559
-
560
-    /**
561
-     * Returns a greater than or equal criterion used for matching objects against a query
562
-     *
563
-     * @param string $propertyName The name of the property to compare against
564
-     * @param mixed $operand The value to compare with
565
-     * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
566
-     * @api
567
-     */
568
-    public function greaterThanOrEqual($propertyName, $operand)
569
-    {
570
-        return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_GREATER_THAN_OR_EQUAL_TO, $operand);
571
-    }
572
-
573
-    /**
574
-     * Returns the query result count.
575
-     *
576
-     * @return integer The query result count
577
-     * @api
578
-     */
579
-    public function count()
580
-    {
581
-        /** @var VidiDbBackend $backend */
582
-        $backend = $this->objectManager->get(VidiDbBackend::class, $this);
583
-        return $backend->countResult();
584
-    }
585
-
586
-    /**
587
-     * Returns an "isEmpty" criterion used for matching objects against a query.
588
-     * It matches if the multivalued property contains no values or is null.
589
-     *
590
-     * @param string $propertyName The name of the multivalued property to compare against
591
-     * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\NotImplementedException
592
-     * @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException if used on a single-valued property
593
-     * @api
594
-     */
595
-    public function isEmpty($propertyName)
596
-    {
597
-        throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\NotImplementedException(__METHOD__);
598
-    }
599
-
600
-    /**
601
-     * @return string
602
-     */
603
-    public function getDistinct()
604
-    {
605
-        return $this->distinct;
606
-    }
607
-
608
-    /**
609
-     * @param string $distinct
610
-     * @return $this
611
-     */
612
-    public function setDistinct($distinct)
613
-    {
614
-        $this->distinct = $distinct;
615
-        return $this;
616
-    }
617
-
618
-    /**
619
-     * Sets the statement of this query. If you use this, you will lose the abstraction from a concrete storage
620
-     * backend (database).
621
-     *
622
-     * @param string|\TYPO3\CMS\Core\Database\PreparedStatement $statement The statement
623
-     * @param array $parameters An array of parameters. These will be bound to placeholders '?' in the $statement.
624
-     * @return QueryInterface
625
-     */
626
-    public function statement($statement, array $parameters = array())
627
-    {
628
-        $this->statement = $this->qomFactory->statement($statement, $parameters);
629
-        return $this;
630
-    }
631
-
632
-    /**
633
-     * Returns the statement of this query.
634
-     *
635
-     * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\Statement
636
-     */
637
-    public function getStatement()
638
-    {
639
-        return $this->statement;
640
-    }
641
-
642
-    /**
643
-     * Returns whether the current mode is Backend.
644
-     *
645
-     * @return bool
646
-     */
647
-    protected function isBackendMode()
648
-    {
649
-        return TYPO3_MODE == 'BE';
650
-    }
651
-
652
-    /**
653
-     * @return string
654
-     */
655
-    public function getSourceFieldName()
656
-    {
657
-        return $this->sourceFieldName;
658
-    }
659
-
660
-    /**
661
-     * @param string $sourceFieldName
662
-     * @return $this
663
-     */
664
-    public function setSourceFieldName($sourceFieldName)
665
-    {
666
-        $this->sourceFieldName = $sourceFieldName;
667
-        return $this;
668
-    }
26
+	/**
27
+	 * An inner join.
28
+	 */
29
+	const JCR_JOIN_TYPE_INNER = '{http://www.jcp.org/jcr/1.0}joinTypeInner';
30
+
31
+	/**
32
+	 * A left-outer join.
33
+	 */
34
+	const JCR_JOIN_TYPE_LEFT_OUTER = '{http://www.jcp.org/jcr/1.0}joinTypeLeftOuter';
35
+
36
+	/**
37
+	 * A right-outer join.
38
+	 */
39
+	const JCR_JOIN_TYPE_RIGHT_OUTER = '{http://www.jcp.org/jcr/1.0}joinTypeRightOuter';
40
+
41
+	/**
42
+	 * Charset of strings in QOM
43
+	 */
44
+	const CHARSET = 'utf-8';
45
+
46
+	/**
47
+	 * @var string
48
+	 */
49
+	protected $sourceFieldName;
50
+
51
+	/**
52
+	 * @var string
53
+	 */
54
+	protected $type;
55
+
56
+	/**
57
+	 * @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
58
+	 */
59
+	protected $objectManager;
60
+
61
+	/**
62
+	 * @var \TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface
63
+	 */
64
+	protected $persistenceManager;
65
+
66
+	/**
67
+	 * @var \TYPO3\CMS\Extbase\Persistence\Generic\Qom\QueryObjectModelFactory
68
+	 */
69
+	protected $qomFactory;
70
+
71
+	/**
72
+	 * @var \TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInterface
73
+	 */
74
+	protected $source;
75
+
76
+	/**
77
+	 * @var ConstraintInterface
78
+	 */
79
+	protected $constraint;
80
+
81
+	/**
82
+	 * @var \TYPO3\CMS\Extbase\Persistence\Generic\Qom\Statement
83
+	 */
84
+	protected $statement;
85
+
86
+	/**
87
+	 * @var array
88
+	 */
89
+	protected $orderings = [];
90
+
91
+	/**
92
+	 * @var int
93
+	 */
94
+	protected $limit;
95
+
96
+	/**
97
+	 * @var int
98
+	 */
99
+	protected $offset;
100
+
101
+	/**
102
+	 * Apply DISTINCT upon property.
103
+	 *
104
+	 * @var string
105
+	 */
106
+	protected $distinct;
107
+
108
+	/**
109
+	 * The query settings.
110
+	 *
111
+	 * @var \Fab\Vidi\Persistence\QuerySettings
112
+	 * @inject
113
+	 */
114
+	protected $querySettings;
115
+
116
+	/**
117
+	 * Constructs a query object working on the given class name
118
+	 *
119
+	 * @param string $type
120
+	 */
121
+	public function __construct($type)
122
+	{
123
+		$this->type = $type;
124
+	}
125
+
126
+	/**
127
+	 * @param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager
128
+	 * @return void
129
+	 */
130
+	public function injectObjectManager(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager)
131
+	{
132
+		$this->objectManager = $objectManager;
133
+	}
134
+
135
+	/**
136
+	 * Injects the persistence manager, used to fetch the CR session
137
+	 *
138
+	 * @param \TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface $persistenceManager
139
+	 * @return void
140
+	 */
141
+	public function injectPersistenceManager(\TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface $persistenceManager)
142
+	{
143
+		$this->persistenceManager = $persistenceManager;
144
+	}
145
+
146
+	/**
147
+	 * Injects the Query Object Model Factory
148
+	 *
149
+	 * @param \TYPO3\CMS\Extbase\Persistence\Generic\Qom\QueryObjectModelFactory $qomFactory
150
+	 * @return void
151
+	 */
152
+	public function injectQomFactory(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\QueryObjectModelFactory $qomFactory)
153
+	{
154
+		$this->qomFactory = $qomFactory;
155
+	}
156
+
157
+	/**
158
+	 * Sets the Query Settings. These Query settings must match the settings expected by
159
+	 * the specific Storage Backend.
160
+	 *
161
+	 * @param \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface $querySettings The Query Settings
162
+	 * @return void
163
+	 * @api This method is not part of FLOW3 API
164
+	 */
165
+	public function setQuerySettings(\TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface $querySettings)
166
+	{
167
+		$this->querySettings = $querySettings;
168
+	}
169
+
170
+	/**
171
+	 * Returns the Query Settings.
172
+	 *
173
+	 * @throws \Exception
174
+	 * @return \Fab\Vidi\Persistence\QuerySettings $querySettings The Query Settings
175
+	 * @api This method is not part of FLOW3 API
176
+	 */
177
+	public function getQuerySettings()
178
+	{
179
+		if (!$this->querySettings instanceof \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface) {
180
+			throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception('Tried to get the query settings without setting them before.', 1248689115);
181
+		}
182
+
183
+		// Apply possible settings to the query.
184
+		if ($this->isBackendMode()) {
185
+			/** @var \TYPO3\CMS\Extbase\Configuration\BackendConfigurationManager $backendConfigurationManager */
186
+			$backendConfigurationManager = $this->objectManager->get('TYPO3\CMS\Extbase\Configuration\BackendConfigurationManager');
187
+			$configuration = $backendConfigurationManager->getTypoScriptSetup();
188
+			$querySettings = array('respectSysLanguage');
189
+			foreach ($querySettings as $setting) {
190
+				if (isset($configuration['config.']['tx_vidi.']['persistence.']['backend.'][$this->type . '.'][$setting])) {
191
+					$value = (bool)$configuration['config.']['tx_vidi.']['persistence.']['backend.'][$this->type . '.'][$setting];
192
+					ObjectAccess::setProperty($this->querySettings, $setting, $value);
193
+				}
194
+			}
195
+		}
196
+
197
+		return $this->querySettings;
198
+	}
199
+
200
+	/**
201
+	 * Returns the type this query cares for.
202
+	 *
203
+	 * @return string
204
+	 * @api
205
+	 */
206
+	public function getType()
207
+	{
208
+		return $this->type;
209
+	}
210
+
211
+	/**
212
+	 * Sets the source to fetch the result from
213
+	 *
214
+	 * @param \TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInterface $source
215
+	 */
216
+	public function setSource(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInterface $source)
217
+	{
218
+		$this->source = $source;
219
+	}
220
+
221
+	/**
222
+	 * Returns the selectorn name or an empty string, if the source is not a selector
223
+	 * TODO This has to be checked at another place
224
+	 *
225
+	 * @return string The selector name
226
+	 */
227
+	protected function getSelectorName()
228
+	{
229
+		if ($this->getSource() instanceof \TYPO3\CMS\Extbase\Persistence\Generic\Qom\SelectorInterface) {
230
+			return $this->source->getSelectorName();
231
+		} else {
232
+			return '';
233
+		}
234
+	}
235
+
236
+	/**
237
+	 * Gets the node-tuple source for this query.
238
+	 *
239
+	 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInterface the node-tuple source; non-null
240
+	 */
241
+	public function getSource()
242
+	{
243
+		if ($this->source === null) {
244
+			$this->source = $this->qomFactory->selector($this->getType());
245
+		}
246
+		return $this->source;
247
+	}
248
+
249
+	/**
250
+	 * Executes the query against the database and returns the result
251
+	 *
252
+	 * @return \TYPO3\CMS\Extbase\Persistence\QueryResultInterface|array The query result object or an array if $this->getQuerySettings()->getReturnRawQueryResult() is true
253
+	 * @api
254
+	 */
255
+	public function execute($returnRawQueryResult = false)
256
+	{
257
+		/** @var VidiDbBackend $backend */
258
+		$backend = $this->objectManager->get(VidiDbBackend::class, $this);
259
+		return $backend->fetchResult();
260
+	}
261
+
262
+	/**
263
+	 * Sets the property names to order the result by. Expected like this:
264
+	 * array(
265
+	 * 'foo' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_ASCENDING,
266
+	 * 'bar' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_DESCENDING
267
+	 * )
268
+	 * where 'foo' and 'bar' are property names.
269
+	 *
270
+	 * @param array $orderings The property names to order by
271
+	 * @return QueryInterface
272
+	 * @api
273
+	 */
274
+	public function setOrderings(array $orderings)
275
+	{
276
+		$this->orderings = $orderings;
277
+		return $this;
278
+	}
279
+
280
+	/**
281
+	 * Returns the property names to order the result by. Like this:
282
+	 * array(
283
+	 * 'foo' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_ASCENDING,
284
+	 * 'bar' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_DESCENDING
285
+	 * )
286
+	 *
287
+	 * @return array
288
+	 */
289
+	public function getOrderings()
290
+	{
291
+		return $this->orderings;
292
+	}
293
+
294
+	/**
295
+	 * Sets the maximum size of the result set to limit. Returns $this to allow
296
+	 * for chaining (fluid interface)
297
+	 *
298
+	 * @param integer $limit
299
+	 * @throws \InvalidArgumentException
300
+	 * @return QueryInterface
301
+	 * @api
302
+	 */
303
+	public function setLimit($limit)
304
+	{
305
+		if (!is_int($limit) || $limit < 1) {
306
+			throw new \InvalidArgumentException('The limit must be an integer >= 1', 1245071870);
307
+		}
308
+		$this->limit = $limit;
309
+		return $this;
310
+	}
311
+
312
+	/**
313
+	 * Resets a previously set maximum size of the result set. Returns $this to allow
314
+	 * for chaining (fluid interface)
315
+	 *
316
+	 * @return QueryInterface
317
+	 * @api
318
+	 */
319
+	public function unsetLimit()
320
+	{
321
+		unset($this->limit);
322
+		return $this;
323
+	}
324
+
325
+	/**
326
+	 * Returns the maximum size of the result set to limit.
327
+	 *
328
+	 * @return integer
329
+	 * @api
330
+	 */
331
+	public function getLimit()
332
+	{
333
+		return $this->limit;
334
+	}
335
+
336
+	/**
337
+	 * Sets the start offset of the result set to offset. Returns $this to
338
+	 * allow for chaining (fluid interface)
339
+	 *
340
+	 * @param integer $offset
341
+	 * @throws \InvalidArgumentException
342
+	 * @return QueryInterface
343
+	 * @api
344
+	 */
345
+	public function setOffset($offset)
346
+	{
347
+		if (!is_int($offset) || $offset < 0) {
348
+			throw new \InvalidArgumentException('The offset must be a positive integer', 1245071872);
349
+		}
350
+		$this->offset = $offset;
351
+		return $this;
352
+	}
353
+
354
+	/**
355
+	 * Returns the start offset of the result set.
356
+	 *
357
+	 * @return integer
358
+	 * @api
359
+	 */
360
+	public function getOffset()
361
+	{
362
+		return $this->offset;
363
+	}
364
+
365
+	/**
366
+	 * The constraint used to limit the result set. Returns $this to allow
367
+	 * for chaining (fluid interface)
368
+	 *
369
+	 * @param ConstraintInterface $constraint
370
+	 * @return QueryInterface
371
+	 * @api
372
+	 */
373
+	public function matching($constraint)
374
+	{
375
+		$this->constraint = $constraint;
376
+		return $this;
377
+	}
378
+
379
+	/**
380
+	 * Gets the constraint for this query.
381
+	 *
382
+	 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ConstraintInterface the constraint, or null if none
383
+	 * @api
384
+	 */
385
+	public function getConstraint()
386
+	{
387
+		return $this->constraint;
388
+	}
389
+
390
+	/**
391
+	 * Performs a logical conjunction of the given constraints. The method takes one or more contraints and concatenates them with a boolean AND.
392
+	 * It also scepts a single array of constraints to be concatenated.
393
+	 *
394
+	 * @param mixed $constraint1 The first of multiple constraints or an array of constraints.
395
+	 * @throws InvalidNumberOfConstraintsException
396
+	 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\AndInterface
397
+	 * @api
398
+	 */
399
+	public function logicalAnd($constraint1)
400
+	{
401
+		if (is_array($constraint1)) {
402
+			$resultingConstraint = array_shift($constraint1);
403
+			$constraints = $constraint1;
404
+		} else {
405
+			$constraints = func_get_args();
406
+			$resultingConstraint = array_shift($constraints);
407
+		}
408
+		if ($resultingConstraint === null) {
409
+			throw new InvalidNumberOfConstraintsException('There must be at least one constraint or a non-empty array of constraints given.', 1401289500);
410
+		}
411
+		foreach ($constraints as $constraint) {
412
+			$resultingConstraint = $this->qomFactory->_and($resultingConstraint, $constraint);
413
+		}
414
+		return $resultingConstraint;
415
+	}
416
+
417
+	/**
418
+	 * Performs a logical disjunction of the two given constraints
419
+	 *
420
+	 * @param mixed $constraint1 The first of multiple constraints or an array of constraints.
421
+	 * @throws InvalidNumberOfConstraintsException
422
+	 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\OrInterface
423
+	 * @api
424
+	 */
425
+	public function logicalOr($constraint1)
426
+	{
427
+		if (is_array($constraint1)) {
428
+			$resultingConstraint = array_shift($constraint1);
429
+			$constraints = $constraint1;
430
+		} else {
431
+			$constraints = func_get_args();
432
+			$resultingConstraint = array_shift($constraints);
433
+		}
434
+		if ($resultingConstraint === null) {
435
+			throw new InvalidNumberOfConstraintsException('There must be at least one constraint or a non-empty array of constraints given.', 1401289501);
436
+		}
437
+		foreach ($constraints as $constraint) {
438
+			$resultingConstraint = $this->qomFactory->_or($resultingConstraint, $constraint);
439
+		}
440
+		return $resultingConstraint;
441
+	}
442
+
443
+	/**
444
+	 * Performs a logical negation of the given constraint
445
+	 *
446
+	 * @param ConstraintInterface $constraint Constraint to negate
447
+	 * @throws \RuntimeException
448
+	 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\NotInterface
449
+	 * @api
450
+	 */
451
+	public function logicalNot(ConstraintInterface $constraint)
452
+	{
453
+		return $this->qomFactory->not($constraint);
454
+	}
455
+
456
+	/**
457
+	 * Returns an equals criterion used for matching objects against a query
458
+	 *
459
+	 * @param string $propertyName The name of the property to compare against
460
+	 * @param mixed $operand The value to compare with
461
+	 * @param boolean $caseSensitive Whether the equality test should be done case-sensitive
462
+	 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
463
+	 * @api
464
+	 */
465
+	public function equals($propertyName, $operand, $caseSensitive = true)
466
+	{
467
+		if (is_object($operand) || $caseSensitive) {
468
+			$comparison = $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_EQUAL_TO, $operand);
469
+		} else {
470
+			$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::class)->conv_case(\TYPO3\CMS\Extbase\Persistence\Generic\Query::CHARSET, $operand, 'toLower'));
471
+		}
472
+		return $comparison;
473
+	}
474
+
475
+	/**
476
+	 * Returns a like criterion used for matching objects against a query
477
+	 *
478
+	 * @param string $propertyName The name of the property to compare against
479
+	 * @param mixed $operand The value to compare with
480
+	 * @param boolean $caseSensitive Whether the matching should be done case-sensitive
481
+	 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
482
+	 * @api
483
+	 */
484
+	public function like($propertyName, $operand, $caseSensitive = true)
485
+	{
486
+		return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_LIKE, $operand);
487
+	}
488
+
489
+	/**
490
+	 * Returns a "contains" criterion used for matching objects against a query.
491
+	 * It matches if the multivalued property contains the given operand.
492
+	 *
493
+	 * @param string $propertyName The name of the (multivalued) property to compare against
494
+	 * @param mixed $operand The value to compare with
495
+	 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
496
+	 * @api
497
+	 */
498
+	public function contains($propertyName, $operand)
499
+	{
500
+		return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_CONTAINS, $operand);
501
+	}
502
+
503
+	/**
504
+	 * Returns an "in" criterion used for matching objects against a query. It
505
+	 * matches if the property's value is contained in the multivalued operand.
506
+	 *
507
+	 * @param string $propertyName The name of the property to compare against
508
+	 * @param mixed $operand The value to compare with, multivalued
509
+	 * @throws UnexpectedTypeException
510
+	 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
511
+	 * @api
512
+	 */
513
+	public function in($propertyName, $operand)
514
+	{
515
+		if (!is_array($operand) && !$operand instanceof \ArrayAccess && !$operand instanceof \Traversable) {
516
+			throw new UnexpectedTypeException('The "in" operator must be given a mutlivalued operand (array, ArrayAccess, Traversable).', 1264678095);
517
+		}
518
+		return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_IN, $operand);
519
+	}
520
+
521
+	/**
522
+	 * Returns a less than criterion used for matching objects against a query
523
+	 *
524
+	 * @param string $propertyName The name of the property to compare against
525
+	 * @param mixed $operand The value to compare with
526
+	 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
527
+	 * @api
528
+	 */
529
+	public function lessThan($propertyName, $operand)
530
+	{
531
+		return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_LESS_THAN, $operand);
532
+	}
533
+
534
+	/**
535
+	 * Returns a less or equal than criterion used for matching objects against a query
536
+	 *
537
+	 * @param string $propertyName The name of the property to compare against
538
+	 * @param mixed $operand The value to compare with
539
+	 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
540
+	 * @api
541
+	 */
542
+	public function lessThanOrEqual($propertyName, $operand)
543
+	{
544
+		return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_LESS_THAN_OR_EQUAL_TO, $operand);
545
+	}
546
+
547
+	/**
548
+	 * Returns a greater than criterion used for matching objects against a query
549
+	 *
550
+	 * @param string $propertyName The name of the property to compare against
551
+	 * @param mixed $operand The value to compare with
552
+	 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
553
+	 * @api
554
+	 */
555
+	public function greaterThan($propertyName, $operand)
556
+	{
557
+		return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_GREATER_THAN, $operand);
558
+	}
559
+
560
+	/**
561
+	 * Returns a greater than or equal criterion used for matching objects against a query
562
+	 *
563
+	 * @param string $propertyName The name of the property to compare against
564
+	 * @param mixed $operand The value to compare with
565
+	 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface
566
+	 * @api
567
+	 */
568
+	public function greaterThanOrEqual($propertyName, $operand)
569
+	{
570
+		return $this->qomFactory->comparison($this->qomFactory->propertyValue($propertyName, $this->getSelectorName()), QueryInterface::OPERATOR_GREATER_THAN_OR_EQUAL_TO, $operand);
571
+	}
572
+
573
+	/**
574
+	 * Returns the query result count.
575
+	 *
576
+	 * @return integer The query result count
577
+	 * @api
578
+	 */
579
+	public function count()
580
+	{
581
+		/** @var VidiDbBackend $backend */
582
+		$backend = $this->objectManager->get(VidiDbBackend::class, $this);
583
+		return $backend->countResult();
584
+	}
585
+
586
+	/**
587
+	 * Returns an "isEmpty" criterion used for matching objects against a query.
588
+	 * It matches if the multivalued property contains no values or is null.
589
+	 *
590
+	 * @param string $propertyName The name of the multivalued property to compare against
591
+	 * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\NotImplementedException
592
+	 * @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException if used on a single-valued property
593
+	 * @api
594
+	 */
595
+	public function isEmpty($propertyName)
596
+	{
597
+		throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\NotImplementedException(__METHOD__);
598
+	}
599
+
600
+	/**
601
+	 * @return string
602
+	 */
603
+	public function getDistinct()
604
+	{
605
+		return $this->distinct;
606
+	}
607
+
608
+	/**
609
+	 * @param string $distinct
610
+	 * @return $this
611
+	 */
612
+	public function setDistinct($distinct)
613
+	{
614
+		$this->distinct = $distinct;
615
+		return $this;
616
+	}
617
+
618
+	/**
619
+	 * Sets the statement of this query. If you use this, you will lose the abstraction from a concrete storage
620
+	 * backend (database).
621
+	 *
622
+	 * @param string|\TYPO3\CMS\Core\Database\PreparedStatement $statement The statement
623
+	 * @param array $parameters An array of parameters. These will be bound to placeholders '?' in the $statement.
624
+	 * @return QueryInterface
625
+	 */
626
+	public function statement($statement, array $parameters = array())
627
+	{
628
+		$this->statement = $this->qomFactory->statement($statement, $parameters);
629
+		return $this;
630
+	}
631
+
632
+	/**
633
+	 * Returns the statement of this query.
634
+	 *
635
+	 * @return \TYPO3\CMS\Extbase\Persistence\Generic\Qom\Statement
636
+	 */
637
+	public function getStatement()
638
+	{
639
+		return $this->statement;
640
+	}
641
+
642
+	/**
643
+	 * Returns whether the current mode is Backend.
644
+	 *
645
+	 * @return bool
646
+	 */
647
+	protected function isBackendMode()
648
+	{
649
+		return TYPO3_MODE == 'BE';
650
+	}
651
+
652
+	/**
653
+	 * @return string
654
+	 */
655
+	public function getSourceFieldName()
656
+	{
657
+		return $this->sourceFieldName;
658
+	}
659
+
660
+	/**
661
+	 * @param string $sourceFieldName
662
+	 * @return $this
663
+	 */
664
+	public function setSourceFieldName($sourceFieldName)
665
+	{
666
+		$this->sourceFieldName = $sourceFieldName;
667
+		return $this;
668
+	}
669 669
 
670 670
 }
Please login to merge, or discard this patch.
Classes/Persistence/Storage/VidiDbBackend.php 3 patches
Doc Comments   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -645,7 +645,7 @@  discard block
 block discarded – undo
645 645
     /**
646 646
      * Adds additional WHERE statements according to the query settings.
647 647
      *
648
-     * @param QuerySettingsInterface $querySettings The TYPO3 CMS specific query settings
648
+     * @param \Fab\Vidi\Persistence\QuerySettings $querySettings The TYPO3 CMS specific query settings
649 649
      * @param string $tableNameOrAlias The table name to add the additional where clause for
650 650
      * @param array &$statementParts
651 651
      * @return void
@@ -873,7 +873,7 @@  discard block
 block discarded – undo
873 873
      * detected (depending on FE or BE context). You can also explicitly set the language/workspace id.
874 874
      *
875 875
      * @param array $row
876
-     * @param QuerySettingsInterface $querySettings The TYPO3 CMS specific query settings
876
+     * @param \Fab\Vidi\Persistence\QuerySettings $querySettings The TYPO3 CMS specific query settings
877 877
      * @return array
878 878
      */
879 879
     protected function doLanguageAndWorkspaceOverlay(array $row, $querySettings)
Please login to merge, or discard this patch.
Indentation   +1027 added lines, -1027 removed lines patch added patch discarded remove patch
@@ -37,1032 +37,1032 @@
 block discarded – undo
37 37
 class VidiDbBackend
38 38
 {
39 39
 
40
-    const OPERATOR_EQUAL_TO_NULL = 'operatorEqualToNull';
41
-    const OPERATOR_NOT_EQUAL_TO_NULL = 'operatorNotEqualToNull';
42
-
43
-    /**
44
-     * The TYPO3 page repository. Used for language and workspace overlay
45
-     *
46
-     * @var PageRepository
47
-     */
48
-    protected $pageRepository;
49
-
50
-    /**
51
-     * @var \TYPO3\CMS\Extbase\Service\EnvironmentService
52
-     * @inject
53
-     */
54
-    protected $environmentService;
55
-
56
-    /**
57
-     * @var \Fab\Vidi\Persistence\Query
58
-     */
59
-    protected $query;
60
-
61
-    /**
62
-     * Store some info related to table name and its aliases.
63
-     *
64
-     * @var array
65
-     */
66
-    protected $tableNameAliases = array(
67
-        'aliases' => [],
68
-        'aliasIncrement' => [],
69
-    );
70
-
71
-    /**
72
-     * Use to store the current foreign table name alias.
73
-     *
74
-     * @var string
75
-     */
76
-    protected $currentChildTableNameAlias = '';
77
-
78
-    /**
79
-     * @param Query $query
80
-     */
81
-    public function __construct(Query $query)
82
-    {
83
-        $this->query = $query;
84
-    }
85
-
86
-    /**
87
-     * Returns the result of the query
88
-     */
89
-    public function fetchResult()
90
-    {
91
-        $parameters = [];
92
-        $statementParts = $this->parseQuery($parameters);
93
-        $statementParts = $this->processStatementStructureForRecursiveMMRelation($statementParts);
94
-        $sql = $this->buildQuery($statementParts);
95
-        //print $sql; exit();
96
-
97
-        $rows = $this->getConnection()
98
-            ->executeQuery($sql, $parameters)
99
-            ->fetchAll();
100
-
101
-        return $this->getContentObjects($rows);
102
-    }
103
-
104
-    /**
105
-     * Returns the number of tuples matching the query.
106
-     *
107
-     * @return int The number of matching tuples
108
-     */
109
-    public function countResult()
110
-    {
111
-        $parameters = [];
112
-        $statementParts = $this->parseQuery($parameters);
113
-        $statementParts = $this->processStatementStructureForRecursiveMMRelation($statementParts);
114
-
115
-        // if limit is set, we need to count the rows "manually" as COUNT(*) ignores LIMIT constraints
116
-        if (!empty($statementParts['limit'])) {
117
-            $sql = $this->buildQuery($statementParts);
118
-
119
-            $count = $this
120
-                ->getConnection()
121
-                ->executeQuery($sql, $parameters)
122
-                ->rowCount();
123
-        } else {
124
-            $statementParts['fields'] = array('COUNT(*)');
125
-            // having orderings without grouping is not compatible with non-MySQL DBMS
126
-            $statementParts['orderings'] = [];
127
-            if (isset($statementParts['keywords']['distinct'])) {
128
-                unset($statementParts['keywords']['distinct']);
129
-                $distinctField = $this->query->getDistinct() ? $this->query->getDistinct() : 'uid';
130
-                $statementParts['fields'] = array('COUNT(DISTINCT ' . $statementParts['mainTable'] . '.' . $distinctField . ')');
131
-            }
132
-
133
-            $sql = $this->buildQuery($statementParts);
134
-            $count = $this
135
-                ->getConnection()
136
-                ->executeQuery($sql, $parameters)
137
-                ->fetchColumn(0);
138
-        }
139
-        return (int)$count;
140
-    }
141
-
142
-    /**
143
-     * Parses the query and returns the SQL statement parts.
144
-     *
145
-     * @param array &$parameters
146
-     * @return array
147
-     */
148
-    public function parseQuery(array &$parameters)
149
-    {
150
-        $statementParts = [];
151
-        $statementParts['keywords'] = [];
152
-        $statementParts['tables'] = [];
153
-        $statementParts['unions'] = [];
154
-        $statementParts['fields'] = [];
155
-        $statementParts['where'] = [];
156
-        $statementParts['additionalWhereClause'] = [];
157
-        $statementParts['orderings'] = [];
158
-        $statementParts['limit'] = [];
159
-        $query = $this->query;
160
-        $source = $query->getSource();
161
-        $this->parseSource($source, $statementParts);
162
-        $this->parseConstraint($query->getConstraint(), $source, $statementParts, $parameters);
163
-        $this->parseOrderings($query->getOrderings(), $source, $statementParts);
164
-        $this->parseLimitAndOffset($query->getLimit(), $query->getOffset(), $statementParts);
165
-        $tableNames = array_unique(array_keys($statementParts['tables'] + $statementParts['unions']));
166
-        foreach ($tableNames as $tableNameOrAlias) {
167
-            if (is_string($tableNameOrAlias) && strlen($tableNameOrAlias) > 0) {
168
-                $this->addAdditionalWhereClause($query->getQuerySettings(), $tableNameOrAlias, $statementParts);
169
-            }
170
-        }
171
-
172
-        return $statementParts;
173
-    }
174
-
175
-    /**
176
-     * Fiddle with the statement structure to handle recursive MM relations.
177
-     * For the recursive MM query to work, we must invert some values.
178
-     * Let see if that is the best way of doing that...
179
-     *
180
-     * @param array $statementParts
181
-     * @return array
182
-     */
183
-    public function processStatementStructureForRecursiveMMRelation(array $statementParts)
184
-    {
185
-
186
-        if ($this->hasRecursiveMMRelation()) {
187
-            $tableName = $this->query->getType();
188
-
189
-            // In order the MM query to work for a recursive MM query, we must invert some values.
190
-            // tx_domain_model_foo0 (the alias) <--> tx_domain_model_foo (the origin table name)
191
-            $values = [];
192
-            foreach ($statementParts['fields'] as $key => $value) {
193
-                $values[$key] = str_replace($tableName, $tableName . '0', $value);
194
-            }
195
-            $statementParts['fields'] = $values;
196
-
197
-            // Same comment as above.
198
-            $values = [];
199
-            foreach ($statementParts['where'] as $key => $value) {
200
-                $values[$key] = str_replace($tableName . '0', $tableName, $value);
201
-            }
202
-            $statementParts['where'] = $values;
203
-
204
-            // We must be more restrictive by transforming the "left" union by "inner"
205
-            $values = [];
206
-            foreach ($statementParts['unions'] as $key => $value) {
207
-                $values[$key] = str_replace('LEFT JOIN', 'INNER JOIN', $value);
208
-            }
209
-            $statementParts['unions'] = $values;
210
-        }
211
-
212
-        return $statementParts;
213
-    }
214
-
215
-    /**
216
-     * Tell whether there is a recursive MM relation.
217
-     *
218
-     * @return bool
219
-     */
220
-    public function hasRecursiveMMRelation()
221
-    {
222
-        return isset($this->tableNameAliases['aliasIncrement'][$this->query->getType()]);
223
-
224
-    }
225
-
226
-    /**
227
-     * Returns the statement, ready to be executed.
228
-     *
229
-     * @param array $statementParts The SQL statement parts
230
-     * @return string The SQL statement
231
-     */
232
-    public function buildQuery(array $statementParts)
233
-    {
234
-
235
-        // Add more statement to the UNION part.
236
-        if (!empty($statementParts['unions'])) {
237
-            foreach ($statementParts['unions'] as $tableName => $unionPart) {
238
-                if (!empty($statementParts['additionalWhereClause'][$tableName])) {
239
-                    $statementParts['unions'][$tableName] .= ' AND ' . implode(' AND ', $statementParts['additionalWhereClause'][$tableName]);
240
-                }
241
-            }
242
-        }
243
-
244
-        $statement = 'SELECT ' . implode(' ', $statementParts['keywords']) . ' ' . implode(',', $statementParts['fields']) . ' FROM ' . implode(' ', $statementParts['tables']) . ' ' . implode(' ', $statementParts['unions']);
245
-        if (!empty($statementParts['where'])) {
246
-            $statement .= ' WHERE ' . implode('', $statementParts['where']);
247
-            if (!empty($statementParts['additionalWhereClause'][$this->query->getType()])) {
248
-                $statement .= ' AND ' . implode(' AND ', $statementParts['additionalWhereClause'][$this->query->getType()]);
249
-            }
250
-        } elseif (!empty($statementParts['additionalWhereClause'])) {
251
-            $statement .= ' WHERE ' . implode(' AND ', $statementParts['additionalWhereClause'][$this->query->getType()]);
252
-        }
253
-        if (!empty($statementParts['orderings'])) {
254
-            $statement .= ' ORDER BY ' . implode(', ', $statementParts['orderings']);
255
-        }
256
-        if (!empty($statementParts['limit'])) {
257
-            $statement .= ' LIMIT ' . $statementParts['limit'];
258
-        }
259
-
260
-        return $statement;
261
-    }
262
-
263
-    /**
264
-     * Transforms a Query Source into SQL and parameter arrays
265
-     *
266
-     * @param SourceInterface $source The source
267
-     * @param array &$sql
268
-     * @return void
269
-     */
270
-    protected function parseSource(SourceInterface $source, array &$sql)
271
-    {
272
-        $tableName = $this->getTableName();
273
-        $sql['fields'][$tableName] = $tableName . '.*';
274
-        if ($this->query->getDistinct()) {
275
-            $sql['fields'][$tableName] = $tableName . '.' . $this->query->getDistinct();
276
-            $sql['keywords']['distinct'] = 'DISTINCT';
277
-        }
278
-        $sql['tables'][$tableName] = $tableName;
279
-        $sql['mainTable'] = $tableName;
280
-    }
281
-
282
-    /**
283
-     * Transforms a constraint into SQL and parameter arrays
284
-     *
285
-     * @param ConstraintInterface $constraint The constraint
286
-     * @param SourceInterface $source The source
287
-     * @param array &$statementParts The query parts
288
-     * @param array &$parameters The parameters that will replace the markers
289
-     * @return void
290
-     */
291
-    protected function parseConstraint(ConstraintInterface $constraint = null, SourceInterface $source, array &$statementParts, array &$parameters)
292
-    {
293
-        if ($constraint instanceof \TYPO3\CMS\Extbase\Persistence\Generic\Qom\AndInterface) {
294
-            $statementParts['where'][] = '(';
295
-            $this->parseConstraint($constraint->getConstraint1(), $source, $statementParts, $parameters);
296
-            $statementParts['where'][] = ' AND ';
297
-            $this->parseConstraint($constraint->getConstraint2(), $source, $statementParts, $parameters);
298
-            $statementParts['where'][] = ')';
299
-        } elseif ($constraint instanceof \TYPO3\CMS\Extbase\Persistence\Generic\Qom\OrInterface) {
300
-            $statementParts['where'][] = '(';
301
-            $this->parseConstraint($constraint->getConstraint1(), $source, $statementParts, $parameters);
302
-            $statementParts['where'][] = ' OR ';
303
-            $this->parseConstraint($constraint->getConstraint2(), $source, $statementParts, $parameters);
304
-            $statementParts['where'][] = ')';
305
-        } elseif ($constraint instanceof \TYPO3\CMS\Extbase\Persistence\Generic\Qom\NotInterface) {
306
-            $statementParts['where'][] = 'NOT (';
307
-            $this->parseConstraint($constraint->getConstraint(), $source, $statementParts, $parameters);
308
-            $statementParts['where'][] = ')';
309
-        } elseif ($constraint instanceof ComparisonInterface) {
310
-            $this->parseComparison($constraint, $source, $statementParts, $parameters);
311
-        }
312
-    }
313
-
314
-    /**
315
-     * Parse a Comparison into SQL and parameter arrays.
316
-     *
317
-     * @param ComparisonInterface $comparison The comparison to parse
318
-     * @param SourceInterface $source The source
319
-     * @param array &$statementParts SQL query parts to add to
320
-     * @param array &$parameters Parameters to bind to the SQL
321
-     * @return void
322
-     * @throws Exception\RepositoryException
323
-     */
324
-    protected function parseComparison(ComparisonInterface $comparison, SourceInterface $source, array &$statementParts, array &$parameters)
325
-    {
326
-        $operand1 = $comparison->getOperand1();
327
-        $operator = $comparison->getOperator();
328
-        $operand2 = $comparison->getOperand2();
329
-        if ($operator === QueryInterface::OPERATOR_IN) {
330
-            $items = [];
331
-            $hasValue = false;
332
-            foreach ($operand2 as $value) {
333
-                $value = $this->getPlainValue($value);
334
-                if ($value !== null) {
335
-                    $items[] = $value;
336
-                    $hasValue = true;
337
-                }
338
-            }
339
-            if ($hasValue === false) {
340
-                $statementParts['where'][] = '1<>1';
341
-            } else {
342
-                $this->parseDynamicOperand($operand1, $operator, $source, $statementParts, $parameters, null);
343
-                $parameters[] = $items;
344
-            }
345
-        } elseif ($operator === QueryInterface::OPERATOR_CONTAINS) {
346
-            if ($operand2 === null) {
347
-                $statementParts['where'][] = '1<>1';
348
-            } else {
349
-                throw new \Exception('Not implemented! Contact extension author.', 1412931227);
350
-                # @todo re-implement me if necessary.
351
-                #$tableName = $this->query->getType();
352
-                #$propertyName = $operand1->getPropertyName();
353
-                #while (strpos($propertyName, '.') !== false) {
354
-                #	$this->addUnionStatement($tableName, $propertyName, $statementParts);
355
-                #}
356
-                #$columnName = $propertyName;
357
-                #$columnMap = $propertyName;
358
-                #$typeOfRelation = $columnMap instanceof ColumnMap ? $columnMap->getTypeOfRelation() : null;
359
-                #if ($typeOfRelation === ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY) {
360
-                #	$relationTableName = $columnMap->getRelationTableName();
361
-                #	$statementParts['where'][] = $tableName . '.uid IN (SELECT ' . $columnMap->getParentKeyFieldName() . ' FROM ' . $relationTableName . ' WHERE ' . $columnMap->getChildKeyFieldName() . '=?)';
362
-                #	$parameters[] = intval($this->getPlainValue($operand2));
363
-                #} elseif ($typeOfRelation === ColumnMap::RELATION_HAS_MANY) {
364
-                #	$parentKeyFieldName = $columnMap->getParentKeyFieldName();
365
-                #	if (isset($parentKeyFieldName)) {
366
-                #		$childTableName = $columnMap->getChildTableName();
367
-                #		$statementParts['where'][] = $tableName . '.uid=(SELECT ' . $childTableName . '.' . $parentKeyFieldName . ' FROM ' . $childTableName . ' WHERE ' . $childTableName . '.uid=?)';
368
-                #		$parameters[] = intval($this->getPlainValue($operand2));
369
-                #	} else {
370
-                #		$statementParts['where'][] = 'FIND_IN_SET(?,' . $tableName . '.' . $columnName . ')';
371
-                #		$parameters[] = intval($this->getPlainValue($operand2));
372
-                #	}
373
-                #} else {
374
-                #	throw new Exception\RepositoryException('Unsupported or non-existing property name "' . $propertyName . '" used in relation matching.', 1327065745);
375
-                #}
376
-            }
377
-        } else {
378
-            if ($operand2 === null) {
379
-                if ($operator === QueryInterface::OPERATOR_EQUAL_TO) {
380
-                    $operator = self::OPERATOR_EQUAL_TO_NULL;
381
-                } elseif ($operator === QueryInterface::OPERATOR_NOT_EQUAL_TO) {
382
-                    $operator = self::OPERATOR_NOT_EQUAL_TO_NULL;
383
-                }
384
-            }
385
-            $this->parseDynamicOperand($operand1, $operator, $source, $statementParts, $parameters);
386
-            $parameters[] = $this->getPlainValue($operand2);
387
-        }
388
-    }
389
-
390
-    /**
391
-     * Returns a plain value, i.e. objects are flattened if possible.
392
-     *
393
-     * @param mixed $input
394
-     * @return mixed
395
-     * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\UnexpectedTypeException
396
-     */
397
-    protected function getPlainValue($input)
398
-    {
399
-        if (is_array($input)) {
400
-            throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\UnexpectedTypeException('An array could not be converted to a plain value.', 1274799932);
401
-        }
402
-        if ($input instanceof \DateTime) {
403
-            return $input->format('U');
404
-        } elseif (is_object($input)) {
405
-            if ($input instanceof \TYPO3\CMS\Extbase\Persistence\Generic\LazyLoadingProxy) {
406
-                $realInput = $input->_loadRealInstance();
407
-            } else {
408
-                $realInput = $input;
409
-            }
410
-            if ($realInput instanceof \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface) {
411
-                return $realInput->getUid();
412
-            } else {
413
-                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);
414
-            }
415
-        } elseif (is_bool($input)) {
416
-            return $input === true ? 1 : 0;
417
-        } else {
418
-            return $input;
419
-        }
420
-    }
421
-
422
-    /**
423
-     * Parse a DynamicOperand into SQL and parameter arrays.
424
-     *
425
-     * @param DynamicOperandInterface $operand
426
-     * @param string $operator One of the JCR_OPERATOR_* constants
427
-     * @param SourceInterface $source The source
428
-     * @param array &$statementParts The query parts
429
-     * @param array &$parameters The parameters that will replace the markers
430
-     * @param string $valueFunction an optional SQL function to apply to the operand value
431
-     * @return void
432
-     */
433
-    protected function parseDynamicOperand(DynamicOperandInterface $operand, $operator, SourceInterface $source, array &$statementParts, array &$parameters, $valueFunction = null)
434
-    {
435
-        if ($operand instanceof LowerCaseInterface) {
436
-            $this->parseDynamicOperand($operand->getOperand(), $operator, $source, $statementParts, $parameters, 'LOWER');
437
-        } elseif ($operand instanceof UpperCaseInterface) {
438
-            $this->parseDynamicOperand($operand->getOperand(), $operator, $source, $statementParts, $parameters, 'UPPER');
439
-        } elseif ($operand instanceof PropertyValueInterface) {
440
-            $propertyName = $operand->getPropertyName();
441
-
442
-            // Reset value.
443
-            $this->currentChildTableNameAlias = '';
444
-
445
-            if ($source instanceof SelectorInterface) {
446
-                $tableName = $this->query->getType();
447
-                while (strpos($propertyName, '.') !== false) {
448
-                    $this->addUnionStatement($tableName, $propertyName, $statementParts);
449
-                }
450
-            } elseif ($source instanceof JoinInterface) {
451
-                $tableName = $source->getJoinCondition()->getSelector1Name();
452
-            }
453
-
454
-            $columnName = $propertyName;
455
-            $resolvedOperator = $this->resolveOperator($operator);
456
-            $constraintSQL = '';
457
-
458
-            $marker = $operator === QueryInterface::OPERATOR_IN
459
-                ? '(?)'
460
-                : '?';
461
-
462
-            if ($valueFunction === null) {
463
-                $constraintSQL .= (!empty($tableName) ? $tableName . '.' : '') . $columnName . ' ' . $resolvedOperator . ' ' . $marker;
464
-            } else {
465
-                $constraintSQL .= $valueFunction . '(' . (!empty($tableName) ? $tableName . '.' : '') . $columnName . ') ' . $resolvedOperator . ' ' . $marker;
466
-            }
467
-
468
-            if (isset($tableName) && !empty($this->currentChildTableNameAlias)) {
469
-                $constraintSQL = $this->replaceTableNameByAlias($tableName, $this->currentChildTableNameAlias, $constraintSQL);
470
-            }
471
-            $statementParts['where'][] = $constraintSQL;
472
-        }
473
-    }
474
-
475
-    /**
476
-     * @param string &$tableName
477
-     * @param string &$propertyPath
478
-     * @param array &$statementParts
479
-     */
480
-    protected function addUnionStatement(&$tableName, &$propertyPath, array &$statementParts)
481
-    {
482
-
483
-        $table = Tca::table($tableName);
484
-
485
-        $explodedPropertyPath = explode('.', $propertyPath, 2);
486
-        $fieldName = $explodedPropertyPath[0];
487
-
488
-        // Field of type "group" are special because property path must contain the table name
489
-        // to determine the relation type. Example for sys_category, property path will look like "items.sys_file"
490
-        $parts = explode('.', $propertyPath, 3);
491
-        if ($table->field($fieldName)->isGroup() && count($parts) > 2) {
492
-            $explodedPropertyPath[0] = $parts[0] . '.' . $parts[1];
493
-            $explodedPropertyPath[1] = $parts[2];
494
-            $fieldName = $explodedPropertyPath[0];
495
-        }
496
-
497
-        $parentKeyFieldName = $table->field($fieldName)->getForeignField();
498
-        $childTableName = $table->field($fieldName)->getForeignTable();
499
-
500
-        if ($childTableName === null) {
501
-            throw new Exception\InvalidRelationConfigurationException('The relation information for property "' . $fieldName . '" of class "' . $tableName . '" is missing.', 1353170925);
502
-        }
503
-
504
-        if ($table->field($fieldName)->hasOne()) { // includes relation "one-to-one" and "many-to-one"
505
-            // sometimes the opposite relation is not defined. We don't want to force this config for backward compatibility reasons.
506
-            // $parentKeyFieldName === null does the trick somehow. Before condition was if (isset($parentKeyFieldName))
507
-            if ($table->field($fieldName)->hasRelationManyToOne() || $parentKeyFieldName === null) {
508
-                $statementParts['unions'][$childTableName] = 'LEFT JOIN ' . $childTableName . ' ON ' . $tableName . '.' . $fieldName . '=' . $childTableName . '.uid';
509
-            } else {
510
-                $statementParts['unions'][$childTableName] = 'LEFT JOIN ' . $childTableName . ' ON ' . $tableName . '.uid=' . $childTableName . '.' . $parentKeyFieldName;
511
-            }
512
-        } elseif ($table->field($fieldName)->hasRelationManyToMany()) {
513
-            $relationTableName = $table->field($fieldName)->getManyToManyTable();
514
-
515
-            $parentKeyFieldName = $table->field($fieldName)->isOppositeRelation() ? 'uid_foreign' : 'uid_local';
516
-            $childKeyFieldName = !$table->field($fieldName)->isOppositeRelation() ? 'uid_foreign' : 'uid_local';
517
-
518
-            // MM table e.g sys_category_record_mm
519
-            $relationTableNameAlias = $this->generateAlias($relationTableName);
520
-            $join = sprintf(
521
-                'LEFT JOIN %s AS %s ON %s.uid=%s.%s', $relationTableName,
522
-                $relationTableNameAlias,
523
-                $tableName,
524
-                $relationTableNameAlias,
525
-                $parentKeyFieldName
526
-            );
527
-            $statementParts['unions'][$relationTableNameAlias] = $join;
528
-
529
-            // Foreign table e.g sys_category
530
-            $childTableNameAlias = $this->generateAlias($childTableName);
531
-            $this->currentChildTableNameAlias = $childTableNameAlias;
532
-            $join = sprintf(
533
-                'LEFT JOIN %s AS %s ON %s.%s=%s.uid',
534
-                $childTableName,
535
-                $childTableNameAlias,
536
-                $relationTableNameAlias,
537
-                $childKeyFieldName,
538
-                $childTableNameAlias
539
-            );
540
-            $statementParts['unions'][$childTableNameAlias] = $join;
541
-
542
-            // Find a possible table name for a MM condition.
543
-            $tableNameCondition = $table->field($fieldName)->getAdditionalTableNameCondition();
544
-            if ($tableNameCondition) {
545
-
546
-                // If we can find a source file name,  we can then retrieve more MM conditions from the TCA such as a field name.
547
-                $sourceFileName = $this->query->getSourceFieldName();
548
-                if (empty($sourceFileName)) {
549
-                    $additionalMMConditions = array(
550
-                        'tablenames' => $tableNameCondition,
551
-                    );
552
-                } else {
553
-                    $additionalMMConditions = Tca::table($tableNameCondition)->field($sourceFileName)->getAdditionalMMCondition();
554
-                }
555
-
556
-                foreach ($additionalMMConditions as $additionalFieldName => $additionalMMCondition) {
557
-                    $additionalJoin = sprintf(' AND %s.%s = "%s"', $relationTableNameAlias, $additionalFieldName, $additionalMMCondition);
558
-                    $statementParts['unions'][$relationTableNameAlias] .= $additionalJoin;
559
-
560
-                    $additionalJoin = sprintf(' AND %s.%s = "%s"', $relationTableNameAlias, $additionalFieldName, $additionalMMCondition);
561
-                    $statementParts['unions'][$childTableNameAlias] .= $additionalJoin;
562
-                }
563
-            }
564
-
565
-        } elseif ($table->field($fieldName)->hasMany()) { // includes relations "many-to-one" and "csv" relations
566
-            $childTableNameAlias = $this->generateAlias($childTableName);
567
-            $this->currentChildTableNameAlias = $childTableNameAlias;
568
-
569
-            if (isset($parentKeyFieldName)) {
570
-                $join = sprintf(
571
-                    'LEFT JOIN %s AS %s ON %s.uid=%s.%s',
572
-                    $childTableName,
573
-                    $childTableNameAlias,
574
-                    $tableName,
575
-                    $childTableNameAlias,
576
-                    $parentKeyFieldName
577
-                );
578
-                $statementParts['unions'][$childTableNameAlias] = $join;
579
-            } else {
580
-                $join = sprintf(
581
-                    'LEFT JOIN %s AS %s ON (FIND_IN_SET(%s.uid, %s.%s))',
582
-                    $childTableName,
583
-                    $childTableNameAlias,
584
-                    $childTableNameAlias,
585
-                    $tableName,
586
-                    $fieldName
587
-                );
588
-                $statementParts['unions'][$childTableNameAlias] = $join;
589
-            }
590
-        } else {
591
-            throw new Exception('Could not determine type of relation.', 1252502725);
592
-        }
593
-
594
-        $statementParts['keywords']['distinct'] = 'DISTINCT';
595
-        $propertyPath = $explodedPropertyPath[1];
596
-        $tableName = $childTableName;
597
-    }
598
-
599
-    /**
600
-     * Returns the SQL operator for the given JCR operator type.
601
-     *
602
-     * @param string $operator One of the JCR_OPERATOR_* constants
603
-     * @return string an SQL operator
604
-     * @throws Exception
605
-     */
606
-    protected function resolveOperator($operator)
607
-    {
608
-        switch ($operator) {
609
-            case self::OPERATOR_EQUAL_TO_NULL:
610
-                $operator = 'IS';
611
-                break;
612
-            case self::OPERATOR_NOT_EQUAL_TO_NULL:
613
-                $operator = 'IS NOT';
614
-                break;
615
-            case QueryInterface::OPERATOR_IN:
616
-                $operator = 'IN';
617
-                break;
618
-            case QueryInterface::OPERATOR_EQUAL_TO:
619
-                $operator = '=';
620
-                break;
621
-            case QueryInterface::OPERATOR_NOT_EQUAL_TO:
622
-                $operator = '!=';
623
-                break;
624
-            case QueryInterface::OPERATOR_LESS_THAN:
625
-                $operator = '<';
626
-                break;
627
-            case QueryInterface::OPERATOR_LESS_THAN_OR_EQUAL_TO:
628
-                $operator = '<=';
629
-                break;
630
-            case QueryInterface::OPERATOR_GREATER_THAN:
631
-                $operator = '>';
632
-                break;
633
-            case QueryInterface::OPERATOR_GREATER_THAN_OR_EQUAL_TO:
634
-                $operator = '>=';
635
-                break;
636
-            case QueryInterface::OPERATOR_LIKE:
637
-                $operator = 'LIKE';
638
-                break;
639
-            default:
640
-                throw new Exception('Unsupported operator encountered.', 1242816073);
641
-        }
642
-        return $operator;
643
-    }
644
-
645
-    /**
646
-     * Adds additional WHERE statements according to the query settings.
647
-     *
648
-     * @param QuerySettingsInterface $querySettings The TYPO3 CMS specific query settings
649
-     * @param string $tableNameOrAlias The table name to add the additional where clause for
650
-     * @param array &$statementParts
651
-     * @return void
652
-     */
653
-    protected function addAdditionalWhereClause(QuerySettingsInterface $querySettings, $tableNameOrAlias, &$statementParts)
654
-    {
655
-        $this->addVisibilityConstraintStatement($querySettings, $tableNameOrAlias, $statementParts);
656
-        if ($querySettings->getRespectSysLanguage()) {
657
-            $this->addSysLanguageStatement($tableNameOrAlias, $statementParts, $querySettings);
658
-        }
659
-    }
660
-
661
-    /**
662
-     * Adds enableFields and deletedClause to the query if necessary
663
-     *
664
-     * @param QuerySettingsInterface $querySettings
665
-     * @param string $tableNameOrAlias The database table name
666
-     * @param array &$statementParts The query parts
667
-     * @return void
668
-     */
669
-    protected function addVisibilityConstraintStatement(QuerySettingsInterface $querySettings, $tableNameOrAlias, array &$statementParts)
670
-    {
671
-        $statement = '';
672
-        $tableName = $this->resolveTableNameAlias($tableNameOrAlias);
673
-        if (is_array($GLOBALS['TCA'][$tableName]['ctrl'])) {
674
-            $ignoreEnableFields = $querySettings->getIgnoreEnableFields();
675
-            $enableFieldsToBeIgnored = $querySettings->getEnableFieldsToBeIgnored();
676
-            $includeDeleted = $querySettings->getIncludeDeleted();
677
-            if ($this->environmentService->isEnvironmentInFrontendMode()) {
678
-                $statement .= $this->getFrontendConstraintStatement($tableNameOrAlias, $ignoreEnableFields, $enableFieldsToBeIgnored, $includeDeleted);
679
-            } else {
680
-                // TYPO3_MODE === 'BE'
681
-                $statement .= $this->getBackendConstraintStatement($tableNameOrAlias, $ignoreEnableFields, $includeDeleted);
682
-            }
683
-
684
-            // Remove the prefixing "AND" if any.
685
-            if (!empty($statement)) {
686
-                $statement = strtolower(substr($statement, 1, 3)) === 'and' ? substr($statement, 5) : $statement;
687
-                $statementParts['additionalWhereClause'][$tableNameOrAlias][] = $statement;
688
-            }
689
-        }
690
-    }
691
-
692
-    /**
693
-     * Returns constraint statement for frontend context
694
-     *
695
-     * @param string $tableNameOrAlias
696
-     * @param boolean $ignoreEnableFields A flag indicating whether the enable fields should be ignored
697
-     * @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.
698
-     * @param boolean $includeDeleted A flag indicating whether deleted records should be included
699
-     * @return string
700
-     * @throws Exception\InconsistentQuerySettingsException
701
-     */
702
-    protected function getFrontendConstraintStatement($tableNameOrAlias, $ignoreEnableFields, $enableFieldsToBeIgnored, $includeDeleted)
703
-    {
704
-        $statement = '';
705
-        $tableName = $this->resolveTableNameAlias($tableNameOrAlias);
706
-        if ($ignoreEnableFields && !$includeDeleted) {
707
-            if (count($enableFieldsToBeIgnored)) {
708
-                // array_combine() is necessary because of the way \TYPO3\CMS\Frontend\Page\PageRepository::enableFields() is implemented
709
-                $statement .= $this->getPageRepository()->enableFields($tableName, -1, array_combine($enableFieldsToBeIgnored, $enableFieldsToBeIgnored));
710
-            } else {
711
-                $statement .= $this->getPageRepository()->deleteClause($tableName);
712
-            }
713
-        } elseif (!$ignoreEnableFields && !$includeDeleted) {
714
-            $statement .= $this->getPageRepository()->enableFields($tableName);
715
-        } elseif (!$ignoreEnableFields && $includeDeleted) {
716
-            throw new Exception\InconsistentQuerySettingsException('Query setting "ignoreEnableFields=false" can not be used together with "includeDeleted=true" in frontend context.', 1327678173);
717
-        }
718
-        return $this->replaceTableNameByAlias($tableName, $tableNameOrAlias, $statement);
719
-    }
720
-
721
-    /**
722
-     * Returns constraint statement for backend context
723
-     *
724
-     * @param string $tableNameOrAlias
725
-     * @param boolean $ignoreEnableFields A flag indicating whether the enable fields should be ignored
726
-     * @param boolean $includeDeleted A flag indicating whether deleted records should be included
727
-     * @return string
728
-     */
729
-    protected function getBackendConstraintStatement($tableNameOrAlias, $ignoreEnableFields, $includeDeleted)
730
-    {
731
-        $tableName = $this->resolveTableNameAlias($tableNameOrAlias);
732
-        $statement = '';
733
-        if (!$ignoreEnableFields) {
734
-            $statement .= BackendUtility::BEenableFields($tableName);
735
-        }
736
-
737
-        // If the table is found to have "workspace" support, add the corresponding fields in the statement.
738
-        if (Tca::table($tableName)->hasWorkspaceSupport()) {
739
-            if ($this->getBackendUser()->workspace === 0) {
740
-                $statement .= ' AND ' . $tableName . '.t3ver_state<=' . new VersionState(VersionState::DEFAULT_STATE);
741
-            } else {
742
-                // Show only records of live and of the current workspace
743
-                // In case we are in a Versioning preview
744
-                $statement .= ' AND (' .
745
-                    $tableName . '.t3ver_wsid=0 OR ' .
746
-                    $tableName . '.t3ver_wsid=' . (int)$this->getBackendUser()->workspace .
747
-                    ')';
748
-            }
749
-
750
-            // Check if this segment make sense here or whether it should be in the "if" part when we have workspace = 0
751
-            $statement .= ' AND ' . $tableName . '.pid<>-1';
752
-        }
753
-
754
-        if (!$includeDeleted) {
755
-            $statement .= BackendUtility::deleteClause($tableName);
756
-        }
757
-
758
-        return $this->replaceTableNameByAlias($tableName, $tableNameOrAlias, $statement);
759
-    }
760
-
761
-    /**
762
-     * Builds the language field statement
763
-     *
764
-     * @param string $tableNameOrAlias The database table name
765
-     * @param array &$statementParts The query parts
766
-     * @param QuerySettingsInterface $querySettings The TYPO3 CMS specific query settings
767
-     * @return void
768
-     * @throws Exception
769
-     */
770
-    protected function addSysLanguageStatement($tableNameOrAlias, array &$statementParts, $querySettings)
771
-    {
772
-        $tableName = $this->resolveTableNameAlias($tableNameOrAlias);
773
-        if (is_array($GLOBALS['TCA'][$tableName]['ctrl'])) {
774
-            if (!empty($GLOBALS['TCA'][$tableName]['ctrl']['languageField'])) {
775
-                // Select all entries for the current language
776
-                $additionalWhereClause = $tableNameOrAlias . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] . ' IN (' . intval($querySettings->getLanguageUid()) . ',-1)';
777
-                // If any language is set -> get those entries which are not translated yet
778
-                // They will be removed by t3lib_page::getRecordOverlay if not matching overlay mode
779
-                if (isset($GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'])
780
-                    && $querySettings->getLanguageUid() > 0
781
-                ) {
782
-                    $additionalWhereClause .= ' OR (' . $tableNameOrAlias . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] . '=0' .
783
-                        ' AND ' . $tableNameOrAlias . '.uid NOT IN (SELECT ' . $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'] .
784
-                        ' FROM ' . $tableName .
785
-                        ' WHERE ' . $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'] . '>0' .
786
-                        ' AND ' . $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] . '>0';
787
-
788
-                    // Add delete clause to ensure all entries are loaded
789
-                    if (isset($GLOBALS['TCA'][$tableName]['ctrl']['delete'])) {
790
-                        $additionalWhereClause .= ' AND ' . $tableNameOrAlias . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['delete'] . '=0';
791
-                    }
792
-                    $additionalWhereClause .= '))';
793
-                }
794
-                $statementParts['additionalWhereClause'][$tableNameOrAlias][] = '(' . $additionalWhereClause . ')';
795
-            }
796
-        }
797
-    }
798
-
799
-    /**
800
-     * Transforms orderings into SQL.
801
-     *
802
-     * @param array $orderings An array of orderings (Tx_Extbase_Persistence_QOM_Ordering)
803
-     * @param SourceInterface $source The source
804
-     * @param array &$statementParts The query parts
805
-     * @return void
806
-     * @throws Exception\UnsupportedOrderException
807
-     */
808
-    protected function parseOrderings(array $orderings, SourceInterface $source, array &$statementParts)
809
-    {
810
-        foreach ($orderings as $fieldNameAndPath => $order) {
811
-            switch ($order) {
812
-                case QueryInterface::ORDER_ASCENDING:
813
-                    $order = 'ASC';
814
-                    break;
815
-                case QueryInterface::ORDER_DESCENDING:
816
-                    $order = 'DESC';
817
-                    break;
818
-                default:
819
-                    throw new Exception\UnsupportedOrderException('Unsupported order encountered.', 1456845126);
820
-            }
821
-
822
-            $tableName = $this->getFieldPathResolver()->getDataType($fieldNameAndPath, $this->query->getType());
823
-            $fieldName = $this->getFieldPathResolver()->stripFieldPath($fieldNameAndPath, $tableName);
824
-            $statementParts['orderings'][] = sprintf('%s.%s %s', $tableName, $fieldName, $order);
825
-        }
826
-    }
827
-
828
-    /**
829
-     * Transforms limit and offset into SQL
830
-     *
831
-     * @param int $limit
832
-     * @param int $offset
833
-     * @param array &$statementParts
834
-     * @return void
835
-     */
836
-    protected function parseLimitAndOffset($limit, $offset, array &$statementParts)
837
-    {
838
-        if ($limit !== null && $offset !== null) {
839
-            $statementParts['limit'] = intval($offset) . ', ' . intval($limit);
840
-        } elseif ($limit !== null) {
841
-            $statementParts['limit'] = intval($limit);
842
-        }
843
-    }
844
-
845
-    /**
846
-     * @param array $rows
847
-     * @return array
848
-     */
849
-    protected function getContentObjects(array $rows): array
850
-    {
851
-        $contentObjects = [];
852
-        foreach ($rows as $row) {
853
-
854
-            // Get language uid from querySettings.
855
-            // Ensure the backend handling is not broken (fallback to Get parameter 'L' if needed)
856
-            $overlaidRow = $this->doLanguageAndWorkspaceOverlay(
857
-                $row,
858
-                $this->query->getQuerySettings()
859
-            );
860
-
861
-            $contentObjects[] = GeneralUtility::makeInstance(
862
-                \Fab\Vidi\Domain\Model\Content::class,
863
-                $this->query->getType(),
864
-                $overlaidRow
865
-            );
866
-        }
867
-
868
-        return $contentObjects;
869
-    }
870
-
871
-    /**
872
-     * Performs workspace and language overlay on the given row array. The language and workspace id is automatically
873
-     * detected (depending on FE or BE context). You can also explicitly set the language/workspace id.
874
-     *
875
-     * @param array $row
876
-     * @param QuerySettingsInterface $querySettings The TYPO3 CMS specific query settings
877
-     * @return array
878
-     */
879
-    protected function doLanguageAndWorkspaceOverlay(array $row, $querySettings)
880
-    {
881
-        $tableName = $this->getTableName();
882
-
883
-        $pageRepository = $this->getPageRepository();
884
-        if (is_object($GLOBALS['TSFE'])) {
885
-            $languageMode = $GLOBALS['TSFE']->sys_language_mode;
886
-            if ($this->isBackendUserLogged() && $this->getBackendUser()->workspace !== 0) {
887
-                $pageRepository->versioningWorkspaceId = $this->getBackendUser()->workspace;
888
-            }
889
-        } else {
890
-            $languageMode = '';
891
-            $workspaceUid = $this->getBackendUser()->workspace;
892
-            $pageRepository->versioningWorkspaceId = $workspaceUid;
893
-            if ($this->getBackendUser()->workspace !== 0) {
894
-                $pageRepository->versioningPreview = 1;
895
-            }
896
-        }
897
-
898
-        // If current row is a translation select its parent
899
-        if (isset($GLOBALS['TCA'][$tableName]['ctrl']['languageField'])
900
-            && isset($GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'])
901
-        ) {
902
-            if (isset($row[$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']])
903
-                && $row[$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']] > 0
904
-            ) {
905
-                $queryBuilder = $this->getQueryBuilder();
906
-                $row = $queryBuilder
907
-                    ->select($tableName . '.*')
908
-                    ->from($tableName)
909
-                    ->andWhere(
910
-                        $tableName . '.uid=' . (int)$row[$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']],
911
-                        $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] . ' = 0'
912
-                    )
913
-                    ->execute()
914
-                    ->fetch();
915
-            }
916
-        }
917
-
918
-        // Retrieve the original uid; Used for Workspaces!
919
-        if (TYPO3_MODE !== 'BE') {
920
-            $pageRepository->versionOL($tableName, $row, true, true);
921
-        } else {
922
-            \TYPO3\CMS\Backend\Utility\BackendUtility::workspaceOL($tableName, $row);
923
-        }
924
-        if ($pageRepository->versioningPreview && isset($row['_ORIG_uid'])) {
925
-            $row['uid'] = $row['_ORIG_uid'];
926
-        }
927
-
928
-        // Special case for table "pages"
929
-        if ($tableName == 'pages') {
930
-            $row = $pageRepository->getPageOverlay($row, $querySettings->getLanguageUid());
931
-        } elseif (isset($GLOBALS['TCA'][$tableName]['ctrl']['languageField'])
932
-            && $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] !== ''
933
-        ) {
934
-            if (in_array($row[$GLOBALS['TCA'][$tableName]['ctrl']['languageField']], array(-1, 0))) {
935
-                $overlayMode = $languageMode === 'strict' ? 'hideNonTranslated' : '';
936
-                $row = $pageRepository->getRecordOverlay($tableName, $row, $querySettings->getLanguageUid(), $overlayMode);
937
-            }
938
-        }
939
-
940
-        return $row;
941
-    }
942
-
943
-    /**
944
-     * Return a resolved table name given a possible table name alias.
945
-     *
946
-     * @param string $tableNameOrAlias
947
-     * @return string
948
-     */
949
-    protected function resolveTableNameAlias($tableNameOrAlias)
950
-    {
951
-        $resolvedTableName = $tableNameOrAlias;
952
-        if (!empty($this->tableNameAliases['aliases'][$tableNameOrAlias])) {
953
-            $resolvedTableName = $this->tableNameAliases['aliases'][$tableNameOrAlias];
954
-        }
955
-        return $resolvedTableName;
956
-    }
957
-
958
-    /**
959
-     * Generate a unique table name alias for the given table name.
960
-     *
961
-     * @param string $tableName
962
-     * @return string
963
-     */
964
-    protected function generateAlias($tableName)
965
-    {
966
-
967
-        if (!isset($this->tableNameAliases['aliasIncrement'][$tableName])) {
968
-            $this->tableNameAliases['aliasIncrement'][$tableName] = 0;
969
-        }
970
-
971
-        $numberOfAliases = $this->tableNameAliases['aliasIncrement'][$tableName];
972
-        $tableNameAlias = $tableName . $numberOfAliases;
973
-
974
-        $this->tableNameAliases['aliasIncrement'][$tableName]++;
975
-        $this->tableNameAliases['aliases'][$tableNameAlias] = $tableName;
976
-
977
-        return $tableNameAlias;
978
-    }
979
-
980
-    /**
981
-     * Replace the table names by its table name alias within the given statement.
982
-     *
983
-     * @param string $tableName
984
-     * @param string $tableNameAlias
985
-     * @param string $statement
986
-     * @return string
987
-     */
988
-    protected function replaceTableNameByAlias($tableName, $tableNameAlias, $statement)
989
-    {
990
-        if ($statement && $tableName !== $tableNameAlias) {
991
-            $statement = str_replace($tableName, $tableNameAlias, $statement);
992
-        }
993
-        return $statement;
994
-    }
995
-
996
-    /**
997
-     * Returns an instance of the current Backend User.
998
-     *
999
-     * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
1000
-     */
1001
-    protected function getBackendUser()
1002
-    {
1003
-        return $GLOBALS['BE_USER'];
1004
-    }
1005
-
1006
-    /**
1007
-     * Tell whether a Backend User is logged in.
1008
-     *
1009
-     * @return bool
1010
-     */
1011
-    protected function isBackendUserLogged()
1012
-    {
1013
-        return is_object($GLOBALS['BE_USER']);
1014
-    }
1015
-
1016
-    /**
1017
-     * @return PageRepository|object
1018
-     */
1019
-    protected function getPageRepository()
1020
-    {
1021
-        if (!$this->pageRepository instanceof PageRepository) {
1022
-            if ($this->environmentService->isEnvironmentInFrontendMode() && is_object($GLOBALS['TSFE'])) {
1023
-                $this->pageRepository = $GLOBALS['TSFE']->sys_page;
1024
-            } else {
1025
-                $this->pageRepository = GeneralUtility::makeInstance(PageRepository::class);
1026
-            }
1027
-        }
1028
-
1029
-        return $this->pageRepository;
1030
-    }
1031
-
1032
-    /**
1033
-     * @return \Fab\Vidi\Resolver\FieldPathResolver|object
1034
-     */
1035
-    protected function getFieldPathResolver()
1036
-    {
1037
-        return GeneralUtility::makeInstance(\Fab\Vidi\Resolver\FieldPathResolver::class);
1038
-    }
1039
-
1040
-    /**
1041
-     * @return object|Connection
1042
-     */
1043
-    protected function getConnection(): Connection
1044
-    {
1045
-        /** @var ConnectionPool $connectionPool */
1046
-        return GeneralUtility::makeInstance(ConnectionPool::class)
1047
-            ->getConnectionForTable($this->getTableName());
1048
-    }
1049
-
1050
-    /**
1051
-     * @return object|QueryBuilder
1052
-     */
1053
-    protected function getQueryBuilder(): QueryBuilder
1054
-    {
1055
-        /** @var ConnectionPool $connectionPool */
1056
-        $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
1057
-        return $connectionPool->getQueryBuilderForTable($this->getTableName());
1058
-    }
1059
-
1060
-    /**
1061
-     * @return string
1062
-     */
1063
-    public function getTableName(): string
1064
-    {
1065
-        return $this->query->getSource()->getNodeTypeName(); // getSelectorName()
1066
-    }
40
+	const OPERATOR_EQUAL_TO_NULL = 'operatorEqualToNull';
41
+	const OPERATOR_NOT_EQUAL_TO_NULL = 'operatorNotEqualToNull';
42
+
43
+	/**
44
+	 * The TYPO3 page repository. Used for language and workspace overlay
45
+	 *
46
+	 * @var PageRepository
47
+	 */
48
+	protected $pageRepository;
49
+
50
+	/**
51
+	 * @var \TYPO3\CMS\Extbase\Service\EnvironmentService
52
+	 * @inject
53
+	 */
54
+	protected $environmentService;
55
+
56
+	/**
57
+	 * @var \Fab\Vidi\Persistence\Query
58
+	 */
59
+	protected $query;
60
+
61
+	/**
62
+	 * Store some info related to table name and its aliases.
63
+	 *
64
+	 * @var array
65
+	 */
66
+	protected $tableNameAliases = array(
67
+		'aliases' => [],
68
+		'aliasIncrement' => [],
69
+	);
70
+
71
+	/**
72
+	 * Use to store the current foreign table name alias.
73
+	 *
74
+	 * @var string
75
+	 */
76
+	protected $currentChildTableNameAlias = '';
77
+
78
+	/**
79
+	 * @param Query $query
80
+	 */
81
+	public function __construct(Query $query)
82
+	{
83
+		$this->query = $query;
84
+	}
85
+
86
+	/**
87
+	 * Returns the result of the query
88
+	 */
89
+	public function fetchResult()
90
+	{
91
+		$parameters = [];
92
+		$statementParts = $this->parseQuery($parameters);
93
+		$statementParts = $this->processStatementStructureForRecursiveMMRelation($statementParts);
94
+		$sql = $this->buildQuery($statementParts);
95
+		//print $sql; exit();
96
+
97
+		$rows = $this->getConnection()
98
+			->executeQuery($sql, $parameters)
99
+			->fetchAll();
100
+
101
+		return $this->getContentObjects($rows);
102
+	}
103
+
104
+	/**
105
+	 * Returns the number of tuples matching the query.
106
+	 *
107
+	 * @return int The number of matching tuples
108
+	 */
109
+	public function countResult()
110
+	{
111
+		$parameters = [];
112
+		$statementParts = $this->parseQuery($parameters);
113
+		$statementParts = $this->processStatementStructureForRecursiveMMRelation($statementParts);
114
+
115
+		// if limit is set, we need to count the rows "manually" as COUNT(*) ignores LIMIT constraints
116
+		if (!empty($statementParts['limit'])) {
117
+			$sql = $this->buildQuery($statementParts);
118
+
119
+			$count = $this
120
+				->getConnection()
121
+				->executeQuery($sql, $parameters)
122
+				->rowCount();
123
+		} else {
124
+			$statementParts['fields'] = array('COUNT(*)');
125
+			// having orderings without grouping is not compatible with non-MySQL DBMS
126
+			$statementParts['orderings'] = [];
127
+			if (isset($statementParts['keywords']['distinct'])) {
128
+				unset($statementParts['keywords']['distinct']);
129
+				$distinctField = $this->query->getDistinct() ? $this->query->getDistinct() : 'uid';
130
+				$statementParts['fields'] = array('COUNT(DISTINCT ' . $statementParts['mainTable'] . '.' . $distinctField . ')');
131
+			}
132
+
133
+			$sql = $this->buildQuery($statementParts);
134
+			$count = $this
135
+				->getConnection()
136
+				->executeQuery($sql, $parameters)
137
+				->fetchColumn(0);
138
+		}
139
+		return (int)$count;
140
+	}
141
+
142
+	/**
143
+	 * Parses the query and returns the SQL statement parts.
144
+	 *
145
+	 * @param array &$parameters
146
+	 * @return array
147
+	 */
148
+	public function parseQuery(array &$parameters)
149
+	{
150
+		$statementParts = [];
151
+		$statementParts['keywords'] = [];
152
+		$statementParts['tables'] = [];
153
+		$statementParts['unions'] = [];
154
+		$statementParts['fields'] = [];
155
+		$statementParts['where'] = [];
156
+		$statementParts['additionalWhereClause'] = [];
157
+		$statementParts['orderings'] = [];
158
+		$statementParts['limit'] = [];
159
+		$query = $this->query;
160
+		$source = $query->getSource();
161
+		$this->parseSource($source, $statementParts);
162
+		$this->parseConstraint($query->getConstraint(), $source, $statementParts, $parameters);
163
+		$this->parseOrderings($query->getOrderings(), $source, $statementParts);
164
+		$this->parseLimitAndOffset($query->getLimit(), $query->getOffset(), $statementParts);
165
+		$tableNames = array_unique(array_keys($statementParts['tables'] + $statementParts['unions']));
166
+		foreach ($tableNames as $tableNameOrAlias) {
167
+			if (is_string($tableNameOrAlias) && strlen($tableNameOrAlias) > 0) {
168
+				$this->addAdditionalWhereClause($query->getQuerySettings(), $tableNameOrAlias, $statementParts);
169
+			}
170
+		}
171
+
172
+		return $statementParts;
173
+	}
174
+
175
+	/**
176
+	 * Fiddle with the statement structure to handle recursive MM relations.
177
+	 * For the recursive MM query to work, we must invert some values.
178
+	 * Let see if that is the best way of doing that...
179
+	 *
180
+	 * @param array $statementParts
181
+	 * @return array
182
+	 */
183
+	public function processStatementStructureForRecursiveMMRelation(array $statementParts)
184
+	{
185
+
186
+		if ($this->hasRecursiveMMRelation()) {
187
+			$tableName = $this->query->getType();
188
+
189
+			// In order the MM query to work for a recursive MM query, we must invert some values.
190
+			// tx_domain_model_foo0 (the alias) <--> tx_domain_model_foo (the origin table name)
191
+			$values = [];
192
+			foreach ($statementParts['fields'] as $key => $value) {
193
+				$values[$key] = str_replace($tableName, $tableName . '0', $value);
194
+			}
195
+			$statementParts['fields'] = $values;
196
+
197
+			// Same comment as above.
198
+			$values = [];
199
+			foreach ($statementParts['where'] as $key => $value) {
200
+				$values[$key] = str_replace($tableName . '0', $tableName, $value);
201
+			}
202
+			$statementParts['where'] = $values;
203
+
204
+			// We must be more restrictive by transforming the "left" union by "inner"
205
+			$values = [];
206
+			foreach ($statementParts['unions'] as $key => $value) {
207
+				$values[$key] = str_replace('LEFT JOIN', 'INNER JOIN', $value);
208
+			}
209
+			$statementParts['unions'] = $values;
210
+		}
211
+
212
+		return $statementParts;
213
+	}
214
+
215
+	/**
216
+	 * Tell whether there is a recursive MM relation.
217
+	 *
218
+	 * @return bool
219
+	 */
220
+	public function hasRecursiveMMRelation()
221
+	{
222
+		return isset($this->tableNameAliases['aliasIncrement'][$this->query->getType()]);
223
+
224
+	}
225
+
226
+	/**
227
+	 * Returns the statement, ready to be executed.
228
+	 *
229
+	 * @param array $statementParts The SQL statement parts
230
+	 * @return string The SQL statement
231
+	 */
232
+	public function buildQuery(array $statementParts)
233
+	{
234
+
235
+		// Add more statement to the UNION part.
236
+		if (!empty($statementParts['unions'])) {
237
+			foreach ($statementParts['unions'] as $tableName => $unionPart) {
238
+				if (!empty($statementParts['additionalWhereClause'][$tableName])) {
239
+					$statementParts['unions'][$tableName] .= ' AND ' . implode(' AND ', $statementParts['additionalWhereClause'][$tableName]);
240
+				}
241
+			}
242
+		}
243
+
244
+		$statement = 'SELECT ' . implode(' ', $statementParts['keywords']) . ' ' . implode(',', $statementParts['fields']) . ' FROM ' . implode(' ', $statementParts['tables']) . ' ' . implode(' ', $statementParts['unions']);
245
+		if (!empty($statementParts['where'])) {
246
+			$statement .= ' WHERE ' . implode('', $statementParts['where']);
247
+			if (!empty($statementParts['additionalWhereClause'][$this->query->getType()])) {
248
+				$statement .= ' AND ' . implode(' AND ', $statementParts['additionalWhereClause'][$this->query->getType()]);
249
+			}
250
+		} elseif (!empty($statementParts['additionalWhereClause'])) {
251
+			$statement .= ' WHERE ' . implode(' AND ', $statementParts['additionalWhereClause'][$this->query->getType()]);
252
+		}
253
+		if (!empty($statementParts['orderings'])) {
254
+			$statement .= ' ORDER BY ' . implode(', ', $statementParts['orderings']);
255
+		}
256
+		if (!empty($statementParts['limit'])) {
257
+			$statement .= ' LIMIT ' . $statementParts['limit'];
258
+		}
259
+
260
+		return $statement;
261
+	}
262
+
263
+	/**
264
+	 * Transforms a Query Source into SQL and parameter arrays
265
+	 *
266
+	 * @param SourceInterface $source The source
267
+	 * @param array &$sql
268
+	 * @return void
269
+	 */
270
+	protected function parseSource(SourceInterface $source, array &$sql)
271
+	{
272
+		$tableName = $this->getTableName();
273
+		$sql['fields'][$tableName] = $tableName . '.*';
274
+		if ($this->query->getDistinct()) {
275
+			$sql['fields'][$tableName] = $tableName . '.' . $this->query->getDistinct();
276
+			$sql['keywords']['distinct'] = 'DISTINCT';
277
+		}
278
+		$sql['tables'][$tableName] = $tableName;
279
+		$sql['mainTable'] = $tableName;
280
+	}
281
+
282
+	/**
283
+	 * Transforms a constraint into SQL and parameter arrays
284
+	 *
285
+	 * @param ConstraintInterface $constraint The constraint
286
+	 * @param SourceInterface $source The source
287
+	 * @param array &$statementParts The query parts
288
+	 * @param array &$parameters The parameters that will replace the markers
289
+	 * @return void
290
+	 */
291
+	protected function parseConstraint(ConstraintInterface $constraint = null, SourceInterface $source, array &$statementParts, array &$parameters)
292
+	{
293
+		if ($constraint instanceof \TYPO3\CMS\Extbase\Persistence\Generic\Qom\AndInterface) {
294
+			$statementParts['where'][] = '(';
295
+			$this->parseConstraint($constraint->getConstraint1(), $source, $statementParts, $parameters);
296
+			$statementParts['where'][] = ' AND ';
297
+			$this->parseConstraint($constraint->getConstraint2(), $source, $statementParts, $parameters);
298
+			$statementParts['where'][] = ')';
299
+		} elseif ($constraint instanceof \TYPO3\CMS\Extbase\Persistence\Generic\Qom\OrInterface) {
300
+			$statementParts['where'][] = '(';
301
+			$this->parseConstraint($constraint->getConstraint1(), $source, $statementParts, $parameters);
302
+			$statementParts['where'][] = ' OR ';
303
+			$this->parseConstraint($constraint->getConstraint2(), $source, $statementParts, $parameters);
304
+			$statementParts['where'][] = ')';
305
+		} elseif ($constraint instanceof \TYPO3\CMS\Extbase\Persistence\Generic\Qom\NotInterface) {
306
+			$statementParts['where'][] = 'NOT (';
307
+			$this->parseConstraint($constraint->getConstraint(), $source, $statementParts, $parameters);
308
+			$statementParts['where'][] = ')';
309
+		} elseif ($constraint instanceof ComparisonInterface) {
310
+			$this->parseComparison($constraint, $source, $statementParts, $parameters);
311
+		}
312
+	}
313
+
314
+	/**
315
+	 * Parse a Comparison into SQL and parameter arrays.
316
+	 *
317
+	 * @param ComparisonInterface $comparison The comparison to parse
318
+	 * @param SourceInterface $source The source
319
+	 * @param array &$statementParts SQL query parts to add to
320
+	 * @param array &$parameters Parameters to bind to the SQL
321
+	 * @return void
322
+	 * @throws Exception\RepositoryException
323
+	 */
324
+	protected function parseComparison(ComparisonInterface $comparison, SourceInterface $source, array &$statementParts, array &$parameters)
325
+	{
326
+		$operand1 = $comparison->getOperand1();
327
+		$operator = $comparison->getOperator();
328
+		$operand2 = $comparison->getOperand2();
329
+		if ($operator === QueryInterface::OPERATOR_IN) {
330
+			$items = [];
331
+			$hasValue = false;
332
+			foreach ($operand2 as $value) {
333
+				$value = $this->getPlainValue($value);
334
+				if ($value !== null) {
335
+					$items[] = $value;
336
+					$hasValue = true;
337
+				}
338
+			}
339
+			if ($hasValue === false) {
340
+				$statementParts['where'][] = '1<>1';
341
+			} else {
342
+				$this->parseDynamicOperand($operand1, $operator, $source, $statementParts, $parameters, null);
343
+				$parameters[] = $items;
344
+			}
345
+		} elseif ($operator === QueryInterface::OPERATOR_CONTAINS) {
346
+			if ($operand2 === null) {
347
+				$statementParts['where'][] = '1<>1';
348
+			} else {
349
+				throw new \Exception('Not implemented! Contact extension author.', 1412931227);
350
+				# @todo re-implement me if necessary.
351
+				#$tableName = $this->query->getType();
352
+				#$propertyName = $operand1->getPropertyName();
353
+				#while (strpos($propertyName, '.') !== false) {
354
+				#	$this->addUnionStatement($tableName, $propertyName, $statementParts);
355
+				#}
356
+				#$columnName = $propertyName;
357
+				#$columnMap = $propertyName;
358
+				#$typeOfRelation = $columnMap instanceof ColumnMap ? $columnMap->getTypeOfRelation() : null;
359
+				#if ($typeOfRelation === ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY) {
360
+				#	$relationTableName = $columnMap->getRelationTableName();
361
+				#	$statementParts['where'][] = $tableName . '.uid IN (SELECT ' . $columnMap->getParentKeyFieldName() . ' FROM ' . $relationTableName . ' WHERE ' . $columnMap->getChildKeyFieldName() . '=?)';
362
+				#	$parameters[] = intval($this->getPlainValue($operand2));
363
+				#} elseif ($typeOfRelation === ColumnMap::RELATION_HAS_MANY) {
364
+				#	$parentKeyFieldName = $columnMap->getParentKeyFieldName();
365
+				#	if (isset($parentKeyFieldName)) {
366
+				#		$childTableName = $columnMap->getChildTableName();
367
+				#		$statementParts['where'][] = $tableName . '.uid=(SELECT ' . $childTableName . '.' . $parentKeyFieldName . ' FROM ' . $childTableName . ' WHERE ' . $childTableName . '.uid=?)';
368
+				#		$parameters[] = intval($this->getPlainValue($operand2));
369
+				#	} else {
370
+				#		$statementParts['where'][] = 'FIND_IN_SET(?,' . $tableName . '.' . $columnName . ')';
371
+				#		$parameters[] = intval($this->getPlainValue($operand2));
372
+				#	}
373
+				#} else {
374
+				#	throw new Exception\RepositoryException('Unsupported or non-existing property name "' . $propertyName . '" used in relation matching.', 1327065745);
375
+				#}
376
+			}
377
+		} else {
378
+			if ($operand2 === null) {
379
+				if ($operator === QueryInterface::OPERATOR_EQUAL_TO) {
380
+					$operator = self::OPERATOR_EQUAL_TO_NULL;
381
+				} elseif ($operator === QueryInterface::OPERATOR_NOT_EQUAL_TO) {
382
+					$operator = self::OPERATOR_NOT_EQUAL_TO_NULL;
383
+				}
384
+			}
385
+			$this->parseDynamicOperand($operand1, $operator, $source, $statementParts, $parameters);
386
+			$parameters[] = $this->getPlainValue($operand2);
387
+		}
388
+	}
389
+
390
+	/**
391
+	 * Returns a plain value, i.e. objects are flattened if possible.
392
+	 *
393
+	 * @param mixed $input
394
+	 * @return mixed
395
+	 * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\UnexpectedTypeException
396
+	 */
397
+	protected function getPlainValue($input)
398
+	{
399
+		if (is_array($input)) {
400
+			throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\UnexpectedTypeException('An array could not be converted to a plain value.', 1274799932);
401
+		}
402
+		if ($input instanceof \DateTime) {
403
+			return $input->format('U');
404
+		} elseif (is_object($input)) {
405
+			if ($input instanceof \TYPO3\CMS\Extbase\Persistence\Generic\LazyLoadingProxy) {
406
+				$realInput = $input->_loadRealInstance();
407
+			} else {
408
+				$realInput = $input;
409
+			}
410
+			if ($realInput instanceof \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface) {
411
+				return $realInput->getUid();
412
+			} else {
413
+				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);
414
+			}
415
+		} elseif (is_bool($input)) {
416
+			return $input === true ? 1 : 0;
417
+		} else {
418
+			return $input;
419
+		}
420
+	}
421
+
422
+	/**
423
+	 * Parse a DynamicOperand into SQL and parameter arrays.
424
+	 *
425
+	 * @param DynamicOperandInterface $operand
426
+	 * @param string $operator One of the JCR_OPERATOR_* constants
427
+	 * @param SourceInterface $source The source
428
+	 * @param array &$statementParts The query parts
429
+	 * @param array &$parameters The parameters that will replace the markers
430
+	 * @param string $valueFunction an optional SQL function to apply to the operand value
431
+	 * @return void
432
+	 */
433
+	protected function parseDynamicOperand(DynamicOperandInterface $operand, $operator, SourceInterface $source, array &$statementParts, array &$parameters, $valueFunction = null)
434
+	{
435
+		if ($operand instanceof LowerCaseInterface) {
436
+			$this->parseDynamicOperand($operand->getOperand(), $operator, $source, $statementParts, $parameters, 'LOWER');
437
+		} elseif ($operand instanceof UpperCaseInterface) {
438
+			$this->parseDynamicOperand($operand->getOperand(), $operator, $source, $statementParts, $parameters, 'UPPER');
439
+		} elseif ($operand instanceof PropertyValueInterface) {
440
+			$propertyName = $operand->getPropertyName();
441
+
442
+			// Reset value.
443
+			$this->currentChildTableNameAlias = '';
444
+
445
+			if ($source instanceof SelectorInterface) {
446
+				$tableName = $this->query->getType();
447
+				while (strpos($propertyName, '.') !== false) {
448
+					$this->addUnionStatement($tableName, $propertyName, $statementParts);
449
+				}
450
+			} elseif ($source instanceof JoinInterface) {
451
+				$tableName = $source->getJoinCondition()->getSelector1Name();
452
+			}
453
+
454
+			$columnName = $propertyName;
455
+			$resolvedOperator = $this->resolveOperator($operator);
456
+			$constraintSQL = '';
457
+
458
+			$marker = $operator === QueryInterface::OPERATOR_IN
459
+				? '(?)'
460
+				: '?';
461
+
462
+			if ($valueFunction === null) {
463
+				$constraintSQL .= (!empty($tableName) ? $tableName . '.' : '') . $columnName . ' ' . $resolvedOperator . ' ' . $marker;
464
+			} else {
465
+				$constraintSQL .= $valueFunction . '(' . (!empty($tableName) ? $tableName . '.' : '') . $columnName . ') ' . $resolvedOperator . ' ' . $marker;
466
+			}
467
+
468
+			if (isset($tableName) && !empty($this->currentChildTableNameAlias)) {
469
+				$constraintSQL = $this->replaceTableNameByAlias($tableName, $this->currentChildTableNameAlias, $constraintSQL);
470
+			}
471
+			$statementParts['where'][] = $constraintSQL;
472
+		}
473
+	}
474
+
475
+	/**
476
+	 * @param string &$tableName
477
+	 * @param string &$propertyPath
478
+	 * @param array &$statementParts
479
+	 */
480
+	protected function addUnionStatement(&$tableName, &$propertyPath, array &$statementParts)
481
+	{
482
+
483
+		$table = Tca::table($tableName);
484
+
485
+		$explodedPropertyPath = explode('.', $propertyPath, 2);
486
+		$fieldName = $explodedPropertyPath[0];
487
+
488
+		// Field of type "group" are special because property path must contain the table name
489
+		// to determine the relation type. Example for sys_category, property path will look like "items.sys_file"
490
+		$parts = explode('.', $propertyPath, 3);
491
+		if ($table->field($fieldName)->isGroup() && count($parts) > 2) {
492
+			$explodedPropertyPath[0] = $parts[0] . '.' . $parts[1];
493
+			$explodedPropertyPath[1] = $parts[2];
494
+			$fieldName = $explodedPropertyPath[0];
495
+		}
496
+
497
+		$parentKeyFieldName = $table->field($fieldName)->getForeignField();
498
+		$childTableName = $table->field($fieldName)->getForeignTable();
499
+
500
+		if ($childTableName === null) {
501
+			throw new Exception\InvalidRelationConfigurationException('The relation information for property "' . $fieldName . '" of class "' . $tableName . '" is missing.', 1353170925);
502
+		}
503
+
504
+		if ($table->field($fieldName)->hasOne()) { // includes relation "one-to-one" and "many-to-one"
505
+			// sometimes the opposite relation is not defined. We don't want to force this config for backward compatibility reasons.
506
+			// $parentKeyFieldName === null does the trick somehow. Before condition was if (isset($parentKeyFieldName))
507
+			if ($table->field($fieldName)->hasRelationManyToOne() || $parentKeyFieldName === null) {
508
+				$statementParts['unions'][$childTableName] = 'LEFT JOIN ' . $childTableName . ' ON ' . $tableName . '.' . $fieldName . '=' . $childTableName . '.uid';
509
+			} else {
510
+				$statementParts['unions'][$childTableName] = 'LEFT JOIN ' . $childTableName . ' ON ' . $tableName . '.uid=' . $childTableName . '.' . $parentKeyFieldName;
511
+			}
512
+		} elseif ($table->field($fieldName)->hasRelationManyToMany()) {
513
+			$relationTableName = $table->field($fieldName)->getManyToManyTable();
514
+
515
+			$parentKeyFieldName = $table->field($fieldName)->isOppositeRelation() ? 'uid_foreign' : 'uid_local';
516
+			$childKeyFieldName = !$table->field($fieldName)->isOppositeRelation() ? 'uid_foreign' : 'uid_local';
517
+
518
+			// MM table e.g sys_category_record_mm
519
+			$relationTableNameAlias = $this->generateAlias($relationTableName);
520
+			$join = sprintf(
521
+				'LEFT JOIN %s AS %s ON %s.uid=%s.%s', $relationTableName,
522
+				$relationTableNameAlias,
523
+				$tableName,
524
+				$relationTableNameAlias,
525
+				$parentKeyFieldName
526
+			);
527
+			$statementParts['unions'][$relationTableNameAlias] = $join;
528
+
529
+			// Foreign table e.g sys_category
530
+			$childTableNameAlias = $this->generateAlias($childTableName);
531
+			$this->currentChildTableNameAlias = $childTableNameAlias;
532
+			$join = sprintf(
533
+				'LEFT JOIN %s AS %s ON %s.%s=%s.uid',
534
+				$childTableName,
535
+				$childTableNameAlias,
536
+				$relationTableNameAlias,
537
+				$childKeyFieldName,
538
+				$childTableNameAlias
539
+			);
540
+			$statementParts['unions'][$childTableNameAlias] = $join;
541
+
542
+			// Find a possible table name for a MM condition.
543
+			$tableNameCondition = $table->field($fieldName)->getAdditionalTableNameCondition();
544
+			if ($tableNameCondition) {
545
+
546
+				// If we can find a source file name,  we can then retrieve more MM conditions from the TCA such as a field name.
547
+				$sourceFileName = $this->query->getSourceFieldName();
548
+				if (empty($sourceFileName)) {
549
+					$additionalMMConditions = array(
550
+						'tablenames' => $tableNameCondition,
551
+					);
552
+				} else {
553
+					$additionalMMConditions = Tca::table($tableNameCondition)->field($sourceFileName)->getAdditionalMMCondition();
554
+				}
555
+
556
+				foreach ($additionalMMConditions as $additionalFieldName => $additionalMMCondition) {
557
+					$additionalJoin = sprintf(' AND %s.%s = "%s"', $relationTableNameAlias, $additionalFieldName, $additionalMMCondition);
558
+					$statementParts['unions'][$relationTableNameAlias] .= $additionalJoin;
559
+
560
+					$additionalJoin = sprintf(' AND %s.%s = "%s"', $relationTableNameAlias, $additionalFieldName, $additionalMMCondition);
561
+					$statementParts['unions'][$childTableNameAlias] .= $additionalJoin;
562
+				}
563
+			}
564
+
565
+		} elseif ($table->field($fieldName)->hasMany()) { // includes relations "many-to-one" and "csv" relations
566
+			$childTableNameAlias = $this->generateAlias($childTableName);
567
+			$this->currentChildTableNameAlias = $childTableNameAlias;
568
+
569
+			if (isset($parentKeyFieldName)) {
570
+				$join = sprintf(
571
+					'LEFT JOIN %s AS %s ON %s.uid=%s.%s',
572
+					$childTableName,
573
+					$childTableNameAlias,
574
+					$tableName,
575
+					$childTableNameAlias,
576
+					$parentKeyFieldName
577
+				);
578
+				$statementParts['unions'][$childTableNameAlias] = $join;
579
+			} else {
580
+				$join = sprintf(
581
+					'LEFT JOIN %s AS %s ON (FIND_IN_SET(%s.uid, %s.%s))',
582
+					$childTableName,
583
+					$childTableNameAlias,
584
+					$childTableNameAlias,
585
+					$tableName,
586
+					$fieldName
587
+				);
588
+				$statementParts['unions'][$childTableNameAlias] = $join;
589
+			}
590
+		} else {
591
+			throw new Exception('Could not determine type of relation.', 1252502725);
592
+		}
593
+
594
+		$statementParts['keywords']['distinct'] = 'DISTINCT';
595
+		$propertyPath = $explodedPropertyPath[1];
596
+		$tableName = $childTableName;
597
+	}
598
+
599
+	/**
600
+	 * Returns the SQL operator for the given JCR operator type.
601
+	 *
602
+	 * @param string $operator One of the JCR_OPERATOR_* constants
603
+	 * @return string an SQL operator
604
+	 * @throws Exception
605
+	 */
606
+	protected function resolveOperator($operator)
607
+	{
608
+		switch ($operator) {
609
+			case self::OPERATOR_EQUAL_TO_NULL:
610
+				$operator = 'IS';
611
+				break;
612
+			case self::OPERATOR_NOT_EQUAL_TO_NULL:
613
+				$operator = 'IS NOT';
614
+				break;
615
+			case QueryInterface::OPERATOR_IN:
616
+				$operator = 'IN';
617
+				break;
618
+			case QueryInterface::OPERATOR_EQUAL_TO:
619
+				$operator = '=';
620
+				break;
621
+			case QueryInterface::OPERATOR_NOT_EQUAL_TO:
622
+				$operator = '!=';
623
+				break;
624
+			case QueryInterface::OPERATOR_LESS_THAN:
625
+				$operator = '<';
626
+				break;
627
+			case QueryInterface::OPERATOR_LESS_THAN_OR_EQUAL_TO:
628
+				$operator = '<=';
629
+				break;
630
+			case QueryInterface::OPERATOR_GREATER_THAN:
631
+				$operator = '>';
632
+				break;
633
+			case QueryInterface::OPERATOR_GREATER_THAN_OR_EQUAL_TO:
634
+				$operator = '>=';
635
+				break;
636
+			case QueryInterface::OPERATOR_LIKE:
637
+				$operator = 'LIKE';
638
+				break;
639
+			default:
640
+				throw new Exception('Unsupported operator encountered.', 1242816073);
641
+		}
642
+		return $operator;
643
+	}
644
+
645
+	/**
646
+	 * Adds additional WHERE statements according to the query settings.
647
+	 *
648
+	 * @param QuerySettingsInterface $querySettings The TYPO3 CMS specific query settings
649
+	 * @param string $tableNameOrAlias The table name to add the additional where clause for
650
+	 * @param array &$statementParts
651
+	 * @return void
652
+	 */
653
+	protected function addAdditionalWhereClause(QuerySettingsInterface $querySettings, $tableNameOrAlias, &$statementParts)
654
+	{
655
+		$this->addVisibilityConstraintStatement($querySettings, $tableNameOrAlias, $statementParts);
656
+		if ($querySettings->getRespectSysLanguage()) {
657
+			$this->addSysLanguageStatement($tableNameOrAlias, $statementParts, $querySettings);
658
+		}
659
+	}
660
+
661
+	/**
662
+	 * Adds enableFields and deletedClause to the query if necessary
663
+	 *
664
+	 * @param QuerySettingsInterface $querySettings
665
+	 * @param string $tableNameOrAlias The database table name
666
+	 * @param array &$statementParts The query parts
667
+	 * @return void
668
+	 */
669
+	protected function addVisibilityConstraintStatement(QuerySettingsInterface $querySettings, $tableNameOrAlias, array &$statementParts)
670
+	{
671
+		$statement = '';
672
+		$tableName = $this->resolveTableNameAlias($tableNameOrAlias);
673
+		if (is_array($GLOBALS['TCA'][$tableName]['ctrl'])) {
674
+			$ignoreEnableFields = $querySettings->getIgnoreEnableFields();
675
+			$enableFieldsToBeIgnored = $querySettings->getEnableFieldsToBeIgnored();
676
+			$includeDeleted = $querySettings->getIncludeDeleted();
677
+			if ($this->environmentService->isEnvironmentInFrontendMode()) {
678
+				$statement .= $this->getFrontendConstraintStatement($tableNameOrAlias, $ignoreEnableFields, $enableFieldsToBeIgnored, $includeDeleted);
679
+			} else {
680
+				// TYPO3_MODE === 'BE'
681
+				$statement .= $this->getBackendConstraintStatement($tableNameOrAlias, $ignoreEnableFields, $includeDeleted);
682
+			}
683
+
684
+			// Remove the prefixing "AND" if any.
685
+			if (!empty($statement)) {
686
+				$statement = strtolower(substr($statement, 1, 3)) === 'and' ? substr($statement, 5) : $statement;
687
+				$statementParts['additionalWhereClause'][$tableNameOrAlias][] = $statement;
688
+			}
689
+		}
690
+	}
691
+
692
+	/**
693
+	 * Returns constraint statement for frontend context
694
+	 *
695
+	 * @param string $tableNameOrAlias
696
+	 * @param boolean $ignoreEnableFields A flag indicating whether the enable fields should be ignored
697
+	 * @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.
698
+	 * @param boolean $includeDeleted A flag indicating whether deleted records should be included
699
+	 * @return string
700
+	 * @throws Exception\InconsistentQuerySettingsException
701
+	 */
702
+	protected function getFrontendConstraintStatement($tableNameOrAlias, $ignoreEnableFields, $enableFieldsToBeIgnored, $includeDeleted)
703
+	{
704
+		$statement = '';
705
+		$tableName = $this->resolveTableNameAlias($tableNameOrAlias);
706
+		if ($ignoreEnableFields && !$includeDeleted) {
707
+			if (count($enableFieldsToBeIgnored)) {
708
+				// array_combine() is necessary because of the way \TYPO3\CMS\Frontend\Page\PageRepository::enableFields() is implemented
709
+				$statement .= $this->getPageRepository()->enableFields($tableName, -1, array_combine($enableFieldsToBeIgnored, $enableFieldsToBeIgnored));
710
+			} else {
711
+				$statement .= $this->getPageRepository()->deleteClause($tableName);
712
+			}
713
+		} elseif (!$ignoreEnableFields && !$includeDeleted) {
714
+			$statement .= $this->getPageRepository()->enableFields($tableName);
715
+		} elseif (!$ignoreEnableFields && $includeDeleted) {
716
+			throw new Exception\InconsistentQuerySettingsException('Query setting "ignoreEnableFields=false" can not be used together with "includeDeleted=true" in frontend context.', 1327678173);
717
+		}
718
+		return $this->replaceTableNameByAlias($tableName, $tableNameOrAlias, $statement);
719
+	}
720
+
721
+	/**
722
+	 * Returns constraint statement for backend context
723
+	 *
724
+	 * @param string $tableNameOrAlias
725
+	 * @param boolean $ignoreEnableFields A flag indicating whether the enable fields should be ignored
726
+	 * @param boolean $includeDeleted A flag indicating whether deleted records should be included
727
+	 * @return string
728
+	 */
729
+	protected function getBackendConstraintStatement($tableNameOrAlias, $ignoreEnableFields, $includeDeleted)
730
+	{
731
+		$tableName = $this->resolveTableNameAlias($tableNameOrAlias);
732
+		$statement = '';
733
+		if (!$ignoreEnableFields) {
734
+			$statement .= BackendUtility::BEenableFields($tableName);
735
+		}
736
+
737
+		// If the table is found to have "workspace" support, add the corresponding fields in the statement.
738
+		if (Tca::table($tableName)->hasWorkspaceSupport()) {
739
+			if ($this->getBackendUser()->workspace === 0) {
740
+				$statement .= ' AND ' . $tableName . '.t3ver_state<=' . new VersionState(VersionState::DEFAULT_STATE);
741
+			} else {
742
+				// Show only records of live and of the current workspace
743
+				// In case we are in a Versioning preview
744
+				$statement .= ' AND (' .
745
+					$tableName . '.t3ver_wsid=0 OR ' .
746
+					$tableName . '.t3ver_wsid=' . (int)$this->getBackendUser()->workspace .
747
+					')';
748
+			}
749
+
750
+			// Check if this segment make sense here or whether it should be in the "if" part when we have workspace = 0
751
+			$statement .= ' AND ' . $tableName . '.pid<>-1';
752
+		}
753
+
754
+		if (!$includeDeleted) {
755
+			$statement .= BackendUtility::deleteClause($tableName);
756
+		}
757
+
758
+		return $this->replaceTableNameByAlias($tableName, $tableNameOrAlias, $statement);
759
+	}
760
+
761
+	/**
762
+	 * Builds the language field statement
763
+	 *
764
+	 * @param string $tableNameOrAlias The database table name
765
+	 * @param array &$statementParts The query parts
766
+	 * @param QuerySettingsInterface $querySettings The TYPO3 CMS specific query settings
767
+	 * @return void
768
+	 * @throws Exception
769
+	 */
770
+	protected function addSysLanguageStatement($tableNameOrAlias, array &$statementParts, $querySettings)
771
+	{
772
+		$tableName = $this->resolveTableNameAlias($tableNameOrAlias);
773
+		if (is_array($GLOBALS['TCA'][$tableName]['ctrl'])) {
774
+			if (!empty($GLOBALS['TCA'][$tableName]['ctrl']['languageField'])) {
775
+				// Select all entries for the current language
776
+				$additionalWhereClause = $tableNameOrAlias . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] . ' IN (' . intval($querySettings->getLanguageUid()) . ',-1)';
777
+				// If any language is set -> get those entries which are not translated yet
778
+				// They will be removed by t3lib_page::getRecordOverlay if not matching overlay mode
779
+				if (isset($GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'])
780
+					&& $querySettings->getLanguageUid() > 0
781
+				) {
782
+					$additionalWhereClause .= ' OR (' . $tableNameOrAlias . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] . '=0' .
783
+						' AND ' . $tableNameOrAlias . '.uid NOT IN (SELECT ' . $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'] .
784
+						' FROM ' . $tableName .
785
+						' WHERE ' . $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'] . '>0' .
786
+						' AND ' . $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] . '>0';
787
+
788
+					// Add delete clause to ensure all entries are loaded
789
+					if (isset($GLOBALS['TCA'][$tableName]['ctrl']['delete'])) {
790
+						$additionalWhereClause .= ' AND ' . $tableNameOrAlias . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['delete'] . '=0';
791
+					}
792
+					$additionalWhereClause .= '))';
793
+				}
794
+				$statementParts['additionalWhereClause'][$tableNameOrAlias][] = '(' . $additionalWhereClause . ')';
795
+			}
796
+		}
797
+	}
798
+
799
+	/**
800
+	 * Transforms orderings into SQL.
801
+	 *
802
+	 * @param array $orderings An array of orderings (Tx_Extbase_Persistence_QOM_Ordering)
803
+	 * @param SourceInterface $source The source
804
+	 * @param array &$statementParts The query parts
805
+	 * @return void
806
+	 * @throws Exception\UnsupportedOrderException
807
+	 */
808
+	protected function parseOrderings(array $orderings, SourceInterface $source, array &$statementParts)
809
+	{
810
+		foreach ($orderings as $fieldNameAndPath => $order) {
811
+			switch ($order) {
812
+				case QueryInterface::ORDER_ASCENDING:
813
+					$order = 'ASC';
814
+					break;
815
+				case QueryInterface::ORDER_DESCENDING:
816
+					$order = 'DESC';
817
+					break;
818
+				default:
819
+					throw new Exception\UnsupportedOrderException('Unsupported order encountered.', 1456845126);
820
+			}
821
+
822
+			$tableName = $this->getFieldPathResolver()->getDataType($fieldNameAndPath, $this->query->getType());
823
+			$fieldName = $this->getFieldPathResolver()->stripFieldPath($fieldNameAndPath, $tableName);
824
+			$statementParts['orderings'][] = sprintf('%s.%s %s', $tableName, $fieldName, $order);
825
+		}
826
+	}
827
+
828
+	/**
829
+	 * Transforms limit and offset into SQL
830
+	 *
831
+	 * @param int $limit
832
+	 * @param int $offset
833
+	 * @param array &$statementParts
834
+	 * @return void
835
+	 */
836
+	protected function parseLimitAndOffset($limit, $offset, array &$statementParts)
837
+	{
838
+		if ($limit !== null && $offset !== null) {
839
+			$statementParts['limit'] = intval($offset) . ', ' . intval($limit);
840
+		} elseif ($limit !== null) {
841
+			$statementParts['limit'] = intval($limit);
842
+		}
843
+	}
844
+
845
+	/**
846
+	 * @param array $rows
847
+	 * @return array
848
+	 */
849
+	protected function getContentObjects(array $rows): array
850
+	{
851
+		$contentObjects = [];
852
+		foreach ($rows as $row) {
853
+
854
+			// Get language uid from querySettings.
855
+			// Ensure the backend handling is not broken (fallback to Get parameter 'L' if needed)
856
+			$overlaidRow = $this->doLanguageAndWorkspaceOverlay(
857
+				$row,
858
+				$this->query->getQuerySettings()
859
+			);
860
+
861
+			$contentObjects[] = GeneralUtility::makeInstance(
862
+				\Fab\Vidi\Domain\Model\Content::class,
863
+				$this->query->getType(),
864
+				$overlaidRow
865
+			);
866
+		}
867
+
868
+		return $contentObjects;
869
+	}
870
+
871
+	/**
872
+	 * Performs workspace and language overlay on the given row array. The language and workspace id is automatically
873
+	 * detected (depending on FE or BE context). You can also explicitly set the language/workspace id.
874
+	 *
875
+	 * @param array $row
876
+	 * @param QuerySettingsInterface $querySettings The TYPO3 CMS specific query settings
877
+	 * @return array
878
+	 */
879
+	protected function doLanguageAndWorkspaceOverlay(array $row, $querySettings)
880
+	{
881
+		$tableName = $this->getTableName();
882
+
883
+		$pageRepository = $this->getPageRepository();
884
+		if (is_object($GLOBALS['TSFE'])) {
885
+			$languageMode = $GLOBALS['TSFE']->sys_language_mode;
886
+			if ($this->isBackendUserLogged() && $this->getBackendUser()->workspace !== 0) {
887
+				$pageRepository->versioningWorkspaceId = $this->getBackendUser()->workspace;
888
+			}
889
+		} else {
890
+			$languageMode = '';
891
+			$workspaceUid = $this->getBackendUser()->workspace;
892
+			$pageRepository->versioningWorkspaceId = $workspaceUid;
893
+			if ($this->getBackendUser()->workspace !== 0) {
894
+				$pageRepository->versioningPreview = 1;
895
+			}
896
+		}
897
+
898
+		// If current row is a translation select its parent
899
+		if (isset($GLOBALS['TCA'][$tableName]['ctrl']['languageField'])
900
+			&& isset($GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'])
901
+		) {
902
+			if (isset($row[$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']])
903
+				&& $row[$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']] > 0
904
+			) {
905
+				$queryBuilder = $this->getQueryBuilder();
906
+				$row = $queryBuilder
907
+					->select($tableName . '.*')
908
+					->from($tableName)
909
+					->andWhere(
910
+						$tableName . '.uid=' . (int)$row[$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']],
911
+						$tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] . ' = 0'
912
+					)
913
+					->execute()
914
+					->fetch();
915
+			}
916
+		}
917
+
918
+		// Retrieve the original uid; Used for Workspaces!
919
+		if (TYPO3_MODE !== 'BE') {
920
+			$pageRepository->versionOL($tableName, $row, true, true);
921
+		} else {
922
+			\TYPO3\CMS\Backend\Utility\BackendUtility::workspaceOL($tableName, $row);
923
+		}
924
+		if ($pageRepository->versioningPreview && isset($row['_ORIG_uid'])) {
925
+			$row['uid'] = $row['_ORIG_uid'];
926
+		}
927
+
928
+		// Special case for table "pages"
929
+		if ($tableName == 'pages') {
930
+			$row = $pageRepository->getPageOverlay($row, $querySettings->getLanguageUid());
931
+		} elseif (isset($GLOBALS['TCA'][$tableName]['ctrl']['languageField'])
932
+			&& $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] !== ''
933
+		) {
934
+			if (in_array($row[$GLOBALS['TCA'][$tableName]['ctrl']['languageField']], array(-1, 0))) {
935
+				$overlayMode = $languageMode === 'strict' ? 'hideNonTranslated' : '';
936
+				$row = $pageRepository->getRecordOverlay($tableName, $row, $querySettings->getLanguageUid(), $overlayMode);
937
+			}
938
+		}
939
+
940
+		return $row;
941
+	}
942
+
943
+	/**
944
+	 * Return a resolved table name given a possible table name alias.
945
+	 *
946
+	 * @param string $tableNameOrAlias
947
+	 * @return string
948
+	 */
949
+	protected function resolveTableNameAlias($tableNameOrAlias)
950
+	{
951
+		$resolvedTableName = $tableNameOrAlias;
952
+		if (!empty($this->tableNameAliases['aliases'][$tableNameOrAlias])) {
953
+			$resolvedTableName = $this->tableNameAliases['aliases'][$tableNameOrAlias];
954
+		}
955
+		return $resolvedTableName;
956
+	}
957
+
958
+	/**
959
+	 * Generate a unique table name alias for the given table name.
960
+	 *
961
+	 * @param string $tableName
962
+	 * @return string
963
+	 */
964
+	protected function generateAlias($tableName)
965
+	{
966
+
967
+		if (!isset($this->tableNameAliases['aliasIncrement'][$tableName])) {
968
+			$this->tableNameAliases['aliasIncrement'][$tableName] = 0;
969
+		}
970
+
971
+		$numberOfAliases = $this->tableNameAliases['aliasIncrement'][$tableName];
972
+		$tableNameAlias = $tableName . $numberOfAliases;
973
+
974
+		$this->tableNameAliases['aliasIncrement'][$tableName]++;
975
+		$this->tableNameAliases['aliases'][$tableNameAlias] = $tableName;
976
+
977
+		return $tableNameAlias;
978
+	}
979
+
980
+	/**
981
+	 * Replace the table names by its table name alias within the given statement.
982
+	 *
983
+	 * @param string $tableName
984
+	 * @param string $tableNameAlias
985
+	 * @param string $statement
986
+	 * @return string
987
+	 */
988
+	protected function replaceTableNameByAlias($tableName, $tableNameAlias, $statement)
989
+	{
990
+		if ($statement && $tableName !== $tableNameAlias) {
991
+			$statement = str_replace($tableName, $tableNameAlias, $statement);
992
+		}
993
+		return $statement;
994
+	}
995
+
996
+	/**
997
+	 * Returns an instance of the current Backend User.
998
+	 *
999
+	 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
1000
+	 */
1001
+	protected function getBackendUser()
1002
+	{
1003
+		return $GLOBALS['BE_USER'];
1004
+	}
1005
+
1006
+	/**
1007
+	 * Tell whether a Backend User is logged in.
1008
+	 *
1009
+	 * @return bool
1010
+	 */
1011
+	protected function isBackendUserLogged()
1012
+	{
1013
+		return is_object($GLOBALS['BE_USER']);
1014
+	}
1015
+
1016
+	/**
1017
+	 * @return PageRepository|object
1018
+	 */
1019
+	protected function getPageRepository()
1020
+	{
1021
+		if (!$this->pageRepository instanceof PageRepository) {
1022
+			if ($this->environmentService->isEnvironmentInFrontendMode() && is_object($GLOBALS['TSFE'])) {
1023
+				$this->pageRepository = $GLOBALS['TSFE']->sys_page;
1024
+			} else {
1025
+				$this->pageRepository = GeneralUtility::makeInstance(PageRepository::class);
1026
+			}
1027
+		}
1028
+
1029
+		return $this->pageRepository;
1030
+	}
1031
+
1032
+	/**
1033
+	 * @return \Fab\Vidi\Resolver\FieldPathResolver|object
1034
+	 */
1035
+	protected function getFieldPathResolver()
1036
+	{
1037
+		return GeneralUtility::makeInstance(\Fab\Vidi\Resolver\FieldPathResolver::class);
1038
+	}
1039
+
1040
+	/**
1041
+	 * @return object|Connection
1042
+	 */
1043
+	protected function getConnection(): Connection
1044
+	{
1045
+		/** @var ConnectionPool $connectionPool */
1046
+		return GeneralUtility::makeInstance(ConnectionPool::class)
1047
+			->getConnectionForTable($this->getTableName());
1048
+	}
1049
+
1050
+	/**
1051
+	 * @return object|QueryBuilder
1052
+	 */
1053
+	protected function getQueryBuilder(): QueryBuilder
1054
+	{
1055
+		/** @var ConnectionPool $connectionPool */
1056
+		$connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
1057
+		return $connectionPool->getQueryBuilderForTable($this->getTableName());
1058
+	}
1059
+
1060
+	/**
1061
+	 * @return string
1062
+	 */
1063
+	public function getTableName(): string
1064
+	{
1065
+		return $this->query->getSource()->getNodeTypeName(); // getSelectorName()
1066
+	}
1067 1067
 
1068 1068
 }
Please login to merge, or discard this patch.
Spacing   +37 added lines, -37 removed lines patch added patch discarded remove patch
@@ -127,7 +127,7 @@  discard block
 block discarded – undo
127 127
             if (isset($statementParts['keywords']['distinct'])) {
128 128
                 unset($statementParts['keywords']['distinct']);
129 129
                 $distinctField = $this->query->getDistinct() ? $this->query->getDistinct() : 'uid';
130
-                $statementParts['fields'] = array('COUNT(DISTINCT ' . $statementParts['mainTable'] . '.' . $distinctField . ')');
130
+                $statementParts['fields'] = array('COUNT(DISTINCT '.$statementParts['mainTable'].'.'.$distinctField.')');
131 131
             }
132 132
 
133 133
             $sql = $this->buildQuery($statementParts);
@@ -190,14 +190,14 @@  discard block
 block discarded – undo
190 190
             // tx_domain_model_foo0 (the alias) <--> tx_domain_model_foo (the origin table name)
191 191
             $values = [];
192 192
             foreach ($statementParts['fields'] as $key => $value) {
193
-                $values[$key] = str_replace($tableName, $tableName . '0', $value);
193
+                $values[$key] = str_replace($tableName, $tableName.'0', $value);
194 194
             }
195 195
             $statementParts['fields'] = $values;
196 196
 
197 197
             // Same comment as above.
198 198
             $values = [];
199 199
             foreach ($statementParts['where'] as $key => $value) {
200
-                $values[$key] = str_replace($tableName . '0', $tableName, $value);
200
+                $values[$key] = str_replace($tableName.'0', $tableName, $value);
201 201
             }
202 202
             $statementParts['where'] = $values;
203 203
 
@@ -236,25 +236,25 @@  discard block
 block discarded – undo
236 236
         if (!empty($statementParts['unions'])) {
237 237
             foreach ($statementParts['unions'] as $tableName => $unionPart) {
238 238
                 if (!empty($statementParts['additionalWhereClause'][$tableName])) {
239
-                    $statementParts['unions'][$tableName] .= ' AND ' . implode(' AND ', $statementParts['additionalWhereClause'][$tableName]);
239
+                    $statementParts['unions'][$tableName] .= ' AND '.implode(' AND ', $statementParts['additionalWhereClause'][$tableName]);
240 240
                 }
241 241
             }
242 242
         }
243 243
 
244
-        $statement = 'SELECT ' . implode(' ', $statementParts['keywords']) . ' ' . implode(',', $statementParts['fields']) . ' FROM ' . implode(' ', $statementParts['tables']) . ' ' . implode(' ', $statementParts['unions']);
244
+        $statement = 'SELECT '.implode(' ', $statementParts['keywords']).' '.implode(',', $statementParts['fields']).' FROM '.implode(' ', $statementParts['tables']).' '.implode(' ', $statementParts['unions']);
245 245
         if (!empty($statementParts['where'])) {
246
-            $statement .= ' WHERE ' . implode('', $statementParts['where']);
246
+            $statement .= ' WHERE '.implode('', $statementParts['where']);
247 247
             if (!empty($statementParts['additionalWhereClause'][$this->query->getType()])) {
248
-                $statement .= ' AND ' . implode(' AND ', $statementParts['additionalWhereClause'][$this->query->getType()]);
248
+                $statement .= ' AND '.implode(' AND ', $statementParts['additionalWhereClause'][$this->query->getType()]);
249 249
             }
250 250
         } elseif (!empty($statementParts['additionalWhereClause'])) {
251
-            $statement .= ' WHERE ' . implode(' AND ', $statementParts['additionalWhereClause'][$this->query->getType()]);
251
+            $statement .= ' WHERE '.implode(' AND ', $statementParts['additionalWhereClause'][$this->query->getType()]);
252 252
         }
253 253
         if (!empty($statementParts['orderings'])) {
254
-            $statement .= ' ORDER BY ' . implode(', ', $statementParts['orderings']);
254
+            $statement .= ' ORDER BY '.implode(', ', $statementParts['orderings']);
255 255
         }
256 256
         if (!empty($statementParts['limit'])) {
257
-            $statement .= ' LIMIT ' . $statementParts['limit'];
257
+            $statement .= ' LIMIT '.$statementParts['limit'];
258 258
         }
259 259
 
260 260
         return $statement;
@@ -270,9 +270,9 @@  discard block
 block discarded – undo
270 270
     protected function parseSource(SourceInterface $source, array &$sql)
271 271
     {
272 272
         $tableName = $this->getTableName();
273
-        $sql['fields'][$tableName] = $tableName . '.*';
273
+        $sql['fields'][$tableName] = $tableName.'.*';
274 274
         if ($this->query->getDistinct()) {
275
-            $sql['fields'][$tableName] = $tableName . '.' . $this->query->getDistinct();
275
+            $sql['fields'][$tableName] = $tableName.'.'.$this->query->getDistinct();
276 276
             $sql['keywords']['distinct'] = 'DISTINCT';
277 277
         }
278 278
         $sql['tables'][$tableName] = $tableName;
@@ -410,7 +410,7 @@  discard block
 block discarded – undo
410 410
             if ($realInput instanceof \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface) {
411 411
                 return $realInput->getUid();
412 412
             } else {
413
-                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);
413
+                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);
414 414
             }
415 415
         } elseif (is_bool($input)) {
416 416
             return $input === true ? 1 : 0;
@@ -460,9 +460,9 @@  discard block
 block discarded – undo
460 460
                 : '?';
461 461
 
462 462
             if ($valueFunction === null) {
463
-                $constraintSQL .= (!empty($tableName) ? $tableName . '.' : '') . $columnName . ' ' . $resolvedOperator . ' ' . $marker;
463
+                $constraintSQL .= (!empty($tableName) ? $tableName.'.' : '').$columnName.' '.$resolvedOperator.' '.$marker;
464 464
             } else {
465
-                $constraintSQL .= $valueFunction . '(' . (!empty($tableName) ? $tableName . '.' : '') . $columnName . ') ' . $resolvedOperator . ' ' . $marker;
465
+                $constraintSQL .= $valueFunction.'('.(!empty($tableName) ? $tableName.'.' : '').$columnName.') '.$resolvedOperator.' '.$marker;
466 466
             }
467 467
 
468 468
             if (isset($tableName) && !empty($this->currentChildTableNameAlias)) {
@@ -489,7 +489,7 @@  discard block
 block discarded – undo
489 489
         // to determine the relation type. Example for sys_category, property path will look like "items.sys_file"
490 490
         $parts = explode('.', $propertyPath, 3);
491 491
         if ($table->field($fieldName)->isGroup() && count($parts) > 2) {
492
-            $explodedPropertyPath[0] = $parts[0] . '.' . $parts[1];
492
+            $explodedPropertyPath[0] = $parts[0].'.'.$parts[1];
493 493
             $explodedPropertyPath[1] = $parts[2];
494 494
             $fieldName = $explodedPropertyPath[0];
495 495
         }
@@ -498,16 +498,16 @@  discard block
 block discarded – undo
498 498
         $childTableName = $table->field($fieldName)->getForeignTable();
499 499
 
500 500
         if ($childTableName === null) {
501
-            throw new Exception\InvalidRelationConfigurationException('The relation information for property "' . $fieldName . '" of class "' . $tableName . '" is missing.', 1353170925);
501
+            throw new Exception\InvalidRelationConfigurationException('The relation information for property "'.$fieldName.'" of class "'.$tableName.'" is missing.', 1353170925);
502 502
         }
503 503
 
504 504
         if ($table->field($fieldName)->hasOne()) { // includes relation "one-to-one" and "many-to-one"
505 505
             // sometimes the opposite relation is not defined. We don't want to force this config for backward compatibility reasons.
506 506
             // $parentKeyFieldName === null does the trick somehow. Before condition was if (isset($parentKeyFieldName))
507 507
             if ($table->field($fieldName)->hasRelationManyToOne() || $parentKeyFieldName === null) {
508
-                $statementParts['unions'][$childTableName] = 'LEFT JOIN ' . $childTableName . ' ON ' . $tableName . '.' . $fieldName . '=' . $childTableName . '.uid';
508
+                $statementParts['unions'][$childTableName] = 'LEFT JOIN '.$childTableName.' ON '.$tableName.'.'.$fieldName.'='.$childTableName.'.uid';
509 509
             } else {
510
-                $statementParts['unions'][$childTableName] = 'LEFT JOIN ' . $childTableName . ' ON ' . $tableName . '.uid=' . $childTableName . '.' . $parentKeyFieldName;
510
+                $statementParts['unions'][$childTableName] = 'LEFT JOIN '.$childTableName.' ON '.$tableName.'.uid='.$childTableName.'.'.$parentKeyFieldName;
511 511
             }
512 512
         } elseif ($table->field($fieldName)->hasRelationManyToMany()) {
513 513
             $relationTableName = $table->field($fieldName)->getManyToManyTable();
@@ -737,18 +737,18 @@  discard block
 block discarded – undo
737 737
         // If the table is found to have "workspace" support, add the corresponding fields in the statement.
738 738
         if (Tca::table($tableName)->hasWorkspaceSupport()) {
739 739
             if ($this->getBackendUser()->workspace === 0) {
740
-                $statement .= ' AND ' . $tableName . '.t3ver_state<=' . new VersionState(VersionState::DEFAULT_STATE);
740
+                $statement .= ' AND '.$tableName.'.t3ver_state<='.new VersionState(VersionState::DEFAULT_STATE);
741 741
             } else {
742 742
                 // Show only records of live and of the current workspace
743 743
                 // In case we are in a Versioning preview
744
-                $statement .= ' AND (' .
745
-                    $tableName . '.t3ver_wsid=0 OR ' .
746
-                    $tableName . '.t3ver_wsid=' . (int)$this->getBackendUser()->workspace .
744
+                $statement .= ' AND ('.
745
+                    $tableName.'.t3ver_wsid=0 OR '.
746
+                    $tableName.'.t3ver_wsid='.(int)$this->getBackendUser()->workspace.
747 747
                     ')';
748 748
             }
749 749
 
750 750
             // Check if this segment make sense here or whether it should be in the "if" part when we have workspace = 0
751
-            $statement .= ' AND ' . $tableName . '.pid<>-1';
751
+            $statement .= ' AND '.$tableName.'.pid<>-1';
752 752
         }
753 753
 
754 754
         if (!$includeDeleted) {
@@ -773,25 +773,25 @@  discard block
 block discarded – undo
773 773
         if (is_array($GLOBALS['TCA'][$tableName]['ctrl'])) {
774 774
             if (!empty($GLOBALS['TCA'][$tableName]['ctrl']['languageField'])) {
775 775
                 // Select all entries for the current language
776
-                $additionalWhereClause = $tableNameOrAlias . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] . ' IN (' . intval($querySettings->getLanguageUid()) . ',-1)';
776
+                $additionalWhereClause = $tableNameOrAlias.'.'.$GLOBALS['TCA'][$tableName]['ctrl']['languageField'].' IN ('.intval($querySettings->getLanguageUid()).',-1)';
777 777
                 // If any language is set -> get those entries which are not translated yet
778 778
                 // They will be removed by t3lib_page::getRecordOverlay if not matching overlay mode
779 779
                 if (isset($GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'])
780 780
                     && $querySettings->getLanguageUid() > 0
781 781
                 ) {
782
-                    $additionalWhereClause .= ' OR (' . $tableNameOrAlias . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] . '=0' .
783
-                        ' AND ' . $tableNameOrAlias . '.uid NOT IN (SELECT ' . $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'] .
784
-                        ' FROM ' . $tableName .
785
-                        ' WHERE ' . $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'] . '>0' .
786
-                        ' AND ' . $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] . '>0';
782
+                    $additionalWhereClause .= ' OR ('.$tableNameOrAlias.'.'.$GLOBALS['TCA'][$tableName]['ctrl']['languageField'].'=0'.
783
+                        ' AND '.$tableNameOrAlias.'.uid NOT IN (SELECT '.$tableName.'.'.$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'].
784
+                        ' FROM '.$tableName.
785
+                        ' WHERE '.$tableName.'.'.$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'].'>0'.
786
+                        ' AND '.$tableName.'.'.$GLOBALS['TCA'][$tableName]['ctrl']['languageField'].'>0';
787 787
 
788 788
                     // Add delete clause to ensure all entries are loaded
789 789
                     if (isset($GLOBALS['TCA'][$tableName]['ctrl']['delete'])) {
790
-                        $additionalWhereClause .= ' AND ' . $tableNameOrAlias . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['delete'] . '=0';
790
+                        $additionalWhereClause .= ' AND '.$tableNameOrAlias.'.'.$GLOBALS['TCA'][$tableName]['ctrl']['delete'].'=0';
791 791
                     }
792 792
                     $additionalWhereClause .= '))';
793 793
                 }
794
-                $statementParts['additionalWhereClause'][$tableNameOrAlias][] = '(' . $additionalWhereClause . ')';
794
+                $statementParts['additionalWhereClause'][$tableNameOrAlias][] = '('.$additionalWhereClause.')';
795 795
             }
796 796
         }
797 797
     }
@@ -836,7 +836,7 @@  discard block
 block discarded – undo
836 836
     protected function parseLimitAndOffset($limit, $offset, array &$statementParts)
837 837
     {
838 838
         if ($limit !== null && $offset !== null) {
839
-            $statementParts['limit'] = intval($offset) . ', ' . intval($limit);
839
+            $statementParts['limit'] = intval($offset).', '.intval($limit);
840 840
         } elseif ($limit !== null) {
841 841
             $statementParts['limit'] = intval($limit);
842 842
         }
@@ -904,11 +904,11 @@  discard block
 block discarded – undo
904 904
             ) {
905 905
                 $queryBuilder = $this->getQueryBuilder();
906 906
                 $row = $queryBuilder
907
-                    ->select($tableName . '.*')
907
+                    ->select($tableName.'.*')
908 908
                     ->from($tableName)
909 909
                     ->andWhere(
910
-                        $tableName . '.uid=' . (int)$row[$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']],
911
-                        $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] . ' = 0'
910
+                        $tableName.'.uid='.(int)$row[$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']],
911
+                        $tableName.'.'.$GLOBALS['TCA'][$tableName]['ctrl']['languageField'].' = 0'
912 912
                     )
913 913
                     ->execute()
914 914
                     ->fetch();
@@ -969,7 +969,7 @@  discard block
 block discarded – undo
969 969
         }
970 970
 
971 971
         $numberOfAliases = $this->tableNameAliases['aliasIncrement'][$tableName];
972
-        $tableNameAlias = $tableName . $numberOfAliases;
972
+        $tableNameAlias = $tableName.$numberOfAliases;
973 973
 
974 974
         $this->tableNameAliases['aliasIncrement'][$tableName]++;
975 975
         $this->tableNameAliases['aliases'][$tableNameAlias] = $tableName;
Please login to merge, or discard this patch.
Classes/Service/FileReferenceService.php 3 patches
Doc Comments   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -69,7 +69,7 @@  discard block
 block discarded – undo
69 69
     /**
70 70
      * Fetch the files given an object assuming
71 71
      *
72
-     * @param $propertyName
72
+     * @param string $propertyName
73 73
      * @param Content $object
74 74
      * @return File[]
75 75
      */
@@ -99,7 +99,7 @@  discard block
 block discarded – undo
99 99
     }
100 100
 
101 101
     /**
102
-     * @return DataService
102
+     * @return string
103 103
      */
104 104
     protected function getDataService(): string
105 105
     {
Please login to merge, or discard this patch.
Unused Use Statements   -1 removed lines patch added patch discarded remove patch
@@ -8,7 +8,6 @@
 block discarded – undo
8 8
  * LICENSE.md file that was distributed with this source code.
9 9
  */
10 10
 
11
-use Fab\Vidi\Utility\BackendUtility;
12 11
 use TYPO3\CMS\Core\Resource\File;
13 12
 use TYPO3\CMS\Core\Resource\ResourceFactory;
14 13
 use TYPO3\CMS\Core\SingletonInterface;
Please login to merge, or discard this patch.
Indentation   +82 added lines, -82 removed lines patch added patch discarded remove patch
@@ -23,87 +23,87 @@
 block discarded – undo
23 23
 class FileReferenceService implements SingletonInterface
24 24
 {
25 25
 
26
-    /**
27
-     * @var array
28
-     */
29
-    static protected $instances = [];
30
-
31
-    /**
32
-     * Returns a class instance
33
-     *
34
-     * @return \Fab\Vidi\Service\FileReferenceService|object
35
-     */
36
-    static public function getInstance()
37
-    {
38
-        return GeneralUtility::makeInstance(\Fab\Vidi\Service\FileReferenceService::class);
39
-    }
40
-
41
-    /**
42
-     * @param Content $object
43
-     * @param string $propertyName
44
-     * @return File[]
45
-     */
46
-    public function findReferencedBy($propertyName, Content $object)
47
-    {
48
-
49
-        if (!isset(self::$instances[$object->getUid()][$propertyName])) {
50
-
51
-            // Initialize instances value
52
-            if (!isset(self::$instances[$object->getUid()])) {
53
-                self::$instances[$object->getUid()] = [];
54
-            }
55
-
56
-            $fieldName = GeneralUtility::camelCaseToLowerCaseUnderscored($propertyName);
57
-            $field = Tca::table($object->getDataType())->field($fieldName);
58
-            if ($field->getForeignTable() === 'sys_file_reference') {
59
-                $files = $this->findByFileReference($propertyName, $object);
60
-                self::$instances[$object->getUid()][$propertyName] = $files;
61
-            } else {
62
-                // @todo the standard way of handling file references is by "sys_file_reference". Let see if there is other use cases...
63
-            }
64
-        }
65
-
66
-        return self::$instances[$object->getUid()][$propertyName];
67
-    }
68
-
69
-    /**
70
-     * Fetch the files given an object assuming
71
-     *
72
-     * @param $propertyName
73
-     * @param Content $object
74
-     * @return File[]
75
-     */
76
-    protected function findByFileReference($propertyName, Content $object)
77
-    {
78
-
79
-        $fileField = 'uid_local';
80
-        $tableName = 'sys_file_reference';
81
-
82
-        $rows = $this->getDataService()->getRecords(
83
-            $tableName,
84
-            [
85
-                'tablenames' => $object->getDataType(),
86
-                'fieldname'=> GeneralUtility::camelCaseToLowerCaseUnderscored($propertyName),
87
-                'uid_foreign'=> $object->getUid(),
88
-            ]
89
-        );
90
-
91
-
92
-        // Build array of Files
93
-        $files = [];
94
-        foreach ($rows as $row) {
95
-            $files[] = ResourceFactory::getInstance()->getFileObject($row[$fileField]);
96
-        }
97
-
98
-        return $files;
99
-    }
100
-
101
-    /**
102
-     * @return DataService
103
-     */
104
-    protected function getDataService(): string
105
-    {
106
-        return GeneralUtility::makeInstance(DataService::class);
107
-    }
26
+	/**
27
+	 * @var array
28
+	 */
29
+	static protected $instances = [];
30
+
31
+	/**
32
+	 * Returns a class instance
33
+	 *
34
+	 * @return \Fab\Vidi\Service\FileReferenceService|object
35
+	 */
36
+	static public function getInstance()
37
+	{
38
+		return GeneralUtility::makeInstance(\Fab\Vidi\Service\FileReferenceService::class);
39
+	}
40
+
41
+	/**
42
+	 * @param Content $object
43
+	 * @param string $propertyName
44
+	 * @return File[]
45
+	 */
46
+	public function findReferencedBy($propertyName, Content $object)
47
+	{
48
+
49
+		if (!isset(self::$instances[$object->getUid()][$propertyName])) {
50
+
51
+			// Initialize instances value
52
+			if (!isset(self::$instances[$object->getUid()])) {
53
+				self::$instances[$object->getUid()] = [];
54
+			}
55
+
56
+			$fieldName = GeneralUtility::camelCaseToLowerCaseUnderscored($propertyName);
57
+			$field = Tca::table($object->getDataType())->field($fieldName);
58
+			if ($field->getForeignTable() === 'sys_file_reference') {
59
+				$files = $this->findByFileReference($propertyName, $object);
60
+				self::$instances[$object->getUid()][$propertyName] = $files;
61
+			} else {
62
+				// @todo the standard way of handling file references is by "sys_file_reference". Let see if there is other use cases...
63
+			}
64
+		}
65
+
66
+		return self::$instances[$object->getUid()][$propertyName];
67
+	}
68
+
69
+	/**
70
+	 * Fetch the files given an object assuming
71
+	 *
72
+	 * @param $propertyName
73
+	 * @param Content $object
74
+	 * @return File[]
75
+	 */
76
+	protected function findByFileReference($propertyName, Content $object)
77
+	{
78
+
79
+		$fileField = 'uid_local';
80
+		$tableName = 'sys_file_reference';
81
+
82
+		$rows = $this->getDataService()->getRecords(
83
+			$tableName,
84
+			[
85
+				'tablenames' => $object->getDataType(),
86
+				'fieldname'=> GeneralUtility::camelCaseToLowerCaseUnderscored($propertyName),
87
+				'uid_foreign'=> $object->getUid(),
88
+			]
89
+		);
90
+
91
+
92
+		// Build array of Files
93
+		$files = [];
94
+		foreach ($rows as $row) {
95
+			$files[] = ResourceFactory::getInstance()->getFileObject($row[$fileField]);
96
+		}
97
+
98
+		return $files;
99
+	}
100
+
101
+	/**
102
+	 * @return DataService
103
+	 */
104
+	protected function getDataService(): string
105
+	{
106
+		return GeneralUtility::makeInstance(DataService::class);
107
+	}
108 108
 
109 109
 }
Please login to merge, or discard this patch.
ext_localconf.php 1 patch
Indentation   +29 added lines, -29 removed lines patch added patch discarded remove patch
@@ -3,33 +3,33 @@
 block discarded – undo
3 3
 
4 4
 call_user_func(function () {
5 5
 
6
-    $configuration = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(
7
-        \TYPO3\CMS\Core\Configuration\ExtensionConfiguration::class
8
-    )->get('vidi');
9
-
10
-    if (false === isset($configuration['autoload_typoscript']) || true === (bool)$configuration['autoload_typoscript']) {
11
-
12
-        \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTypoScript(
13
-            'vidi',
14
-            'constants',
15
-            '<INCLUDE_TYPOSCRIPT: source="FILE:EXT:vidi/Configuration/TypoScript/constants.txt">'
16
-        );
17
-
18
-        \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTypoScript(
19
-            'vidi',
20
-            'setup',
21
-            '<INCLUDE_TYPOSCRIPT: source="FILE:EXT:vidi/Configuration/TypoScript/setup.txt">'
22
-        );
23
-    }
24
-
25
-    // Initialize generic Vidi modules after the TCA is loaded.
26
-    $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['extTablesInclusion-PostProcessing'][] = 'Fab\Vidi\Configuration\VidiModulesAspect';
27
-
28
-    // Initialize generic grid TCA for all data types
29
-    $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['extTablesInclusion-PostProcessing'][] = 'Fab\Vidi\Configuration\TcaGridAspect';
30
-
31
-    // cache configuration, see https://docs.typo3.org/typo3cms/CoreApiReference/ApiOverview/CachingFramework/Configuration/Index.html#cache-configurations
32
-    $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['vidi']['frontend'] = \TYPO3\CMS\Core\Cache\Frontend\VariableFrontend::class;
33
-    $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['vidi']['groups'] = array('all', 'vidi');
34
-    $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['vidi']['options']['defaultLifetime'] = 2592000;
6
+	$configuration = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(
7
+		\TYPO3\CMS\Core\Configuration\ExtensionConfiguration::class
8
+	)->get('vidi');
9
+
10
+	if (false === isset($configuration['autoload_typoscript']) || true === (bool)$configuration['autoload_typoscript']) {
11
+
12
+		\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTypoScript(
13
+			'vidi',
14
+			'constants',
15
+			'<INCLUDE_TYPOSCRIPT: source="FILE:EXT:vidi/Configuration/TypoScript/constants.txt">'
16
+		);
17
+
18
+		\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTypoScript(
19
+			'vidi',
20
+			'setup',
21
+			'<INCLUDE_TYPOSCRIPT: source="FILE:EXT:vidi/Configuration/TypoScript/setup.txt">'
22
+		);
23
+	}
24
+
25
+	// Initialize generic Vidi modules after the TCA is loaded.
26
+	$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['extTablesInclusion-PostProcessing'][] = 'Fab\Vidi\Configuration\VidiModulesAspect';
27
+
28
+	// Initialize generic grid TCA for all data types
29
+	$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['extTablesInclusion-PostProcessing'][] = 'Fab\Vidi\Configuration\TcaGridAspect';
30
+
31
+	// cache configuration, see https://docs.typo3.org/typo3cms/CoreApiReference/ApiOverview/CachingFramework/Configuration/Index.html#cache-configurations
32
+	$GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['vidi']['frontend'] = \TYPO3\CMS\Core\Cache\Frontend\VariableFrontend::class;
33
+	$GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['vidi']['groups'] = array('all', 'vidi');
34
+	$GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['vidi']['options']['defaultLifetime'] = 2592000;
35 35
 });
36 36
\ No newline at end of file
Please login to merge, or discard this patch.
Classes/Module/ModulePidService.php 1 patch
Indentation   +218 added lines, -218 removed lines patch added patch discarded remove patch
@@ -19,223 +19,223 @@
 block discarded – undo
19 19
  */
20 20
 class ModulePidService
21 21
 {
22
-    /**
23
-     * The data type (table)
24
-     *
25
-     * @var string
26
-     */
27
-    protected $dataType = '';
28
-
29
-    /**
30
-     * The page record of the configured pid
31
-     *
32
-     * @var array
33
-     */
34
-    protected $page = [];
35
-
36
-    /**
37
-     * A collection of speaking error messages why the pid is invalid.
38
-     *
39
-     * @var array
40
-     */
41
-    protected $errors = [];
42
-
43
-    /**
44
-     * ModulePidService constructor.
45
-     */
46
-    public function __construct()
47
-    {
48
-        $this->dataType = $this->getModuleLoader()->getDataType();
49
-    }
50
-
51
-    /**
52
-     * Returns a class instance
53
-     *
54
-     * @return \Fab\Vidi\Module\ModulePidService|object
55
-     */
56
-    static public function getInstance()
57
-    {
58
-        return GeneralUtility::makeInstance(self::class);
59
-    }
60
-
61
-    /**
62
-     * @return bool
63
-     */
64
-    public function isConfiguredPidValid(): bool
65
-    {
66
-        $errors = $this->validateConfiguredPid();
67
-        return empty($errors);
68
-    }
69
-
70
-    /**
71
-     * @return array
72
-     */
73
-    public function validateConfiguredPid(): array
74
-    {
75
-        $configuredPid = $this->getConfiguredNewRecordPid();
76
-        $this->validateRootLevel($configuredPid);
77
-        $this->validatePageExist($configuredPid);
78
-        $this->validateDoktype($configuredPid);
79
-        return $this->errors;
80
-    }
81
-
82
-    /**
83
-     * Return the default configured pid.
84
-     *
85
-     * @return int
86
-     */
87
-    public function getConfiguredNewRecordPid(): int
88
-    {
89
-        if (GeneralUtility::_GP(Parameter::PID)) {
90
-            $configuredPid = (int)GeneralUtility::_GP(Parameter::PID);
91
-        } else {
92
-
93
-            // Get pid from User TSConfig if any.
94
-            $tsConfigPath = sprintf('tx_vidi.dataType.%s.storagePid', $this->dataType);
95
-            $result = $this->getBackendUser()->getTSConfig($tsConfigPath);
96
-            $configuredPid = isset($result['value'])
97
-                ? $configuredPid = (int)$result['value']
98
-                : $this->getModuleLoader()->getDefaultPid();
99
-        }
100
-
101
-        return $configuredPid;
102
-    }
103
-
104
-    /**
105
-     * Check if pid is 0 and given table is allowed on root level.
106
-     *
107
-     * @param int $configuredPid
108
-     * @return void
109
-     */
110
-    protected function validateRootLevel(int $configuredPid): void
111
-    {
112
-        if ($configuredPid > 0) {
113
-            return;
114
-        }
115
-
116
-        $isRootLevel = (bool)Tca::table()->get('rootLevel');
117
-        if (!$isRootLevel) {
118
-            $this->errors[] = sprintf(
119
-                'You are not allowed to use page id "0" unless you set $GLOBALS[\'TCA\'][\'%1$s\'][\'ctrl\'][\'rootLevel\'] = 1;',
120
-                $this->dataType
121
-            );
122
-        }
123
-    }
124
-
125
-    /**
126
-     * Check if a page exists for the configured pid
127
-     *
128
-     * @param int $configuredPid
129
-     * @return void
130
-     */
131
-    protected function validatePageExist(int $configuredPid): void
132
-    {
133
-        if ($configuredPid === 0) {
134
-            return;
135
-        }
136
-
137
-        $page = $this->getPage($configuredPid);
138
-        if (empty($page)) {
139
-            $this->errors[] = sprintf(
140
-                'No page found for the configured page id "%s".',
141
-                $configuredPid
142
-            );
143
-        }
144
-    }
145
-
146
-    /**
147
-     * Check if configured page is a sysfolder and if it is allowed.
148
-     *
149
-     * @param int $configuredPid
150
-     * @return void
151
-     */
152
-    protected function validateDoktype(int $configuredPid): void
153
-    {
154
-        if ($configuredPid === 0) {
155
-            return;
156
-        }
157
-
158
-        $page = $this->getPage($configuredPid);
159
-        if (!empty($page)
160
-            && (int)$page['doktype'] !== PageRepository::DOKTYPE_SYSFOLDER
161
-            && !$this->isTableAllowedOnStandardPages()
162
-            && $this->getModuleLoader()->hasComponentInDocHeader(\Fab\Vidi\View\Button\NewButton::class)) {
163
-            $this->errors[] = sprintf(
164
-                'The page with the id "%s" either has to be of the type "folder" (doktype=254) or the table "%s" has to be allowed on standard pages.',
165
-                $configuredPid,
166
-                $this->dataType
167
-            );
168
-        }
169
-    }
170
-
171
-    /**
172
-     * Check if given table is allowed on standard pages
173
-     *
174
-     * @return bool
175
-     * @see \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::allowTableOnStandardPages()
176
-     */
177
-    protected function isTableAllowedOnStandardPages(): bool
178
-    {
179
-        $allowedTables = explode(',', $GLOBALS['PAGES_TYPES']['default']['allowedTables']);
180
-        return in_array($this->dataType, $allowedTables, true);
181
-    }
182
-
183
-    /**
184
-     * Returns the page record of the configured pid
185
-     *
186
-     * @param int $configuredPid
187
-     * @return array
188
-     */
189
-    protected function getPage(int $configuredPid): ?array
190
-    {
191
-        if ($this->page !== null) {
192
-            return $this->page;
193
-        }
194
-
195
-        $query = $this->getQueryBuilder('pages');
196
-        $query->getRestrictions()->removeAll(); // we are in BE context.
197
-
198
-        $page = $query->select('doktype')
199
-            ->from('pages')
200
-            ->where('deleted = 0',
201
-                'uid = ' . $configuredPid)
202
-            ->execute()
203
-            ->fetch();
204
-
205
-        return is_array($page)
206
-            ? $page
207
-            : [];
208
-    }
209
-
210
-    /**
211
-     * @param string $tableName
212
-     * @return object|QueryBuilder
213
-     */
214
-    protected function getQueryBuilder($tableName): QueryBuilder
215
-    {
216
-        /** @var ConnectionPool $connectionPool */
217
-        $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
218
-        return $connectionPool->getQueryBuilderForTable($tableName);
219
-    }
220
-
221
-    /**
222
-     * Returns an instance of the current Backend User.
223
-     *
224
-     * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
225
-     */
226
-    protected function getBackendUser()
227
-    {
228
-        return $GLOBALS['BE_USER'];
229
-    }
230
-
231
-    /**
232
-     * Get the Vidi Module Loader.
233
-     *
234
-     * @return \Fab\Vidi\Module\ModuleLoader|object
235
-     */
236
-    protected function getModuleLoader()
237
-    {
238
-        return GeneralUtility::makeInstance(\Fab\Vidi\Module\ModuleLoader::class);
239
-    }
22
+	/**
23
+	 * The data type (table)
24
+	 *
25
+	 * @var string
26
+	 */
27
+	protected $dataType = '';
28
+
29
+	/**
30
+	 * The page record of the configured pid
31
+	 *
32
+	 * @var array
33
+	 */
34
+	protected $page = [];
35
+
36
+	/**
37
+	 * A collection of speaking error messages why the pid is invalid.
38
+	 *
39
+	 * @var array
40
+	 */
41
+	protected $errors = [];
42
+
43
+	/**
44
+	 * ModulePidService constructor.
45
+	 */
46
+	public function __construct()
47
+	{
48
+		$this->dataType = $this->getModuleLoader()->getDataType();
49
+	}
50
+
51
+	/**
52
+	 * Returns a class instance
53
+	 *
54
+	 * @return \Fab\Vidi\Module\ModulePidService|object
55
+	 */
56
+	static public function getInstance()
57
+	{
58
+		return GeneralUtility::makeInstance(self::class);
59
+	}
60
+
61
+	/**
62
+	 * @return bool
63
+	 */
64
+	public function isConfiguredPidValid(): bool
65
+	{
66
+		$errors = $this->validateConfiguredPid();
67
+		return empty($errors);
68
+	}
69
+
70
+	/**
71
+	 * @return array
72
+	 */
73
+	public function validateConfiguredPid(): array
74
+	{
75
+		$configuredPid = $this->getConfiguredNewRecordPid();
76
+		$this->validateRootLevel($configuredPid);
77
+		$this->validatePageExist($configuredPid);
78
+		$this->validateDoktype($configuredPid);
79
+		return $this->errors;
80
+	}
81
+
82
+	/**
83
+	 * Return the default configured pid.
84
+	 *
85
+	 * @return int
86
+	 */
87
+	public function getConfiguredNewRecordPid(): int
88
+	{
89
+		if (GeneralUtility::_GP(Parameter::PID)) {
90
+			$configuredPid = (int)GeneralUtility::_GP(Parameter::PID);
91
+		} else {
92
+
93
+			// Get pid from User TSConfig if any.
94
+			$tsConfigPath = sprintf('tx_vidi.dataType.%s.storagePid', $this->dataType);
95
+			$result = $this->getBackendUser()->getTSConfig($tsConfigPath);
96
+			$configuredPid = isset($result['value'])
97
+				? $configuredPid = (int)$result['value']
98
+				: $this->getModuleLoader()->getDefaultPid();
99
+		}
100
+
101
+		return $configuredPid;
102
+	}
103
+
104
+	/**
105
+	 * Check if pid is 0 and given table is allowed on root level.
106
+	 *
107
+	 * @param int $configuredPid
108
+	 * @return void
109
+	 */
110
+	protected function validateRootLevel(int $configuredPid): void
111
+	{
112
+		if ($configuredPid > 0) {
113
+			return;
114
+		}
115
+
116
+		$isRootLevel = (bool)Tca::table()->get('rootLevel');
117
+		if (!$isRootLevel) {
118
+			$this->errors[] = sprintf(
119
+				'You are not allowed to use page id "0" unless you set $GLOBALS[\'TCA\'][\'%1$s\'][\'ctrl\'][\'rootLevel\'] = 1;',
120
+				$this->dataType
121
+			);
122
+		}
123
+	}
124
+
125
+	/**
126
+	 * Check if a page exists for the configured pid
127
+	 *
128
+	 * @param int $configuredPid
129
+	 * @return void
130
+	 */
131
+	protected function validatePageExist(int $configuredPid): void
132
+	{
133
+		if ($configuredPid === 0) {
134
+			return;
135
+		}
136
+
137
+		$page = $this->getPage($configuredPid);
138
+		if (empty($page)) {
139
+			$this->errors[] = sprintf(
140
+				'No page found for the configured page id "%s".',
141
+				$configuredPid
142
+			);
143
+		}
144
+	}
145
+
146
+	/**
147
+	 * Check if configured page is a sysfolder and if it is allowed.
148
+	 *
149
+	 * @param int $configuredPid
150
+	 * @return void
151
+	 */
152
+	protected function validateDoktype(int $configuredPid): void
153
+	{
154
+		if ($configuredPid === 0) {
155
+			return;
156
+		}
157
+
158
+		$page = $this->getPage($configuredPid);
159
+		if (!empty($page)
160
+			&& (int)$page['doktype'] !== PageRepository::DOKTYPE_SYSFOLDER
161
+			&& !$this->isTableAllowedOnStandardPages()
162
+			&& $this->getModuleLoader()->hasComponentInDocHeader(\Fab\Vidi\View\Button\NewButton::class)) {
163
+			$this->errors[] = sprintf(
164
+				'The page with the id "%s" either has to be of the type "folder" (doktype=254) or the table "%s" has to be allowed on standard pages.',
165
+				$configuredPid,
166
+				$this->dataType
167
+			);
168
+		}
169
+	}
170
+
171
+	/**
172
+	 * Check if given table is allowed on standard pages
173
+	 *
174
+	 * @return bool
175
+	 * @see \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::allowTableOnStandardPages()
176
+	 */
177
+	protected function isTableAllowedOnStandardPages(): bool
178
+	{
179
+		$allowedTables = explode(',', $GLOBALS['PAGES_TYPES']['default']['allowedTables']);
180
+		return in_array($this->dataType, $allowedTables, true);
181
+	}
182
+
183
+	/**
184
+	 * Returns the page record of the configured pid
185
+	 *
186
+	 * @param int $configuredPid
187
+	 * @return array
188
+	 */
189
+	protected function getPage(int $configuredPid): ?array
190
+	{
191
+		if ($this->page !== null) {
192
+			return $this->page;
193
+		}
194
+
195
+		$query = $this->getQueryBuilder('pages');
196
+		$query->getRestrictions()->removeAll(); // we are in BE context.
197
+
198
+		$page = $query->select('doktype')
199
+			->from('pages')
200
+			->where('deleted = 0',
201
+				'uid = ' . $configuredPid)
202
+			->execute()
203
+			->fetch();
204
+
205
+		return is_array($page)
206
+			? $page
207
+			: [];
208
+	}
209
+
210
+	/**
211
+	 * @param string $tableName
212
+	 * @return object|QueryBuilder
213
+	 */
214
+	protected function getQueryBuilder($tableName): QueryBuilder
215
+	{
216
+		/** @var ConnectionPool $connectionPool */
217
+		$connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
218
+		return $connectionPool->getQueryBuilderForTable($tableName);
219
+	}
220
+
221
+	/**
222
+	 * Returns an instance of the current Backend User.
223
+	 *
224
+	 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
225
+	 */
226
+	protected function getBackendUser()
227
+	{
228
+		return $GLOBALS['BE_USER'];
229
+	}
230
+
231
+	/**
232
+	 * Get the Vidi Module Loader.
233
+	 *
234
+	 * @return \Fab\Vidi\Module\ModuleLoader|object
235
+	 */
236
+	protected function getModuleLoader()
237
+	{
238
+		return GeneralUtility::makeInstance(\Fab\Vidi\Module\ModuleLoader::class);
239
+	}
240 240
 
241 241
 }
Please login to merge, or discard this patch.
Classes/Module/ModulePreferences.php 1 patch
Indentation   +216 added lines, -216 removed lines patch added patch discarded remove patch
@@ -18,221 +18,221 @@
 block discarded – undo
18 18
 class ModulePreferences implements SingletonInterface
19 19
 {
20 20
 
21
-    /**
22
-     * @var array
23
-     */
24
-    protected $preferences;
25
-
26
-    /**
27
-     * @var string
28
-     */
29
-    protected $tableName = 'tx_vidi_preference';
30
-
31
-    /**
32
-     * @param string $key
33
-     * @param string $dataType
34
-     * @return mixed
35
-     */
36
-    public function get($key, $dataType = '')
37
-    {
38
-
39
-        if (empty($dataType)) {
40
-            $dataType = $this->getModuleLoader()->getDataType();
41
-        }
42
-
43
-        if (!$this->isLoaded($dataType)) {
44
-            $this->load($dataType);
45
-        }
46
-
47
-        $value = empty($this->preferences[$dataType][$key]) ? null : $this->preferences[$dataType][$key];
48
-        return $value;
49
-    }
50
-
51
-    /**
52
-     * Tell whether the module is loaded.
53
-     *
54
-     * @param string $dataType
55
-     * @return bool
56
-     */
57
-    public function isLoaded($dataType)
58
-    {
59
-        return !empty($this->preferences[$dataType]);
60
-    }
61
-
62
-    /**
63
-     * @param string $dataType
64
-     * @return array
65
-     */
66
-    public function getAll($dataType = '')
67
-    {
68
-
69
-        if (empty($dataType)) {
70
-            $dataType = $this->getModuleLoader()->getDataType();
71
-        }
72
-        $this->load($dataType);
73
-        return $this->preferences[$dataType];
74
-    }
75
-
76
-    /**
77
-     * Get the md5 signature of the preferences.
78
-     *
79
-     * @param string $dataType
80
-     * @return bool
81
-     */
82
-    public function getSignature($dataType = '')
83
-    {
84
-        $preferences = $this->getAll($dataType);
85
-        return md5(serialize($preferences));
86
-    }
87
-
88
-    /**
89
-     * Load preferences.
90
-     *
91
-     * @param string $dataType
92
-     * @return void
93
-     */
94
-    public function load($dataType)
95
-    {
96
-
97
-        // Fetch preferences from different sources and overlay them
98
-        $databasePreferences = $this->fetchPreferencesFromDatabase($dataType);
99
-        $generalPreferences = $this->fetchGlobalPreferencesFromTypoScript();
100
-        $specificPreferences = $this->fetchExtraPreferencesFromTypoScript($dataType);
101
-
102
-        $preferences = array_merge($generalPreferences, $specificPreferences, $databasePreferences);
103
-        $this->preferences[$dataType] = $preferences;
104
-    }
105
-
106
-    /**
107
-     * Save preferences
108
-     *
109
-     * @param array $preferences
110
-     * @return void
111
-     */
112
-    public function save($preferences)
113
-    {
114
-        $configurableParts = ConfigurablePart::getParts();
115
-
116
-        $dataType = $this->getModuleLoader()->getDataType();
117
-        $this->getDataService()->delete(
118
-            $this->tableName,
119
-            [
120
-                'data_type' => $dataType
121
-            ]
122
-        );
123
-
124
-        $sanitizedPreferences = [];
125
-        foreach ($preferences as $key => $value) {
126
-            if (in_array($key, $configurableParts)) {
127
-                $sanitizedPreferences[$key] = $value;
128
-            }
129
-        }
130
-
131
-        $this->getDataService()->insert(
132
-            $this->tableName,
133
-            [
134
-                'data_type' => $dataType,
135
-                'preferences' => serialize($sanitizedPreferences),
136
-            ]
137
-        );
138
-    }
139
-
140
-    /**
141
-     * @param $dataType
142
-     * @return array
143
-     */
144
-    public function fetchPreferencesFromDatabase($dataType)
145
-    {
146
-        $preferences = [];
147
-        $record = $this->getDataService()->getRecord(
148
-            $this->tableName,
149
-            [
150
-                'data_type' => $dataType
151
-            ]
152
-        );
153
-
154
-        if (!empty($record)) {
155
-            $preferences = unserialize($record['preferences']);
156
-        }
157
-
158
-        return $preferences;
159
-    }
160
-
161
-    /**
162
-     * Returns the module settings.
163
-     *
164
-     * @return array
165
-     */
166
-    protected function fetchGlobalPreferencesFromTypoScript()
167
-    {
168
-        $settings = $this->getSettings();
169
-
170
-        $configurableParts = ConfigurablePart::getParts();
171
-        $preferences = [];
172
-        foreach ($settings as $key => $value) {
173
-            if (in_array($key, $configurableParts)) {
174
-                $preferences[$key] = $value;
175
-            }
176
-        }
177
-
178
-        return $preferences;
179
-    }
180
-
181
-    /**
182
-     * Returns the module settings.
183
-     *
184
-     * @param string $dataType
185
-     * @return array
186
-     */
187
-    protected function fetchExtraPreferencesFromTypoScript($dataType)
188
-    {
189
-        $generalSettings = $this->getSettings();
190
-
191
-        $preferences = [];
192
-        if (isset($generalSettings[$dataType . '.'])) {
193
-            $settings = $generalSettings[$dataType . '.'];
194
-
195
-            $configurableParts = ConfigurablePart::getParts();
196
-            foreach ($settings as $key => $value) {
197
-                if (in_array($key, $configurableParts)) {
198
-                    $preferences[$key] = $value;
199
-                }
200
-            }
201
-        }
202
-
203
-        return $preferences;
204
-    }
205
-
206
-    /**
207
-     * Returns the module settings.
208
-     *
209
-     * @return array
210
-     */
211
-    protected function getSettings()
212
-    {
213
-        /** @var \TYPO3\CMS\Extbase\Configuration\BackendConfigurationManager $backendConfigurationManager */
214
-        $objectManager = GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Object\ObjectManager::class);
215
-        $backendConfigurationManager = $objectManager->get(\TYPO3\CMS\Extbase\Configuration\BackendConfigurationManager::class);
216
-        $configuration = $backendConfigurationManager->getTypoScriptSetup();
217
-        return $configuration['module.']['tx_vidi.']['settings.'];
218
-    }
219
-
220
-    /**
221
-     * @return object|DataService
222
-     */
223
-    protected function getDataService(): DataService
224
-    {
225
-        return GeneralUtility::makeInstance(DataService::class);
226
-    }
227
-
228
-    /**
229
-     * Get the Vidi Module Loader.
230
-     *
231
-     * @return \Fab\Vidi\Module\ModuleLoader|object
232
-     */
233
-    protected function getModuleLoader()
234
-    {
235
-        return GeneralUtility::makeInstance(\Fab\Vidi\Module\ModuleLoader::class);
236
-    }
21
+	/**
22
+	 * @var array
23
+	 */
24
+	protected $preferences;
25
+
26
+	/**
27
+	 * @var string
28
+	 */
29
+	protected $tableName = 'tx_vidi_preference';
30
+
31
+	/**
32
+	 * @param string $key
33
+	 * @param string $dataType
34
+	 * @return mixed
35
+	 */
36
+	public function get($key, $dataType = '')
37
+	{
38
+
39
+		if (empty($dataType)) {
40
+			$dataType = $this->getModuleLoader()->getDataType();
41
+		}
42
+
43
+		if (!$this->isLoaded($dataType)) {
44
+			$this->load($dataType);
45
+		}
46
+
47
+		$value = empty($this->preferences[$dataType][$key]) ? null : $this->preferences[$dataType][$key];
48
+		return $value;
49
+	}
50
+
51
+	/**
52
+	 * Tell whether the module is loaded.
53
+	 *
54
+	 * @param string $dataType
55
+	 * @return bool
56
+	 */
57
+	public function isLoaded($dataType)
58
+	{
59
+		return !empty($this->preferences[$dataType]);
60
+	}
61
+
62
+	/**
63
+	 * @param string $dataType
64
+	 * @return array
65
+	 */
66
+	public function getAll($dataType = '')
67
+	{
68
+
69
+		if (empty($dataType)) {
70
+			$dataType = $this->getModuleLoader()->getDataType();
71
+		}
72
+		$this->load($dataType);
73
+		return $this->preferences[$dataType];
74
+	}
75
+
76
+	/**
77
+	 * Get the md5 signature of the preferences.
78
+	 *
79
+	 * @param string $dataType
80
+	 * @return bool
81
+	 */
82
+	public function getSignature($dataType = '')
83
+	{
84
+		$preferences = $this->getAll($dataType);
85
+		return md5(serialize($preferences));
86
+	}
87
+
88
+	/**
89
+	 * Load preferences.
90
+	 *
91
+	 * @param string $dataType
92
+	 * @return void
93
+	 */
94
+	public function load($dataType)
95
+	{
96
+
97
+		// Fetch preferences from different sources and overlay them
98
+		$databasePreferences = $this->fetchPreferencesFromDatabase($dataType);
99
+		$generalPreferences = $this->fetchGlobalPreferencesFromTypoScript();
100
+		$specificPreferences = $this->fetchExtraPreferencesFromTypoScript($dataType);
101
+
102
+		$preferences = array_merge($generalPreferences, $specificPreferences, $databasePreferences);
103
+		$this->preferences[$dataType] = $preferences;
104
+	}
105
+
106
+	/**
107
+	 * Save preferences
108
+	 *
109
+	 * @param array $preferences
110
+	 * @return void
111
+	 */
112
+	public function save($preferences)
113
+	{
114
+		$configurableParts = ConfigurablePart::getParts();
115
+
116
+		$dataType = $this->getModuleLoader()->getDataType();
117
+		$this->getDataService()->delete(
118
+			$this->tableName,
119
+			[
120
+				'data_type' => $dataType
121
+			]
122
+		);
123
+
124
+		$sanitizedPreferences = [];
125
+		foreach ($preferences as $key => $value) {
126
+			if (in_array($key, $configurableParts)) {
127
+				$sanitizedPreferences[$key] = $value;
128
+			}
129
+		}
130
+
131
+		$this->getDataService()->insert(
132
+			$this->tableName,
133
+			[
134
+				'data_type' => $dataType,
135
+				'preferences' => serialize($sanitizedPreferences),
136
+			]
137
+		);
138
+	}
139
+
140
+	/**
141
+	 * @param $dataType
142
+	 * @return array
143
+	 */
144
+	public function fetchPreferencesFromDatabase($dataType)
145
+	{
146
+		$preferences = [];
147
+		$record = $this->getDataService()->getRecord(
148
+			$this->tableName,
149
+			[
150
+				'data_type' => $dataType
151
+			]
152
+		);
153
+
154
+		if (!empty($record)) {
155
+			$preferences = unserialize($record['preferences']);
156
+		}
157
+
158
+		return $preferences;
159
+	}
160
+
161
+	/**
162
+	 * Returns the module settings.
163
+	 *
164
+	 * @return array
165
+	 */
166
+	protected function fetchGlobalPreferencesFromTypoScript()
167
+	{
168
+		$settings = $this->getSettings();
169
+
170
+		$configurableParts = ConfigurablePart::getParts();
171
+		$preferences = [];
172
+		foreach ($settings as $key => $value) {
173
+			if (in_array($key, $configurableParts)) {
174
+				$preferences[$key] = $value;
175
+			}
176
+		}
177
+
178
+		return $preferences;
179
+	}
180
+
181
+	/**
182
+	 * Returns the module settings.
183
+	 *
184
+	 * @param string $dataType
185
+	 * @return array
186
+	 */
187
+	protected function fetchExtraPreferencesFromTypoScript($dataType)
188
+	{
189
+		$generalSettings = $this->getSettings();
190
+
191
+		$preferences = [];
192
+		if (isset($generalSettings[$dataType . '.'])) {
193
+			$settings = $generalSettings[$dataType . '.'];
194
+
195
+			$configurableParts = ConfigurablePart::getParts();
196
+			foreach ($settings as $key => $value) {
197
+				if (in_array($key, $configurableParts)) {
198
+					$preferences[$key] = $value;
199
+				}
200
+			}
201
+		}
202
+
203
+		return $preferences;
204
+	}
205
+
206
+	/**
207
+	 * Returns the module settings.
208
+	 *
209
+	 * @return array
210
+	 */
211
+	protected function getSettings()
212
+	{
213
+		/** @var \TYPO3\CMS\Extbase\Configuration\BackendConfigurationManager $backendConfigurationManager */
214
+		$objectManager = GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Object\ObjectManager::class);
215
+		$backendConfigurationManager = $objectManager->get(\TYPO3\CMS\Extbase\Configuration\BackendConfigurationManager::class);
216
+		$configuration = $backendConfigurationManager->getTypoScriptSetup();
217
+		return $configuration['module.']['tx_vidi.']['settings.'];
218
+	}
219
+
220
+	/**
221
+	 * @return object|DataService
222
+	 */
223
+	protected function getDataService(): DataService
224
+	{
225
+		return GeneralUtility::makeInstance(DataService::class);
226
+	}
227
+
228
+	/**
229
+	 * Get the Vidi Module Loader.
230
+	 *
231
+	 * @return \Fab\Vidi\Module\ModuleLoader|object
232
+	 */
233
+	protected function getModuleLoader()
234
+	{
235
+		return GeneralUtility::makeInstance(\Fab\Vidi\Module\ModuleLoader::class);
236
+	}
237 237
 
238 238
 }
Please login to merge, or discard this patch.
Classes/ViewHelpers/Result/AbstractToFormatViewHelper.php 1 patch
Indentation   +158 added lines, -158 removed lines patch added patch discarded remove patch
@@ -23,163 +23,163 @@
 block discarded – undo
23 23
 abstract class AbstractToFormatViewHelper extends AbstractViewHelper
24 24
 {
25 25
 
26
-    /**
27
-     * Store fields of type "file".
28
-     *
29
-     * @var array
30
-     */
31
-    protected $fileTypeProperties = [];
32
-
33
-    /**
34
-     * @var File[]
35
-     */
36
-    protected $collectedFiles = [];
37
-
38
-    /**
39
-     * @var string
40
-     */
41
-    protected $exportFileNameAndPath;
42
-
43
-    /**
44
-     * @var string
45
-     */
46
-    protected $zipFileNameAndPath;
47
-
48
-    /**
49
-     * @var string
50
-     */
51
-    protected $temporaryDirectory;
52
-
53
-
54
-    /**
55
-     * Write the zip file to a temporary location.
56
-     *
57
-     * @return void
58
-     * @throws \RuntimeException
59
-     */
60
-    protected function writeZipFile()
61
-    {
62
-
63
-        $zip = new \ZipArchive();
64
-        $zip->open($this->zipFileNameAndPath, \ZipArchive::CREATE);
65
-
66
-        // Add the CSV content into the zipball.
67
-        $zip->addFile($this->exportFileNameAndPath, basename($this->exportFileNameAndPath));
68
-
69
-        // Add the files into the zipball.
70
-        foreach ($this->collectedFiles as $file) {
71
-            $zip->addFile($file->getForLocalProcessing(false), $file->getIdentifier());
72
-        }
73
-
74
-        $zip->close();
75
-    }
76
-
77
-    /**
78
-     * Initialize some properties
79
-     *
80
-     * @param array $objects
81
-     * @return void
82
-     */
83
-    protected function initializeEnvironment(array $objects)
84
-    {
85
-
86
-        /** @var \Fab\Vidi\Domain\Model\Content $object */
87
-        $object = reset($objects);
88
-
89
-        $this->temporaryDirectory = PATH_site . 'typo3temp/' . uniqid() . '/';
90
-        GeneralUtility::mkdir($this->temporaryDirectory);
91
-
92
-        // Compute file name and path variable
93
-        $this->exportFileNameAndPath = $this->temporaryDirectory . $object->getDataType() . '-' . date($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy']);
94
-
95
-        // Compute file name and path variable for zip
96
-        $zipFileName = $object->getDataType() . '-' . date($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy']) . '.zip';
97
-        $this->zipFileNameAndPath = $this->temporaryDirectory . $zipFileName;
98
-    }
99
-
100
-    /**
101
-     * Fetch the files given an object.
102
-     *
103
-     * @param \Fab\Vidi\Domain\Model\Content $object
104
-     * @return void
105
-     */
106
-    protected function collectFiles(Content $object)
107
-    {
108
-        foreach ($this->fileTypeProperties as $property) {
109
-            $files = FileReferenceService::getInstance()->findReferencedBy($property, $object);
110
-            foreach ($files as $file) {
111
-                $this->collectedFiles[$file->getUid()] = $file;
112
-            }
113
-        }
114
-    }
115
-
116
-    /**
117
-     * Tells whether the object has fields containing files.
118
-     *
119
-     * @return boolean
120
-     */
121
-    protected function hasCollectedFiles()
122
-    {
123
-        return !empty($this->collectedFiles);
124
-    }
125
-
126
-    /**
127
-     * Tells whether the object has fields containing files.
128
-     *
129
-     * @return boolean
130
-     */
131
-    protected function hasFileFields()
132
-    {
133
-        return !empty($this->fileTypeProperties);
134
-    }
135
-
136
-    /**
137
-     * Check whether the given object is meant to include files in some fields.
138
-     *
139
-     * @param Content $object
140
-     * @return void
141
-     * @throws \Fab\Vidi\Exception\NotExistingClassException
142
-     */
143
-    protected function checkWhetherObjectMayIncludeFiles(Content $object)
144
-    {
145
-        if (Tca::grid($object->getDataType())->areFilesIncludedInExport()) {
146
-            foreach ($object->toFields() as $fieldName) {
147
-                $fieldType = Tca::table($object->getDataType())->field($fieldName)->getType();
148
-
149
-                if ($fieldType === FieldType::FILE) {
150
-                    $this->fileTypeProperties[] = GeneralUtility::camelCaseToLowerCaseUnderscored($fieldName);
151
-                }
152
-            }
153
-        }
154
-    }
155
-
156
-    /**
157
-     * @return void
158
-     * @throws \InvalidArgumentException
159
-     * @throws \TYPO3\CMS\Fluid\Core\ViewHelper\Exception\InvalidVariableException
160
-     */
161
-    protected function sendZipHttpHeaders()
162
-    {
163
-        /** @var \TYPO3\CMS\Extbase\Mvc\Web\Response $response */
164
-        $response = $this->templateVariableContainer->get('response');
165
-        $response->setHeader('Pragma', 'public');
166
-        $response->setHeader('Expires', '0');
167
-        $response->setHeader('Cache-Control', 'must-revalidate, post-check=0, pre-check=0');
168
-        $response->setHeader('Content-Type', 'application/zip');
169
-        $response->setHeader('Content-Disposition', 'attachment; filename="' . basename($this->zipFileNameAndPath) . '"');
170
-        $response->setHeader('Content-Length', filesize($this->zipFileNameAndPath));
171
-        $response->setHeader('Content-Description', 'File Transfer');
172
-        $response->setHeader('Content-Transfer-Encoding', 'binary');
173
-
174
-        $response->sendHeaders();
175
-    }
176
-
177
-    /**
178
-     * @return Rows|object
179
-     */
180
-    protected function getRowsView()
181
-    {
182
-        return GeneralUtility::makeInstance(Rows::class);
183
-    }
26
+	/**
27
+	 * Store fields of type "file".
28
+	 *
29
+	 * @var array
30
+	 */
31
+	protected $fileTypeProperties = [];
32
+
33
+	/**
34
+	 * @var File[]
35
+	 */
36
+	protected $collectedFiles = [];
37
+
38
+	/**
39
+	 * @var string
40
+	 */
41
+	protected $exportFileNameAndPath;
42
+
43
+	/**
44
+	 * @var string
45
+	 */
46
+	protected $zipFileNameAndPath;
47
+
48
+	/**
49
+	 * @var string
50
+	 */
51
+	protected $temporaryDirectory;
52
+
53
+
54
+	/**
55
+	 * Write the zip file to a temporary location.
56
+	 *
57
+	 * @return void
58
+	 * @throws \RuntimeException
59
+	 */
60
+	protected function writeZipFile()
61
+	{
62
+
63
+		$zip = new \ZipArchive();
64
+		$zip->open($this->zipFileNameAndPath, \ZipArchive::CREATE);
65
+
66
+		// Add the CSV content into the zipball.
67
+		$zip->addFile($this->exportFileNameAndPath, basename($this->exportFileNameAndPath));
68
+
69
+		// Add the files into the zipball.
70
+		foreach ($this->collectedFiles as $file) {
71
+			$zip->addFile($file->getForLocalProcessing(false), $file->getIdentifier());
72
+		}
73
+
74
+		$zip->close();
75
+	}
76
+
77
+	/**
78
+	 * Initialize some properties
79
+	 *
80
+	 * @param array $objects
81
+	 * @return void
82
+	 */
83
+	protected function initializeEnvironment(array $objects)
84
+	{
85
+
86
+		/** @var \Fab\Vidi\Domain\Model\Content $object */
87
+		$object = reset($objects);
88
+
89
+		$this->temporaryDirectory = PATH_site . 'typo3temp/' . uniqid() . '/';
90
+		GeneralUtility::mkdir($this->temporaryDirectory);
91
+
92
+		// Compute file name and path variable
93
+		$this->exportFileNameAndPath = $this->temporaryDirectory . $object->getDataType() . '-' . date($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy']);
94
+
95
+		// Compute file name and path variable for zip
96
+		$zipFileName = $object->getDataType() . '-' . date($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy']) . '.zip';
97
+		$this->zipFileNameAndPath = $this->temporaryDirectory . $zipFileName;
98
+	}
99
+
100
+	/**
101
+	 * Fetch the files given an object.
102
+	 *
103
+	 * @param \Fab\Vidi\Domain\Model\Content $object
104
+	 * @return void
105
+	 */
106
+	protected function collectFiles(Content $object)
107
+	{
108
+		foreach ($this->fileTypeProperties as $property) {
109
+			$files = FileReferenceService::getInstance()->findReferencedBy($property, $object);
110
+			foreach ($files as $file) {
111
+				$this->collectedFiles[$file->getUid()] = $file;
112
+			}
113
+		}
114
+	}
115
+
116
+	/**
117
+	 * Tells whether the object has fields containing files.
118
+	 *
119
+	 * @return boolean
120
+	 */
121
+	protected function hasCollectedFiles()
122
+	{
123
+		return !empty($this->collectedFiles);
124
+	}
125
+
126
+	/**
127
+	 * Tells whether the object has fields containing files.
128
+	 *
129
+	 * @return boolean
130
+	 */
131
+	protected function hasFileFields()
132
+	{
133
+		return !empty($this->fileTypeProperties);
134
+	}
135
+
136
+	/**
137
+	 * Check whether the given object is meant to include files in some fields.
138
+	 *
139
+	 * @param Content $object
140
+	 * @return void
141
+	 * @throws \Fab\Vidi\Exception\NotExistingClassException
142
+	 */
143
+	protected function checkWhetherObjectMayIncludeFiles(Content $object)
144
+	{
145
+		if (Tca::grid($object->getDataType())->areFilesIncludedInExport()) {
146
+			foreach ($object->toFields() as $fieldName) {
147
+				$fieldType = Tca::table($object->getDataType())->field($fieldName)->getType();
148
+
149
+				if ($fieldType === FieldType::FILE) {
150
+					$this->fileTypeProperties[] = GeneralUtility::camelCaseToLowerCaseUnderscored($fieldName);
151
+				}
152
+			}
153
+		}
154
+	}
155
+
156
+	/**
157
+	 * @return void
158
+	 * @throws \InvalidArgumentException
159
+	 * @throws \TYPO3\CMS\Fluid\Core\ViewHelper\Exception\InvalidVariableException
160
+	 */
161
+	protected function sendZipHttpHeaders()
162
+	{
163
+		/** @var \TYPO3\CMS\Extbase\Mvc\Web\Response $response */
164
+		$response = $this->templateVariableContainer->get('response');
165
+		$response->setHeader('Pragma', 'public');
166
+		$response->setHeader('Expires', '0');
167
+		$response->setHeader('Cache-Control', 'must-revalidate, post-check=0, pre-check=0');
168
+		$response->setHeader('Content-Type', 'application/zip');
169
+		$response->setHeader('Content-Disposition', 'attachment; filename="' . basename($this->zipFileNameAndPath) . '"');
170
+		$response->setHeader('Content-Length', filesize($this->zipFileNameAndPath));
171
+		$response->setHeader('Content-Description', 'File Transfer');
172
+		$response->setHeader('Content-Transfer-Encoding', 'binary');
173
+
174
+		$response->sendHeaders();
175
+	}
176
+
177
+	/**
178
+	 * @return Rows|object
179
+	 */
180
+	protected function getRowsView()
181
+	{
182
+		return GeneralUtility::makeInstance(Rows::class);
183
+	}
184 184
 
185 185
 }
Please login to merge, or discard this patch.