Test Failed
Branch master (7b1793)
by Tymoteusz
36:50 queued 18:38
created

ImageMenuContentObject   B

Complexity

Total Complexity 46

Size/Duplication

Total Lines 218
Duplicated Lines 30.28 %

Importance

Changes 0
Metric Value
dl 66
loc 218
rs 8.3999
c 0
b 0
f 0
wmc 46

3 Methods

Rating   Name   Duplication   Size   Complexity  
A generate() 12 12 3
A writeMenu() 0 16 3
F makeImageMap() 53 162 40

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like ImageMenuContentObject often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ImageMenuContentObject, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace TYPO3\CMS\Frontend\ContentObject\Menu;
3
4
/*
5
 * This file is part of the TYPO3 CMS project.
6
 *
7
 * It is free software; you can redistribute it and/or modify it under
8
 * the terms of the GNU General Public License, either version 2
9
 * of the License, or any later version.
10
 *
11
 * For the full copyright and license information, please read the
12
 * LICENSE.txt file that was distributed with this source code.
13
 *
14
 * The TYPO3 project - inspiring people to share!
15
 */
16
17
use TYPO3\CMS\Core\Utility\ArrayUtility;
18
use TYPO3\CMS\Core\Utility\GeneralUtility;
19
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
20
use TYPO3\CMS\Frontend\Imaging\GifBuilder;
21
22
/**
23
 * ImageMap based menus
24
 */
25
class ImageMenuContentObject extends AbstractMenuContentObject
26
{
27
    /**
28
     * Calls procesItemStates() so that the common configuration for the menu items are resolved into individual configuration per item.
29
     * Calls makeImageMap() to generate the image map image-file
30
     *
31
     * @see AbstractMenuContentObject::procesItemStates(), makeImageMap()
32
     */
33 View Code Duplication
    public function generate()
34
    {
35
        $NOconf = [];
36
        $splitCount = count($this->menuArr);
37
        if ($splitCount) {
38
            list($NOconf) = $this->procesItemStates($splitCount);
39
        }
40
        if (!empty($this->mconf['debugItemConf'])) {
41
            echo '<h3>$NOconf:</h3>';
42
            debug($NOconf);
43
        }
44
        $this->makeImageMap($NOconf);
45
    }
46
47
    /**
48
     * Will traverse input array with configuration per-item and create corresponding GIF files for the menu.
49
     * The data of the files are stored in $this->result
50
     *
51
     * @param array $conf Array with configuration for each item.
52
     * @access private
53
     * @see generate()
54
     */
55
    public function makeImageMap($conf)
56
    {
57
        if (!is_array($conf)) {
58
            $conf = [];
59
        }
60
        if (is_array($this->mconf['main.'])) {
61
            $gifCreator = GeneralUtility::makeInstance(GifBuilder::class);
62
            $gifCreator->init();
63
            $itemsConf = $conf;
64
            $conf = $this->mconf['main.'];
65
            if (is_array($conf)) {
66
                $sKeyArray = ArrayUtility::filterAndSortByNumericKeys($conf);
67
                $gifObjCount = (int)end($sKeyArray);
68
                // Now we add graphical objects to the gifbuilder-setup
69
                $waArr = [];
70
                foreach ($itemsConf as $key => $val) {
71
                    if (is_array($val)) {
72
                        $gifObjCount++;
73
                        $waArr[$key]['free'] = $gifObjCount;
74
                        $sKeyArray = ArrayUtility::filterAndSortByNumericKeys($val);
75
                        foreach ($sKeyArray as $theKey) {
76
                            $theValue = $val[$theKey];
77
                            if ((int)$theKey && ($theValArr = $val[$theKey . '.'])) {
78
                                $cObjData = $this->menuArr[$key] ?: [];
79
                                $gifObjCount++;
80
                                if ($theValue === 'TEXT') {
81
                                    $waArr[$key]['textNum'] = $gifObjCount;
82
                                    $gifCreator->data = $cObjData;
83
                                    $theValArr = $gifCreator->checkTextObj($theValArr);
84
                                    // if this is not done it seems that imageMaps will be rendered wrong!!
85
                                    unset($theValArr['text.']);
86
                                    // check links
87
                                    $LD = $this->menuTypoLink($this->menuArr[$key], $this->mconf['target'], '', '', [], '', $this->mconf['forceTypeValue']);
0 ignored issues
show
Bug introduced by
It seems like $this->mconf['forceTypeValue'] can also be of type array; however, parameter $typeOverride of TYPO3\CMS\Frontend\Conte...tObject::menuTypoLink() does only seem to accept integer|string, 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

87
                                    $LD = $this->menuTypoLink($this->menuArr[$key], $this->mconf['target'], '', '', [], '', /** @scrutinizer ignore-type */ $this->mconf['forceTypeValue']);
Loading history...
Bug introduced by
It seems like $this->mconf['target'] can also be of type array; however, parameter $oTarget of TYPO3\CMS\Frontend\Conte...tObject::menuTypoLink() does only seem to accept string, 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

87
                                    $LD = $this->menuTypoLink($this->menuArr[$key], /** @scrutinizer ignore-type */ $this->mconf['target'], '', '', [], '', $this->mconf['forceTypeValue']);
Loading history...
Bug introduced by
'' of type string is incompatible with the type boolean expected by parameter $no_cache of TYPO3\CMS\Frontend\Conte...tObject::menuTypoLink(). ( Ignorable by Annotation )

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

87
                                    $LD = $this->menuTypoLink($this->menuArr[$key], $this->mconf['target'], /** @scrutinizer ignore-type */ '', '', [], '', $this->mconf['forceTypeValue']);
Loading history...
88
                                    // If access restricted pages should be shown in menus, change the link of such pages to link to a redirection page:
89
                                    $this->changeLinksForAccessRestrictedPages($LD, $this->menuArr[$key], $this->mconf['target'], $this->mconf['forceTypeValue']);
0 ignored issues
show
Bug introduced by
It seems like $this->mconf['target'] can also be of type array; however, parameter $mainTarget of TYPO3\CMS\Frontend\Conte...AccessRestrictedPages() does only seem to accept string, 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

89
                                    $this->changeLinksForAccessRestrictedPages($LD, $this->menuArr[$key], /** @scrutinizer ignore-type */ $this->mconf['target'], $this->mconf['forceTypeValue']);
Loading history...
Bug introduced by
It seems like $this->mconf['forceTypeValue'] can also be of type array; however, parameter $typeOverride of TYPO3\CMS\Frontend\Conte...AccessRestrictedPages() does only seem to accept string, 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

89
                                    $this->changeLinksForAccessRestrictedPages($LD, $this->menuArr[$key], $this->mconf['target'], /** @scrutinizer ignore-type */ $this->mconf['forceTypeValue']);
Loading history...
90
                                    // Overriding URL / Target if set to do so:
91 View Code Duplication
                                    if ($this->menuArr[$key]['_OVERRIDE_HREF']) {
92
                                        $LD['totalURL'] = $this->menuArr[$key]['_OVERRIDE_HREF'];
93
                                        if ($this->menuArr[$key]['_OVERRIDE_TARGET']) {
94
                                            $LD['target'] = $this->menuArr[$key]['_OVERRIDE_TARGET'];
95
                                        }
96
                                    }
97
                                    // Setting target/url for Image Map:
98
                                    if ($theValArr['imgMap.']['url'] === '') {
99
                                        $theValArr['imgMap.']['url'] = $LD['totalURL'];
100
                                    }
101
                                    if ($theValArr['imgMap.']['target'] === '') {
102
                                        $theValArr['imgMap.']['target'] = $LD['target'];
103
                                    }
104 View Code Duplication
                                    if (is_array($theValArr['imgMap.']['altText.'])) {
105
                                        $cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class);
106
                                        $cObj->start($cObjData, 'pages');
107
                                        if (isset($theValArr['imgMap.']['altText.'])) {
108
                                            $theValArr['imgMap.']['altText'] = $cObj->stdWrap($theValArr['imgMap.']['altText'], $theValArr['imgMap.']['altText.']);
109
                                        }
110
                                        unset($theValArr['imgMap.']['altText.']);
111
                                    }
112 View Code Duplication
                                    if (is_array($theValArr['imgMap.']['titleText.'])) {
113
                                        $cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class);
114
                                        $cObj->start($cObjData, 'pages');
115
                                        if (isset($theValArr['imgMap.']['titleText.'])) {
116
                                            $theValArr['imgMap.']['titleText'] = $cObj->stdWrap($theValArr['imgMap.']['titleText'], $theValArr['imgMap.']['titleText.']);
117
                                        }
118
                                        unset($theValArr['imgMap.']['titleText.']);
119
                                    }
120
                                }
121
                                // This code goes one level in if the object is an image. If 'file' and/or 'mask' appears to be GIFBUILDER-objects, they are both searched for TEXT objects, and if a textobj is found, it's checked with the currently loaded record!!
122
                                if ($theValue === 'IMAGE') {
123 View Code Duplication
                                    if ($theValArr['file'] === 'GIFBUILDER') {
124
                                        $temp_sKeyArray = ArrayUtility::filterAndSortByNumericKeys($theValArr['file.']);
125
                                        foreach ($temp_sKeyArray as $temp_theKey) {
126
                                            if ($theValArr['mask.'][$temp_theKey] === 'TEXT') {
127
                                                $gifCreator->data = $this->menuArr[$key] ?: [];
128
                                                $theValArr['mask.'][$temp_theKey . '.'] = $gifCreator->checkTextObj($theValArr['mask.'][$temp_theKey . '.']);
129
                                                // If this is not done it seems that imageMaps will be rendered wrong!!
130
                                                unset($theValArr['mask.'][$temp_theKey . '.']['text.']);
131
                                            }
132
                                        }
133
                                    }
134 View Code Duplication
                                    if ($theValArr['mask'] === 'GIFBUILDER') {
135
                                        $temp_sKeyArray = ArrayUtility::filterAndSortByNumericKeys($theValArr['mask.']);
136
                                        foreach ($temp_sKeyArray as $temp_theKey) {
137
                                            if ($theValArr['mask.'][$temp_theKey] === 'TEXT') {
138
                                                $gifCreator->data = $this->menuArr[$key] ?: [];
139
                                                $theValArr['mask.'][$temp_theKey . '.'] = $gifCreator->checkTextObj($theValArr['mask.'][$temp_theKey . '.']);
140
                                                // if this is not done it seems that imageMaps will be rendered wrong!!
141
                                                unset($theValArr['mask.'][$temp_theKey . '.']['text.']);
142
                                            }
143
                                        }
144
                                    }
145
                                }
146
                                // Checks if disabled is set...
147
                                $setObjFlag = 1;
148 View Code Duplication
                                if ($theValArr['if.']) {
149
                                    /** @var ContentObjectRenderer $cObj */
150
                                    $cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class);
151
                                    $cObj->start($cObjData, 'pages');
152
                                    if (!empty($theValArr['if.']) && !$cObj->checkIf($theValArr['if.'])) {
153
                                        $setObjFlag = 0;
154
                                    }
155
                                    unset($theValArr['if.']);
156
                                }
157
                                // Set the object!
158
                                if ($setObjFlag) {
159
                                    $conf[$gifObjCount] = $theValue;
160
                                    $conf[$gifObjCount . '.'] = $theValArr;
161
                                }
162
                            }
163
                        }
164
                    }
165
                }
166
                $gifCreator->start($conf, $this->getTypoScriptFrontendController()->page);
167
                // calculations
168
                $dConf = [];
169
                foreach ($waArr as $key => $val) {
170
                    if ($dConf[$key] = $itemsConf[$key]['distrib']) {
171
                        $textBB = $gifCreator->objBB[$val['textNum']];
172
                        $dConf[$key] = str_replace(
173
                            ['textX', 'textY'],
174
                            [$textBB[0], $textBB[1]],
175
                            $dConf[$key]
176
                        );
177
                        $dConf[$key] = GeneralUtility::intExplode(',', $gifCreator->calcOffset($dConf[$key]));
178
                    }
179
                }
180
                $workArea = GeneralUtility::intExplode(',', $gifCreator->calcOffset($this->mconf['dWorkArea']));
181
                foreach ($waArr as $key => $val) {
182
                    $index = $val['free'];
183
                    $gifCreator->setup[$index] = 'WORKAREA';
184
                    $workArea[2] = $dConf[$key][2] ?: $dConf[$key][0];
185
                    $workArea[3] = $dConf[$key][3] ?: $dConf[$key][1];
186
                    $gifCreator->setup[$index . '.']['set'] = implode(',', $workArea);
187
                    $workArea[0] += $dConf[$key][0];
188
                    $workArea[1] += $dConf[$key][1];
189
                }
190
                if ($this->mconf['debugRenumberedObject']) {
191
                    echo '<h3>Renumbered GIFBUILDER object:</h3>';
192
                    debug($gifCreator->setup);
193
                }
194
                GeneralUtility::mkdir_deep(PATH_site . 'typo3temp/assets/menu/');
195
                $gifFileName = $gifCreator->fileName('assets/menu/');
196
                // Gets the ImageMap from the cache...
197
                $cache = $this->getCache();
198
                $imgHash = md5($gifFileName);
199
                $imgMap = $cache->get($imgHash);
200
                // File exists
201
                if ($imgMap && file_exists($gifFileName)) {
202
                    $info = @getimagesize($gifFileName);
203
                    $w = $info[0];
204
                    $h = $info[1];
205
                } else {
206
                    // file is generated
207
                    $gifCreator->make();
208
                    $w = $gifCreator->w;
209
                    $h = $gifCreator->h;
210
                    $gifCreator->output($gifFileName);
211
                    $gifCreator->destroy();
212
                    $imgMap = $gifCreator->map;
213
                    $cache->set($imgHash, $imgMap, ['ident_MENUIMAGEMAP'], 0);
214
                }
215
                $imgMap .= $this->mconf['imgMapExtras'];
216
                $this->result = ['output_file' => $gifFileName, 'output_w' => $w, 'output_h' => $h, 'imgMap' => $imgMap];
217
            }
218
        }
219
    }
220
221
    /**
222
     * Returns the HTML for the image map menu.
223
     * If ->result is TRUE it will create the HTML for the image map menu.
224
     *
225
     * @return string The HTML for the menu
226
     */
227
    public function writeMenu()
228
    {
229
        if ($this->result) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->result of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
230
            $res = $this->result;
231
            // shortMD5 260900
232
            $menuName = 'menu_' . GeneralUtility::shortMD5($res['imgMap']);
233
            $result = '<img src="' . $this->getTypoScriptFrontendController()->absRefPrefix . $res['output_file'] . '" width="' . $res['output_w'] . '" height="' . $res['output_h'] . '" usemap="#' . $menuName . '" border="0" ' . $this->mconf['params'];
234
            // Adding alt attribute if not set.
235
            if (!strstr($result, 'alt="')) {
236
                $result .= ' alt="Menu Image Map"';
237
            }
238
            $result .= ' /><map name="' . $menuName . '" id="' . $menuName . '">' . $res['imgMap'] . '</map>';
239
            $this->getTypoScriptFrontendController()->imagesOnPage[] = $res['output_file'];
240
            return $this->WMcObj->wrap($result, $this->mconf['wrap']);
241
        }
242
        return '';
243
    }
244
}
245