Passed
Push — master ( 29ec4f...169eb0 )
by
unknown
17:16
created

SplitButton::render()   C

Complexity

Conditions 12
Paths 192

Size

Total Lines 74
Code Lines 42

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 42
c 0
b 0
f 0
dl 0
loc 74
rs 6.2
cc 12
nc 192
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
3
/*
4
 * This file is part of the TYPO3 CMS project.
5
 *
6
 * It is free software; you can redistribute it and/or modify it under
7
 * the terms of the GNU General Public License, either version 2
8
 * of the License, or any later version.
9
 *
10
 * For the full copyright and license information, please read the
11
 * LICENSE.txt file that was distributed with this source code.
12
 *
13
 * The TYPO3 project - inspiring people to share!
14
 */
15
16
namespace TYPO3\CMS\Backend\Template\Components\Buttons;
17
18
/**
19
 * SplitButton
20
 *
21
 * This button type renders a bootstrap split button.
22
 * It takes multiple button objects as parameters
23
 *
24
 * EXAMPLE USAGE TO ADD A SPLIT BUTTON TO THE FIRST BUTTON GROUP IN THE LEFT BAR:
25
 *
26
 * $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
27
 *
28
 * $saveButton = $buttonBar->makeInputButton()
29
 *      ->setName('save')
30
 *      ->setValue('1')
31
 *      ->setIcon($this->iconFactory->getIcon('actions-document-save', Icon::SIZE_SMALL))
32
 *      ->setTitle('Save');
33
 *
34
 * $saveAndCloseButton = $buttonBar->makeInputButton()
35
 *      ->setName('save_and_close')
36
 *      ->setValue('1')
37
 *      ->setTitle('Save and close')
38
 *      ->setIcon($this->iconFactory->getIcon('actions-document-save-close', Icon::SIZE_SMALL));
39
 *
40
 * $saveAndShowPageButton = $buttonBar->makeInputButton()
41
 *      ->setName('save_and_show')
42
 *      ->setValue('1')
43
 *      ->setTitle('Save and show')
44
 *      ->setIcon($this->iconFactory->getIcon('actions-document-save-view', Icon::SIZE_SMALL));
45
 *
46
 * $splitButtonElement = $buttonBar->makeSplitButton()
47
 *      ->addItem($saveButton, TRUE)
48
 *      ->addItem($saveAndCloseButton)
49
 *      ->addItem($saveAndShowPageButton);
50
 */
51
class SplitButton extends AbstractButton
52
{
53
    /**
54
     * Internal var that determines whether the split button has received any primary
55
     * actions yet
56
     *
57
     * @var bool
58
     */
59
    protected $containsPrimaryAction = false;
60
61
    /**
62
     * Internal array of items in the split button
63
     *
64
     * @var array
65
     */
66
    protected $items = [];
67
68
    /**
69
     * Adds an instance of any button to the split button
70
     *
71
     * @param AbstractButton $item ButtonObject to add
72
     * @param bool $primaryAction Is the button the primary action?
73
     *
74
     * @throws \InvalidArgumentException In case a button is not valid
75
     *
76
     * @return $this
77
     */
78
    public function addItem(AbstractButton $item, $primaryAction = false)
79
    {
80
        if (!$item->isValid()) {
81
            throw new \InvalidArgumentException(
82
                'Only valid items may be assigned to a split Button. "' .
83
                $item->getType() .
84
                '" did not pass validation',
85
                1441706330
86
            );
87
        }
88
        if ($primaryAction && $this->containsPrimaryAction) {
89
            throw new \InvalidArgumentException('A splitButton may only contain one primary action', 1441706340);
90
        }
91
        if ($primaryAction) {
92
            $this->containsPrimaryAction = true;
93
            $this->items['primary'] = clone $item;
94
        } else {
95
            $this->items['options'][] = clone $item;
96
        }
97
        return $this;
98
    }
99
100
    /**
101
     * Returns the current button
102
     *
103
     * @return array
104
     */
105
    public function getButton()
106
    {
107
        if (!isset($this->items['primary']) && isset($this->items['options'])) {
108
            $primaryAction = array_shift($this->items['options']);
109
            $this->items['primary'] = $primaryAction;
110
        }
111
        return $this->items;
112
    }
113
114
    /**
115
     * Validates the current button
116
     *
117
     *
118
     * @return bool
119
     */
120
    public function isValid()
121
    {
122
        $subject = $this->getButton();
123
        return isset($subject['primary'])
124
               && ($subject['primary'] instanceof AbstractButton)
125
               && isset($subject['options']);
126
    }
127
128
    /**
129
     * Renders the HTML markup of the button
130
     *
131
     * @return string
132
     */
133
    public function render()
134
    {
135
        $items = $this->getButton();
136
        $attributes = [
137
            'type' => 'submit',
138
            'class' => 'btn btn-sm btn-default ' . $items['primary']->getClasses(),
139
        ];
140
        if (method_exists($items['primary'], 'getName')) {
141
            $attributes['name'] = $items['primary']->getName();
142
        }
143
        if (method_exists($items['primary'], 'getValue')) {
144
            $attributes['value'] = $items['primary']->getValue();
145
        }
146
        if (!empty($items['primary']->getOnClick())) {
147
            $attributes['onclick'] = $items['primary']->getOnClick();
148
        }
149
        if (method_exists($items['primary'], 'getForm') && !empty($items['primary']->getForm())) {
150
            $attributes['form'] = $items['primary']->getForm();
151
        }
152
        $attributesString = '';
153
        foreach ($attributes as $key => $value) {
154
            $attributesString .= ' ' . htmlspecialchars($key) . '="' . htmlspecialchars($value) . '"';
155
        }
156
        $content = '
157
        <div class="btn-group t3js-splitbutton">
158
            <button' . $attributesString . '>
159
                ' . $items['primary']->getIcon()->render('inline') . '
160
                ' . htmlspecialchars($items['primary']->getTitle()) . '
161
            </button>
162
            <button type="button" class="btn btn-sm btn-default dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
163
                <span class="sr-only">Toggle Dropdown</span>
164
            </button>
165
            <ul class="dropdown-menu">';
166
167
        /** @var AbstractButton $option */
168
        foreach ($items['options'] as $option) {
169
            if ($option instanceof InputButton) {
170
                // if the option is an InputButton we have to create a custom rendering
171
                $optionAttributes = [
172
                    'href' => '#',
173
                    'data-name' => $option->getName(),
174
                    'data-value' => $option->getValue(),
175
                    'data-form' => $option->getForm()
176
                ];
177
178
                if (!empty($option->getClasses())) {
179
                    $optionAttributes['class'] = $option->getClasses();
180
                }
181
                if (!empty($option->getOnClick())) {
182
                    $optionAttributes['onclick'] = $option->getOnClick();
183
                }
184
                $optionAttributes['class'] = implode(' ', [$optionAttributes['class'] ?? '', 'dropdown-item']);
185
                $optionAttributesString = '';
186
                foreach ($optionAttributes as $key => $value) {
187
                    $optionAttributesString .= ' ' . htmlspecialchars($key) . '="' . htmlspecialchars($value) . '"';
188
                }
189
                $html =  '<a' . $optionAttributesString . '>' . $option->getIcon()->render('inline') . ' '
190
                    . htmlspecialchars($option->getTitle()) . '</a>';
191
            } else {
192
                // for any other kind of button we simply use what comes along (e.g. LinkButton)
193
                $html = $option->render();
194
            }
195
196
            $content .= '
197
                <li>
198
                   ' . $html . '
199
                </li>
200
            ';
201
        }
202
        $content .= '
203
            </ul>
204
        </div>
205
        ';
206
        return $content;
207
    }
208
209
    /**
210
     * Magic method so Fluid can access a button via {button}
211
     *
212
     * @return string
213
     */
214
    public function __toString()
215
    {
216
        return $this->render();
217
    }
218
}
219