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

TextMenuContentObject::writeMenu()   F

Complexity

Conditions 25
Paths > 20000

Size

Total Lines 117
Code Lines 82

Duplication

Lines 20
Ratio 17.09 %

Importance

Changes 0
Metric Value
dl 20
loc 117
rs 2
c 0
b 0
f 0
cc 25
eloc 82
nc 393218
nop 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
use TYPO3\CMS\Core\TypoScript\TypoScriptService;
17
use TYPO3\CMS\Core\Utility\GeneralUtility;
18
19
/**
20
 * Extension class creating text based menus
21
 */
22
class TextMenuContentObject extends AbstractMenuContentObject
23
{
24
    /**
25
     * Calls procesItemStates() so that the common configuration for the menu items are resolved into individual configuration per item.
26
     * Sets the result for the new "normal state" in $this->result
27
     *
28
     * @see AbstractMenuContentObject::procesItemStates()
29
     */
30 View Code Duplication
    public function generate()
31
    {
32
        $NOconf = [];
33
        $splitCount = count($this->menuArr);
34
        if ($splitCount) {
35
            list($NOconf) = $this->procesItemStates($splitCount);
36
        }
37
        if (!empty($this->mconf['debugItemConf'])) {
38
            echo '<h3>$NOconf:</h3>';
39
            debug($NOconf);
40
        }
41
        $this->result = $NOconf;
42
    }
43
44
    /**
45
     * Traverses the ->result array of menu items configuration (made by ->generate()) and renders each item.
46
     * During the execution of this function many internal methods prefixed "extProc_" from this class is called and
47
     * many of these are for now dummy functions.
48
     * An instance of ContentObjectRenderer is also made and for each menu item rendered it is loaded with
49
     * the record for that page so that any stdWrap properties that applies will have the current menu items record available.
50
     *
51
     * @return string The HTML for the menu (returns result through $this->extProc_finish(); )
52
     */
53
    public function writeMenu()
54
    {
55
        if (empty($this->result)) {
56
            return '';
57
        }
58
59
        $this->WMresult = '';
60
        $this->INPfixMD5 = substr(md5(microtime() . 'tmenu'), 0, 4);
0 ignored issues
show
Documentation Bug introduced by
It seems like substr(md5(microtime() . 'tmenu'), 0, 4) can also be of type false. However, the property $INPfixMD5 is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
61
        $this->WMmenuItems = count($this->result);
62
        $typoScriptService = GeneralUtility::makeInstance(TypoScriptService::class);
63
        $this->WMsubmenuObjSuffixes = $typoScriptService->explodeConfigurationForOptionSplit(['sOSuffix' => $this->mconf['submenuObjSuffixes']], $this->WMmenuItems);
64
        $this->extProc_init();
65
        foreach ($this->result as $key => $val) {
66
            $GLOBALS['TSFE']->register['count_HMENU_MENUOBJ']++;
67
            $GLOBALS['TSFE']->register['count_MENUOBJ']++;
68
            // Initialize the cObj with the page record of the menu item
69
            $this->WMcObj->start($this->menuArr[$key], 'pages');
70
            $this->I = [];
71
            $this->I['key'] = $key;
72
            $this->I['INPfix'] = ($this->imgNameNotRandom ? '' : '_' . $this->INPfixMD5) . '_' . $key;
0 ignored issues
show
Bug introduced by
Are you sure $this->INPfixMD5 of type false|string can be used in concatenation? ( Ignorable by Annotation )

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

72
            $this->I['INPfix'] = ($this->imgNameNotRandom ? '' : '_' . /** @scrutinizer ignore-type */ $this->INPfixMD5) . '_' . $key;
Loading history...
73
            $this->I['val'] = $val;
74
            $this->I['title'] = isset($this->I['val']['stdWrap.']) ? $this->WMcObj->stdWrap($this->getPageTitle($this->menuArr[$key]['title'], $this->menuArr[$key]['nav_title']), $this->I['val']['stdWrap.']) : $this->getPageTitle($this->menuArr[$key]['title'], $this->menuArr[$key]['nav_title']);
75
            $this->I['uid'] = $this->menuArr[$key]['uid'];
76
            $this->I['mount_pid'] = $this->menuArr[$key]['mount_pid'];
77
            $this->I['pid'] = $this->menuArr[$key]['pid'];
78
            $this->I['spacer'] = $this->menuArr[$key]['isSpacer'];
79
            // Set access key
80 View Code Duplication
            if ($this->mconf['accessKey']) {
81
                $this->I['accessKey'] = $this->accessKey($this->I['title']);
82
            } else {
83
                $this->I['accessKey'] = [];
84
            }
85
            // Make link tag
86
            $this->I['val']['ATagParams'] = $this->WMcObj->getATagParams($this->I['val']);
87 View Code Duplication
            if (isset($this->I['val']['additionalParams.'])) {
88
                $this->I['val']['additionalParams'] = $this->WMcObj->stdWrap($this->I['val']['additionalParams'], $this->I['val']['additionalParams.']);
89
            }
90
            $this->I['linkHREF'] = $this->link($key, $this->I['val']['altTarget'], $this->mconf['forceTypeValue']);
91
            if (empty($this->I['linkHREF'])) {
92
                $this->I['val']['doNotLinkIt'] = 1;
93
            }
94
            // Title attribute of links:
95
            $titleAttrValue = isset($this->I['val']['ATagTitle.']) ? $this->WMcObj->stdWrap($this->I['val']['ATagTitle'], $this->I['val']['ATagTitle.']) . $this->I['accessKey']['alt'] : $this->I['val']['ATagTitle'] . $this->I['accessKey']['alt'];
96
            if ($titleAttrValue !== '') {
97
                $this->I['linkHREF']['title'] = $titleAttrValue;
98
            }
99
100
            // Calling extra processing function
101
            $this->extProc_beforeLinking($key);
102
            // stdWrap for doNotLinkIt
103 View Code Duplication
            if (isset($this->I['val']['doNotLinkIt.'])) {
104
                $this->I['val']['doNotLinkIt'] = $this->WMcObj->stdWrap($this->I['val']['doNotLinkIt'], $this->I['val']['doNotLinkIt.']);
105
            }
106
            // Compile link tag
107
            if (!$this->I['val']['doNotLinkIt']) {
108
                $this->I['val']['doNotLinkIt'] = 0;
109
            }
110
            if (!$this->I['spacer'] && $this->I['val']['doNotLinkIt'] != 1) {
111
                $this->setATagParts();
112
            } else {
113
                $this->I['A1'] = '';
114
                $this->I['A2'] = '';
115
            }
116
            // ATagBeforeWrap processing:
117
            if ($this->I['val']['ATagBeforeWrap']) {
118
                $wrapPartsBefore = explode('|', $this->I['val']['linkWrap']);
119
                $wrapPartsAfter = ['', ''];
120
            } else {
121
                $wrapPartsBefore = ['', ''];
122
                $wrapPartsAfter = explode('|', $this->I['val']['linkWrap']);
123
            }
124
            if ($this->I['val']['stdWrap2'] || isset($this->I['val']['stdWrap2.'])) {
125
                $stdWrap2 = isset($this->I['val']['stdWrap2.']) ? $this->WMcObj->stdWrap('|', $this->I['val']['stdWrap2.']) : '|';
126
                $wrapPartsStdWrap = explode($this->I['val']['stdWrap2'] ? $this->I['val']['stdWrap2'] : '|', $stdWrap2);
127
            } else {
128
                $wrapPartsStdWrap = ['', ''];
129
            }
130
            // Make before, middle and after parts
131
            $this->I['parts'] = [];
132
            $this->I['parts']['before'] = $this->getBeforeAfter('before');
133
            $this->I['parts']['stdWrap2_begin'] = $wrapPartsStdWrap[0];
134
            // stdWrap for doNotShowLink
135 View Code Duplication
            if (isset($this->I['val']['doNotShowLink.'])) {
136
                $this->I['val']['doNotShowLink'] = $this->WMcObj->stdWrap($this->I['val']['doNotShowLink'], $this->I['val']['doNotShowLink.']);
137
            }
138
            if (!$this->I['val']['doNotShowLink']) {
139
                $this->I['parts']['notATagBeforeWrap_begin'] = $wrapPartsAfter[0];
140
                $this->I['parts']['ATag_begin'] = $this->I['A1'];
141
                $this->I['parts']['ATagBeforeWrap_begin'] = $wrapPartsBefore[0];
142
                $this->I['parts']['title'] = $this->I['title'];
143
                $this->I['parts']['ATagBeforeWrap_end'] = $wrapPartsBefore[1];
144
                $this->I['parts']['ATag_end'] = $this->I['A2'];
145
                $this->I['parts']['notATagBeforeWrap_end'] = $wrapPartsAfter[1];
146
            }
147
            $this->I['parts']['stdWrap2_end'] = $wrapPartsStdWrap[1];
148
            $this->I['parts']['after'] = $this->getBeforeAfter('after');
149
            // Passing I to a user function
150
            if ($this->mconf['IProcFunc']) {
151
                $this->I = $this->userProcess('IProcFunc', $this->I);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->userProcess('IProcFunc', $this->I) can also be of type string. However, the property $I is declared as type array<mixed,mixed>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
152
            }
153
            // Merge parts + beforeAllWrap
154
            $this->I['theItem'] = implode('', $this->I['parts']);
155
            $this->I['theItem'] = $this->extProc_beforeAllWrap($this->I['theItem'], $key);
156
            // allWrap:
157
            $allWrap = isset($this->I['val']['allWrap.']) ? $this->WMcObj->stdWrap($this->I['val']['allWrap'], $this->I['val']['allWrap.']) : $this->I['val']['allWrap'];
158
            $this->I['theItem'] = $this->WMcObj->wrap($this->I['theItem'], $allWrap);
159 View Code Duplication
            if ($this->I['val']['subst_elementUid']) {
160
                $this->I['theItem'] = str_replace('{elementUid}', $this->I['uid'], $this->I['theItem']);
161
            }
162
            // allStdWrap:
163 View Code Duplication
            if (is_array($this->I['val']['allStdWrap.'])) {
164
                $this->I['theItem'] = $this->WMcObj->stdWrap($this->I['theItem'], $this->I['val']['allStdWrap.']);
165
            }
166
            // Calling extra processing function
167
            $this->extProc_afterLinking($key);
168
        }
169
        return $this->extProc_finish();
170
    }
171
172
    /**
173
     * Generates the before* and after* images for TMENUs
174
     *
175
     * @param string $pref Can be "before" or "after" and determines which kind of image to create (basically this is the prefix of the TypoScript properties that are read from the ->I['val'] array
176
     * @return string The resulting HTML of the image, if any.
177
     */
178
    public function getBeforeAfter($pref)
179
    {
180
        $res = '';
181
        if ($imgInfo = $this->WMcObj->getImgResource($this->I['val'][$pref . 'Img'], $this->I['val'][$pref . 'Img.'])) {
182
            $theName = $this->imgNamePrefix . $this->I['uid'] . $this->I['INPfix'] . $pref;
183
            $name = ' ' . $this->nameAttribute . '="' . $theName . '"';
184
            $GLOBALS['TSFE']->imagesOnPage[] = $imgInfo[3];
185
            $res = '<img' . ' src="' . $GLOBALS['TSFE']->absRefPrefix . $imgInfo[3] . '"' . ' width="' . $imgInfo[0] . '"' . ' height="' . $imgInfo[1] . '"' . $name . ($this->I['val'][$pref . 'ImgTagParams'] ? ' ' . $this->I['val'][$pref . 'ImgTagParams'] : '') . $this->parent_cObj->getBorderAttr(' border="0"');
186
            if (!strstr($res, 'alt="')) {
187
                // Adding alt attribute if not set.
188
                $res .= ' alt=""';
189
            }
190
            $res .= ' />';
191
            if ($this->I['val'][$pref . 'ImgLink']) {
192
                $res = $this->I['A1'] . $res . $this->I['A2'];
193
            }
194
        }
195
        $processedPref = isset($this->I['val'][$pref . '.']) ? $this->WMcObj->stdWrap($this->I['val'][$pref], $this->I['val'][$pref . '.']) : $this->I['val'][$pref];
196
        if (isset($this->I['val'][$pref . 'Wrap'])) {
197
            return $this->WMcObj->wrap($res . $processedPref, $this->I['val'][$pref . 'Wrap']);
198
        }
199
        return $res . $processedPref;
200
    }
201
202
    /**
203
     * Called right before the traversing of $this->result begins.
204
     * Can be used for various initialization
205
     *
206
     * @access private
207
     * @see writeMenu()
208
     */
209
    public function extProc_init()
210
    {
211
    }
212
213
    /**
214
     * Called right before the creation of the link for the menu item
215
     *
216
     * @param int $key Pointer to $this->menuArr[$key] where the current menu element record is found
217
     * @access private
218
     * @see writeMenu()
219
     */
220
    public function extProc_beforeLinking($key)
0 ignored issues
show
Unused Code introduced by
The parameter $key 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

220
    public function extProc_beforeLinking(/** @scrutinizer ignore-unused */ $key)

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...
221
    {
222
    }
223
224
    /**
225
     * Called right after the creation of links for the menu item. This is also the last function call before the while-loop traversing menu items goes to the next item.
226
     * This function MUST set $this->WMresult.=[HTML for menu item] to add the generated menu item to the internal accumulation of items.
227
     *
228
     * @param int $key Pointer to $this->menuArr[$key] where the current menu element record is found
229
     * @access private
230
     * @see writeMenu()
231
     */
232 View Code Duplication
    public function extProc_afterLinking($key)
233
    {
234
        // Add part to the accumulated result + fetch submenus
235
        if (!$this->I['spacer']) {
236
            $this->I['theItem'] .= $this->subMenu($this->I['uid'], $this->WMsubmenuObjSuffixes[$key]['sOSuffix']);
237
        }
238
        $part = isset($this->I['val']['wrapItemAndSub.']) ? $this->WMcObj->stdWrap($this->I['val']['wrapItemAndSub'], $this->I['val']['wrapItemAndSub.']) : $this->I['val']['wrapItemAndSub'];
239
        $this->WMresult .= $part ? $this->WMcObj->wrap($this->I['theItem'], $part) : $this->I['theItem'];
240
    }
241
242
    /**
243
     * Called before the "allWrap" happens on the menu item.
244
     *
245
     * @param string $item The current content of the menu item, $this->I['theItem'], passed along.
246
     * @param int $key Pointer to $this->menuArr[$key] where the current menu element record is found
247
     * @return string The modified version of $item, going back into $this->I['theItem']
248
     * @access private
249
     * @see writeMenu()
250
     */
251
    public function extProc_beforeAllWrap($item, $key)
0 ignored issues
show
Unused Code introduced by
The parameter $key 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

251
    public function extProc_beforeAllWrap($item, /** @scrutinizer ignore-unused */ $key)

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...
252
    {
253
        return $item;
254
    }
255
256
    /**
257
     * Called before the writeMenu() function returns (only if a menu was generated)
258
     *
259
     * @return string The total menu content should be returned by this function
260
     * @access private
261
     * @see writeMenu()
262
     */
263 View Code Duplication
    public function extProc_finish()
264
    {
265
        // stdWrap:
266
        if (is_array($this->mconf['stdWrap.'])) {
267
            $this->WMresult = $this->WMcObj->stdWrap($this->WMresult, $this->mconf['stdWrap.']);
268
        }
269
        return $this->WMcObj->wrap($this->WMresult, $this->mconf['wrap']) . $this->WMextraScript;
270
    }
271
}
272