Total Complexity | 48 |
Total Lines | 344 |
Duplicated Lines | 0 % |
Changes | 13 | ||
Bugs | 0 | Features | 0 |
Complex classes like Card 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 Card, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
50 | class Card extends Widget |
||
51 | { |
||
52 | /** |
||
53 | * @var bool whether to HTML-encode the link labels and card title |
||
54 | */ |
||
55 | public $encodeLabels = true; |
||
56 | |||
57 | /** |
||
58 | * @var array a list of attributes to be displayed in the card content tag. Item should be an array |
||
59 | * of the following structure: |
||
60 | * - title: string, title for the card image. Value will be HTML-encoded. |
||
61 | * You can change this, by setting extra attribute ["encode" => false] in "titleOptions" attribute |
||
62 | * - value: string, the HTML content for the card body. It will NOT be HTML-encoded. |
||
63 | * Therefore you can pass in HTML code. If this is coming from end users, |
||
64 | * you should consider encode() it to prevent XSS attacks. |
||
65 | * - options: array, the HTML attributes for the card content tag. |
||
66 | * - titleOptions: array the HTML attributes for the title tag. You can specify 'icon' attribute |
||
67 | * (name for the icon), if you want to add icon to the right side of the title. |
||
68 | */ |
||
69 | public $content = []; |
||
70 | |||
71 | /** |
||
72 | * @var array a list of attributes to be displayed in the card image tag. Item should be an array |
||
73 | * of the following structure: |
||
74 | * - title: string, title for the card image. Value will be HTML-encoded. |
||
75 | * You can change this, by setting extra attribute ["encode" => false] in "titleOptions" attribute |
||
76 | * - url: string the image URL. This parameter will be processed by [[Url::to()]]. |
||
77 | * - fab: array list of attributes for floating action button. Value will be passed to [[Button]] widget. |
||
78 | * You can set extra param 'url' to render it as link. |
||
79 | * - options: array, the HTML attributes for the card image tag. |
||
80 | * - titleOptions: array the HTML attributes for the title tag. You can specify 'icon' attribute |
||
81 | * (name for the icon), if you want to add icon to the right side of the title. |
||
82 | * - imageOptions: array the HTML attributes for the image tag. |
||
83 | */ |
||
84 | public $image = []; |
||
85 | |||
86 | /** |
||
87 | * @var array list of card action items. Each action item should be an array of the following structure: |
||
88 | * - label: string, specifies the action item label. When [[encodeLabels]] is true, the label |
||
89 | * will be HTML-encoded. |
||
90 | * - encode: boolean, optional, whether this item`s label should be HTML-encoded. This param will override |
||
91 | * global [[encodeLabels]] param. |
||
92 | * - url: string or array, optional, specifies the URL of the action item. It will be processed by [[Url::to]]. |
||
93 | * - icon: string or array, optional, icon name or array with 'name' and 'options'. |
||
94 | * - options: array, optional, the HTML attributes for the action container tag. |
||
95 | */ |
||
96 | public $actions = []; |
||
97 | |||
98 | /** |
||
99 | * @var array the HTML attributes for the action wrapper tag of the card view. |
||
100 | * You can use attribute "sticky" to change, whether card actions must be always visible. |
||
101 | * Default value is false. |
||
102 | * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. |
||
103 | */ |
||
104 | public $actionOptions = []; |
||
105 | |||
106 | /** |
||
107 | * @var array a list of attributes to be displayed in the card reveal tag. Item should be an array |
||
108 | * of the following structure: |
||
109 | * - title: string, title for the card image. Value will be HTML-encoded. |
||
110 | * You can change this, by setting extra attribute ["encode" => false] in "titleOptions" attribute |
||
111 | * - value: string, the HTML content for the card body. It will NOT be HTML-encoded. |
||
112 | * Therefore you can pass in HTML code. If this is coming from end users, |
||
113 | * you should consider encode() it to prevent XSS attacks. |
||
114 | * - options: array, the HTML attributes for the card content tag. |
||
115 | * - titleOptions: array the HTML attributes for the title tag. You can specify 'icon' attribute |
||
116 | * (name for the icon), if you want to add icon to the right side of the title. |
||
117 | */ |
||
118 | public $reveal = []; |
||
119 | |||
120 | /** |
||
121 | * @var bool whether image should be on left side. Default value is false |
||
122 | */ |
||
123 | public $horizontal = false; |
||
124 | |||
125 | /** |
||
126 | * @var bool whether card should be spaced as panel. Default value is false. |
||
127 | * Use this for a simpler card with less markup, because it has only padding and a shadow effect. |
||
128 | */ |
||
129 | public $panel = false; |
||
130 | |||
131 | /** |
||
132 | * @var Tabs the class for tab content creation |
||
133 | * @see \dmgpage\yii2materialize\widgets\Tabs for details on how content are being rendered. |
||
134 | */ |
||
135 | public $tabs; |
||
136 | |||
137 | /** |
||
138 | * Initializes the widget. |
||
139 | * @return void |
||
140 | */ |
||
141 | public function init() |
||
142 | { |
||
143 | parent::init(); |
||
144 | |||
145 | $contentData = $this->content; |
||
146 | $cardContentOptions = isset($this->content['options']) ? $this->content['options'] : []; |
||
147 | Html::addCssClass($cardContentOptions, ['class' => 'card-content']); |
||
148 | $this->setCardClass(); // set main css classes to card tag |
||
149 | |||
150 | $html = Html::beginTag('div', $this->options); |
||
151 | $html .= $this->renderImageContent(); |
||
152 | |||
153 | // Create stacked content, if horizontal attribute is true |
||
154 | if ($this->horizontal) { |
||
155 | $html .= Html::beginTag('div', ['class' => 'card-stacked']); |
||
156 | } |
||
157 | |||
158 | // Add reviel button to content title, if reveal attribute is not empty |
||
159 | if (!empty($this->reveal)) { |
||
160 | Html::addCssClass($contentData['titleOptions'], 'activator'); |
||
161 | $addIcon = !isset($contentData['titleOptions']['icon']); |
||
162 | $contentData['titleOptions']['icon'] = $addIcon |
||
163 | ? 'more_vert' |
||
164 | : $contentData['titleOptions']['icon']; |
||
165 | } |
||
166 | |||
167 | // Create card content, if panel not true |
||
168 | if (!$this->panel) { |
||
169 | $html .= Html::beginTag('div', $cardContentOptions); |
||
170 | } |
||
171 | |||
172 | // Validate tab attribute |
||
173 | if ($this->tabs && !$this->tabs instanceof Tabs) { |
||
|
|||
174 | throw new InvalidConfigException('"' . get_class($this) . '::$tabs" should be an instance of "\dmgpage\yii2materialize\widgets\Tabs".'); |
||
175 | } |
||
176 | |||
177 | $html .= $this->renderTitleContent($contentData); |
||
178 | |||
179 | echo $html; |
||
180 | } |
||
181 | |||
182 | /** |
||
183 | * Renders the widget. |
||
184 | * @return void |
||
185 | */ |
||
186 | public function run() |
||
187 | { |
||
188 | $this->registerPlugin('card'); |
||
189 | |||
190 | $html = isset($this->content['value']) ? $this->content['value'] : ''; |
||
191 | |||
192 | if (!$this->panel) { |
||
193 | $html .= Html::endTag('div'); // ends card-content tag |
||
194 | } |
||
195 | |||
196 | if (!empty($this->actions)) { |
||
197 | Html::addCssClass($this->actionOptions, ['class' => 'card-action']); |
||
198 | $html .= Html::beginTag('div', $this->actionOptions); |
||
199 | |||
200 | foreach ($this->actions as $action) { |
||
201 | $html .= $this->renderActionItem($action); |
||
202 | } |
||
203 | |||
204 | $html .= Html::endTag('div'); |
||
205 | } |
||
206 | |||
207 | if ($this->horizontal) { |
||
208 | $html .= Html::endTag('div'); //ends card-stacked tag |
||
209 | } |
||
210 | |||
211 | if ($this->tabs) { |
||
212 | $html .= $this->renderTabsItem(); |
||
213 | } |
||
214 | |||
215 | // Add card reveal tag |
||
216 | $html .= $this->renderRevealContent(); |
||
217 | $html .= Html::endTag('div'); //ends card tag |
||
218 | |||
219 | echo $html; |
||
220 | } |
||
221 | |||
222 | /** |
||
223 | * Sets card CSS class (or several classes) to the card options. |
||
224 | * @return void |
||
225 | */ |
||
226 | protected function setCardClass() |
||
227 | { |
||
228 | $useStickyActions = isset($this->actionOptions['sticky']) ? $this->actionOptions['sticky'] : false; |
||
229 | |||
230 | if ($this->panel) { |
||
231 | Html::addCssClass($this->options, ['card-panel']); |
||
232 | } elseif ($this->horizontal) { |
||
233 | Html::addCssClass($this->options, ['card', 'horizontal']); |
||
234 | } elseif ($useStickyActions) { |
||
235 | Html::addCssClass($this->options, ['card', 'sticky-action']); |
||
236 | unset($this->actionOptions['sticky']); |
||
237 | } else { |
||
238 | Html::addCssClass($this->options, ['card']); |
||
239 | } |
||
240 | } |
||
241 | |||
242 | /** |
||
243 | * Renders card content title tag content. |
||
244 | * |
||
245 | * @param array $source data source for title and options |
||
246 | * @return string the rendering result |
||
247 | */ |
||
248 | protected function renderTitleContent($source) |
||
249 | { |
||
250 | $html = ''; |
||
251 | |||
252 | if (isset($source['title'])) { |
||
253 | $titleValue = $source['title']; |
||
254 | $titleOptions = isset($source['titleOptions']) ? $source['titleOptions'] : []; |
||
255 | $encode = isset($titleOptions['encode']) ? $titleOptions['encode'] : $this->encodeLabels; |
||
256 | $icon = isset($titleOptions['icon']) ? $titleOptions['icon'] : null; |
||
257 | unset($titleOptions['encode']); |
||
258 | Html::addCssClass($titleOptions, 'card-title'); |
||
259 | $title = $encode ? Html::encode($titleValue) : $titleValue; |
||
260 | $title .= !empty($icon) ? Html::icon($icon, ['class' => 'material-icons right']) : ''; |
||
261 | unset($titleOptions['icon']); |
||
262 | $html .= Html::tag('span', $title, $titleOptions); |
||
263 | } |
||
264 | |||
265 | return $html; |
||
266 | } |
||
267 | |||
268 | /** |
||
269 | * Renders a single card action item. |
||
270 | * |
||
271 | * @param array $link the link to be rendered. It must contain the "label" element. The "url" and "icon" element is optional. |
||
272 | * @return string the rendering result |
||
273 | * @throws InvalidConfigException if `$link` does not have "label" element. |
||
274 | */ |
||
275 | protected function renderActionItem($link) |
||
300 | } |
||
301 | } |
||
302 | |||
303 | /** |
||
304 | * Renders card-image tag content. |
||
305 | * @return string the rendering result |
||
306 | */ |
||
307 | protected function renderImageContent() |
||
308 | { |
||
309 | $html = ''; |
||
310 | |||
311 | if (!empty($this->image)) { |
||
312 | $contentData = $this->image; |
||
313 | $fabData = isset($contentData['fab']) ? $contentData['fab'] : []; |
||
314 | $options = isset($contentData['options']) ? $contentData['options'] : []; |
||
315 | $imageOptions = isset($contentData['imageOptions']) ? $contentData['imageOptions'] : []; |
||
316 | $imageUrl = isset($contentData['url']) ? $contentData['url'] : []; |
||
317 | Html::addCssClass($options, ['class' => 'card-image']); |
||
318 | |||
319 | $html .= Html::beginTag('div', $options); |
||
320 | $html .= Html::img($imageUrl, $imageOptions); |
||
321 | $html .= $this->renderTitleContent($contentData); |
||
322 | $html .= $this->renderActionButton($fabData); |
||
323 | $html .= Html::endTag('div'); |
||
324 | } |
||
325 | |||
326 | return $html; |
||
327 | } |
||
328 | |||
329 | /** |
||
330 | * Renders floating action button tag. |
||
331 | * |
||
332 | * @param array $config attribute values and options for Button widget. |
||
333 | * @return string the rendering result |
||
334 | */ |
||
335 | protected function renderActionButton($config) |
||
350 | } |
||
351 | |||
352 | /** |
||
353 | * Renders card-reveal tag content. |
||
354 | * @return string the rendering result |
||
355 | */ |
||
356 | protected function renderRevealContent() |
||
376 | } |
||
377 | |||
378 | /** |
||
379 | * Renders card-tabs tag content. |
||
380 | * @return string the rendering result |
||
381 | */ |
||
382 | protected function renderTabsItem() |
||
396 |