Passed
Push — refactoring/typo3v10 ( f3523a...0d15b9 )
by Felix
21:30
created

TCA::updateMapping()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 25
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 20
nc 4
nop 5
dl 0
loc 25
rs 9.6
c 0
b 0
f 0
1
<?php
2
namespace Aoe\FeatureFlag\System\Typo3;
3
4
/***************************************************************
5
 *  Copyright notice
6
 *
7
 *  (c) 2021 AOE GmbH <[email protected]>
8
 *
9
 *  All rights reserved
10
 *
11
 *  This script is part of the TYPO3 project. The TYPO3 project is
12
 *  free software; you can redistribute it and/or modify
13
 *  it under the terms of the GNU General Public License as published by
14
 *  the Free Software Foundation; either version 3 of the License, or
15
 *  (at your option) any later version.
16
 *
17
 *  The GNU General Public License can be found at
18
 *  http://www.gnu.org/copyleft/gpl.html.
19
 *
20
 *  This script is distributed in the hope that it will be useful,
21
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
22
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23
 *  GNU General Public License for more details.
24
 *
25
 *  This copyright notice MUST APPEAR in all copies of the script!
26
 ***************************************************************/
27
28
use Aoe\FeatureFlag\Domain\Model\FeatureFlag;
29
use Aoe\FeatureFlag\Domain\Model\Mapping;
30
use Aoe\FeatureFlag\Domain\Repository\FeatureFlagRepository;
31
use Aoe\FeatureFlag\Domain\Repository\MappingRepository;
32
use Aoe\FeatureFlag\Service\Exception\FeatureNotFoundException;
33
use Aoe\FeatureFlag\Service\FeatureFlagService;
34
use TYPO3\CMS\Core\DataHandling\DataHandler;
35
use TYPO3\CMS\Core\Localization\LanguageService;
36
use TYPO3\CMS\Core\Utility\GeneralUtility;
37
use TYPO3\CMS\Extbase\Object\ObjectManager;
38
use TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager;
39
use TYPO3\CMS\Extbase\Persistence\QueryResultInterface;
40
41
class TCA
42
{
43
    /**
44
     * @var string
45
     */
46
    const FIELD_BEHAVIOR = 'tx_featureflag_behavior';
47
48
    /**
49
     * @var string
50
     */
51
    const FIELD_FLAG = 'tx_featureflag_flag';
52
53
    /**
54
     * @var ObjectManager
55
     */
56
    protected $objectManager;
57
58
    /**
59
     * @var PersistenceManager
60
     */
61
    protected $persistenceManager;
62
63
    /**
64
     * @var QueryResultInterface
65
     */
66
    protected static $hashedMappings;
67
68
69
    /**
70
     * @param array $PA
71
     * @return string
72
     */
73
    public function renderSelectForFlag(array $PA)
74
    {
75
        $activeMapping = $this->getMappingRepository()->findOneByForeignTableNameAndUid($PA['row']['uid'], $PA['table']);
76
77
        $html = '';
78
        $html .= '<select class="select" id="' . $PA['itemFormElID'] . '" name="' . $PA['itemFormElName'] . '">';
79
        $html .= '<option value="0"></option>';
80
        foreach ($this->getFeatureFlagRepository()->findAll() as $featureFlag) {
81
            /** @var FeatureFlag $featureFlag */
82
            $selected = '';
83
            if ($activeMapping instanceof Mapping &&
84
                $activeMapping->getFeatureFlag()->getUid() === $featureFlag->getUid()
85
            ) {
86
                $selected = ' selected="selected"';
87
            }
88
            $value = $featureFlag->getUid();
89
            $label = $featureFlag->getDescription();
90
            $html .= '<option value="' . $value . '"' . $selected . '>' . $label . '</option>';
91
        }
92
        $html .= '</select>';
93
94
        return $html;
95
    }
96
97
    /**
98
     * @param array $PA
99
     * @return string
100
     */
101
    public function renderInfo(array $PA)
0 ignored issues
show
Unused Code introduced by
The parameter $PA is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

101
    public function renderInfo(/** @scrutinizer ignore-unused */ array $PA)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
102
    {
103
        $langField = 'LLL:EXT:feature_flag/Resources/Private/Language/locallang_db.xml:tx_featureflag_info.text';
104
        return $this->getLanguageService()->sL($langField);
105
    }
106
107
    /**
108
     * @param array $PA
109
     * @return string
110
     */
111
    public function renderSelectForBehavior(array $PA)
112
    {
113
        // check, which behavior is selected
114
        $isBehaviorHideSelected = false;
115
        $isBehaviorShowSelected = false;
116
        $activeMapping = $this->getMappingRepository()->findOneByForeignTableNameAndUid($PA['row']['uid'], $PA['table']);
117
        if ($activeMapping instanceof Mapping) {
0 ignored issues
show
introduced by
$activeMapping is always a sub-type of Aoe\FeatureFlag\Domain\Model\Mapping.
Loading history...
118
            if ($activeMapping->getBehavior() === FeatureFlagService::BEHAVIOR_HIDE) {
0 ignored issues
show
introduced by
The condition $activeMapping->getBehav...gService::BEHAVIOR_HIDE is always false.
Loading history...
119
                $isBehaviorHideSelected = true;
120
            } elseif ($activeMapping->getBehavior() === FeatureFlagService::BEHAVIOR_SHOW) {
0 ignored issues
show
introduced by
The condition $activeMapping->getBehav...gService::BEHAVIOR_SHOW is always false.
Loading history...
121
                $isBehaviorShowSelected = true;
122
            }
123
        }
124
125
        // build select-box
126
        $html = '';
127
        $html .= '<select class="select" id="' . $PA['itemFormElID'] . '" name="' . $PA['itemFormElName'] . '">';
128
        $html .= '<option value="' . FeatureFlagService::BEHAVIOR_HIDE . '"' . ($isBehaviorHideSelected ? ' selected="selected"' : '') .
0 ignored issues
show
introduced by
The condition $isBehaviorHideSelected is always false.
Loading history...
129
            '>';
130
        $langField = 'LLL:EXT:feature_flag/Resources/Private/Language/locallang_db.xml:tx_featureflag_behavior.hide';
131
        $html .= $this->getLanguageService()->sL($langField);
132
        $html .= '</option>';
133
        $html .= '<option value="' . FeatureFlagService::BEHAVIOR_SHOW . '"' . ($isBehaviorShowSelected ? ' selected="selected"' : '') .
0 ignored issues
show
introduced by
The condition $isBehaviorShowSelected is always false.
Loading history...
134
            '>';
135
        $langField = 'LLL:EXT:feature_flag/Resources/Private/Language/locallang_db.xml:tx_featureflag_behavior.show';
136
        $html .= $this->getLanguageService()->sL($langField);
137
        $html .= '</option>';
138
        $html .= '</select>';
139
140
        return $html;
141
    }
142
143
    /**
144
     * Hook for updates in Typo3 backend
145
     * @param array $incomingFieldArray
146
     * @param string $table
147
     * @param integer $id
148
     * @param DataHandler $tceMain
149
     * @codingStandardsIgnoreStart
150
     */
151
    public function processDatamap_preProcessFieldArray(
152
        &$incomingFieldArray,
153
        $table,
154
        $id,
155
        DataHandler $tceMain
156
    ) {
157
        // @codingStandardsIgnoreEnd
158
        if (
159
            array_key_exists(self::FIELD_BEHAVIOR, $incomingFieldArray) &&
160
            array_key_exists(self::FIELD_FLAG, $incomingFieldArray)
161
        ) {
162
            $pid = $tceMain->getPID($table, $id);
163
            $this->updateMapping($table, $id, $incomingFieldArray[self::FIELD_FLAG], $pid, $incomingFieldArray[self::FIELD_BEHAVIOR]);
0 ignored issues
show
Bug introduced by
It seems like $pid can also be of type false; however, parameter $pid of Aoe\FeatureFlag\System\Typo3\TCA::updateMapping() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

163
            $this->updateMapping($table, $id, $incomingFieldArray[self::FIELD_FLAG], /** @scrutinizer ignore-type */ $pid, $incomingFieldArray[self::FIELD_BEHAVIOR]);
Loading history...
164
            unset($incomingFieldArray[self::FIELD_BEHAVIOR]);
165
            unset($incomingFieldArray[self::FIELD_FLAG]);
166
        }
167
    }
168
169
    /**
170
     * Hook for deletes in Typo3 Backend. It also delete all overwrite protection
171
     * @param string $command
172
     * @param string $table
173
     * @param integer $id
174
     * @codingStandardsIgnoreStart
175
     */
176
    public function processCmdmap_postProcess($command, $table, $id)
177
    {
178
        // @codingStandardsIgnoreEnd
179
        if ($command !== 'delete') {
180
            return;
181
        }
182
        $mappings = $this->getMappingRepository()->findAllByForeignTableNameAndUid($id, $table);
183
        if (false === is_array($mappings) && false === ($mappings instanceof QueryResultInterface)) {
184
            return;
185
        }
186
        foreach ($mappings as $mapping) {
187
            if ($mapping instanceof Mapping) {
188
                $this->getMappingRepository()->remove($mapping);
189
            }
190
        }
191
        $this->getPersistenceManager()->persistAll();
192
    }
193
194
    /**
195
     * @param string $table
196
     * @param array $row
197
     * @param string $status
198
     * @param string $iconName
199
     * @return string
200
     */
201
    public function postOverlayPriorityLookup($table, $row, &$status, $iconName)
0 ignored issues
show
Unused Code introduced by
The parameter $status is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

201
    public function postOverlayPriorityLookup($table, $row, /** @scrutinizer ignore-unused */ &$status, $iconName)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
202
    {
203
        if ($this->isMappingAvailableForTableAndUid($row['uid'], $table)) {
204
            $mapping = $this->getMappingRepository()->findOneByForeignTableNameAndUid($row['uid'], $table);
205
            if ($mapping instanceof Mapping) {
0 ignored issues
show
introduced by
$mapping is always a sub-type of Aoe\FeatureFlag\Domain\Model\Mapping.
Loading history...
206
                if ($row['hidden'] === '1') {
207
                    return 'record-has-feature-flag-which-is-hidden';
208
                }
209
                if ($iconName !== '') {
210
                    // if record is e.g. hidden or protected by FE-group, than show that (e.g. 'hidden' or 'fe_group'-)overlay as default
211
                    return $iconName;
212
                }
213
                return 'record-has-feature-flag-which-is-visible';
214
            }
215
        }
216
217
        // return given icon-name as fall-back
218
        return $iconName;
219
    }
220
221
    /**
222
     * @param string $table
223
     * @param int $id
224
     * @param int $featureFlag
225
     * @param int $pid
226
     * @param string $behavior
227
     */
228
    protected function updateMapping($table, $id, $featureFlag, $pid, $behavior)
229
    {
230
        $mapping = $this->getMappingRepository()->findOneByForeignTableNameAndUid($id, $table);
231
        if ($mapping instanceof Mapping) {
0 ignored issues
show
introduced by
$mapping is always a sub-type of Aoe\FeatureFlag\Domain\Model\Mapping.
Loading history...
232
            if ('0' === $featureFlag) {
0 ignored issues
show
introduced by
The condition '0' === $featureFlag is always false.
Loading history...
233
                $this->getMappingRepository()->remove($mapping);
234
            } else {
235
                $mapping->setFeatureFlag($this->getFeatureFlagByUid($featureFlag));
236
                $mapping->setBehavior($behavior);
237
            }
238
            $mapping->setTstamp(time());
239
            $this->getMappingRepository()->update($mapping);
240
        } elseif ('0' !== $featureFlag) {
241
            /** @var Mapping $mapping */
242
            $mapping = $this->getObjectManager()->get(Mapping::class);
243
            $mapping->setPid($pid);
244
            $mapping->setFeatureFlag($this->getFeatureFlagByUid($featureFlag));
245
            $mapping->setForeignTableName($table);
246
            $mapping->setForeignTableUid($id);
247
            $mapping->setCrdate(time());
248
            $mapping->setTstamp(time());
249
            $mapping->setBehavior($behavior);
250
            $this->getMappingRepository()->add($mapping);
251
        }
252
        $this->getPersistenceManager()->persistAll();
253
    }
254
255
    /**
256
     * @param int $foreignTableUid
257
     * @param string $foreignTableName
258
     * @return bool
259
     */
260
    protected function isMappingAvailableForTableAndUid($foreignTableUid, $foreignTableName)
261
    {
262
        if (null === self::$hashedMappings) {
263
            self::$hashedMappings = $this->getMappingRepository()->getHashedMappings();
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->getMappingReposit...()->getHashedMappings() of type array or array is incompatible with the declared type TYPO3\CMS\Extbase\Persistence\QueryResultInterface of property $hashedMappings.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
264
        }
265
        $identifier = sha1($foreignTableUid . '_' . $foreignTableName);
266
        if (array_key_exists($identifier, self::$hashedMappings)) {
0 ignored issues
show
Bug introduced by
It seems like self::hashedMappings can also be of type TYPO3\CMS\Extbase\Persistence\QueryResultInterface; however, parameter $array of array_key_exists() does only seem to accept ArrayObject|array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

266
        if (array_key_exists($identifier, /** @scrutinizer ignore-type */ self::$hashedMappings)) {
Loading history...
267
            return true;
268
        }
269
270
        return false;
271
    }
272
273
    /**
274
     * @param int $uid
275
     * @return FeatureFlag
276
     * @throws FeatureNotFoundException
277
     */
278
    protected function getFeatureFlagByUid($uid)
279
    {
280
        /** @var FeatureFlag $featureFlag */
281
        $featureFlag = $this->getFeatureFlagRepository()->findByUid($uid);
282
        if (false === ($featureFlag instanceof FeatureFlag)) {
283
            throw new FeatureNotFoundException(
284
                'Feature Flag not found by uid: "' . $uid . '"',
285
                1384340431
286
            );
287
        }
288
289
        return $featureFlag;
290
    }
291
292
    /**
293
     * @return MappingRepository
294
     */
295
    protected function getMappingRepository()
296
    {
297
        return $this->getObjectManager()->get(MappingRepository::class);
0 ignored issues
show
Deprecated Code introduced by
The function TYPO3\CMS\Extbase\Object\ObjectManager::get() has been deprecated: since TYPO3 10.4, will be removed in version 12.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

297
        return /** @scrutinizer ignore-deprecated */ $this->getObjectManager()->get(MappingRepository::class);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
298
    }
299
300
    /**
301
     * @return FeatureFlagRepository
302
     */
303
    protected function getFeatureFlagRepository()
304
    {
305
        return $this->getObjectManager()->get(FeatureFlagRepository::class);
0 ignored issues
show
Deprecated Code introduced by
The function TYPO3\CMS\Extbase\Object\ObjectManager::get() has been deprecated: since TYPO3 10.4, will be removed in version 12.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

305
        return /** @scrutinizer ignore-deprecated */ $this->getObjectManager()->get(FeatureFlagRepository::class);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
306
    }
307
308
    /**
309
     * @return ObjectManager
310
     */
311
    protected function getObjectManager()
312
    {
313
        if (false === ($this->objectManager instanceof ObjectManager)) {
314
            $this->objectManager = GeneralUtility::makeInstance(ObjectManager::class);
315
        }
316
317
        return $this->objectManager;
318
    }
319
320
    /**
321
     * @return PersistenceManager
322
     */
323
    protected function getPersistenceManager()
324
    {
325
        if (false === $this->persistenceManager instanceof PersistenceManager) {
326
            $this->persistenceManager = $this->getObjectManager()->get(PersistenceManager::class);
0 ignored issues
show
Deprecated Code introduced by
The function TYPO3\CMS\Extbase\Object\ObjectManager::get() has been deprecated: since TYPO3 10.4, will be removed in version 12.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

326
            $this->persistenceManager = /** @scrutinizer ignore-deprecated */ $this->getObjectManager()->get(PersistenceManager::class);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
327
        }
328
329
        return $this->persistenceManager;
330
    }
331
332
    /**
333
     * @return LanguageService
334
     */
335
    protected function getLanguageService()
336
    {
337
        return $GLOBALS['LANG'];
338
    }
339
}
340