| Total Complexity | 43 |
| Total Lines | 311 |
| Duplicated Lines | 0 % |
| Changes | 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 | * Initializes the widget. |
||
| 133 | * @return void |
||
| 134 | */ |
||
| 135 | public function init() |
||
| 136 | { |
||
| 137 | parent::init(); |
||
| 138 | |||
| 139 | $contentData = $this->content; |
||
| 140 | $cardContentOptions = isset($this->content['options']) ? $this->content['options'] : []; |
||
| 141 | Html::addCssClass($cardContentOptions, ['class' => 'card-content']); |
||
| 142 | $this->setCardClass(); // set main css classes to card tag |
||
| 143 | |||
| 144 | $html = Html::beginTag('div', $this->options); |
||
| 145 | $html .= $this->renderImageContent(); |
||
| 146 | |||
| 147 | // Create stacked content, if horizontal attribute is true |
||
| 148 | if ($this->horizontal) { |
||
| 149 | $html .= Html::beginTag('div', ['class' => 'card-stacked']); |
||
| 150 | } |
||
| 151 | |||
| 152 | // Add reviel button to content title, if reveal attribute is not empty |
||
| 153 | if (!empty($this->reveal)) { |
||
| 154 | Html::addCssClass($contentData['titleOptions'], 'activator'); |
||
| 155 | $addIcon = !isset($contentData['titleOptions']['icon']); |
||
| 156 | $contentData['titleOptions']['icon'] = $addIcon |
||
| 157 | ? 'more_vert' |
||
| 158 | : $contentData['titleOptions']['icon']; |
||
| 159 | } |
||
| 160 | |||
| 161 | // Create card content, if panel not is true |
||
| 162 | if (!$this->panel) { |
||
| 163 | $html .= Html::beginTag('div', $cardContentOptions); |
||
| 164 | } |
||
| 165 | |||
| 166 | $html .= $this->renderTitleContent($contentData); |
||
| 167 | |||
| 168 | echo $html; |
||
| 169 | } |
||
| 170 | |||
| 171 | /** |
||
| 172 | * Renders the widget. |
||
| 173 | * @return void |
||
| 174 | */ |
||
| 175 | public function run() |
||
| 176 | { |
||
| 177 | $this->registerPlugin('card'); |
||
| 178 | |||
| 179 | $html = isset($this->content['value']) ? $this->content['value'] : ''; |
||
| 180 | |||
| 181 | if (!$this->panel) { |
||
| 182 | $html .= Html::endTag('div'); // ends card-content tag |
||
| 183 | } |
||
| 184 | |||
| 185 | if (!empty($this->actions)) { |
||
| 186 | Html::addCssClass($this->actionOptions, ['class' => 'card-action']); |
||
| 187 | $html .= Html::beginTag('div', $this->actionOptions); |
||
| 188 | |||
| 189 | foreach ($this->actions as $action) { |
||
| 190 | $html .= $this->renderActionItem($action); |
||
| 191 | } |
||
| 192 | |||
| 193 | $html .= Html::endTag('div'); |
||
| 194 | } |
||
| 195 | |||
| 196 | if ($this->horizontal) { |
||
| 197 | $html .= Html::endTag('div'); //ends card-stacked tag |
||
| 198 | } |
||
| 199 | |||
| 200 | // Add card reveal tag |
||
| 201 | $html .= $this->renderRevealContent(); |
||
| 202 | $html .= Html::endTag('div'); //ends card tag |
||
| 203 | |||
| 204 | echo $html; |
||
| 205 | } |
||
| 206 | |||
| 207 | /** |
||
| 208 | * Sets card CSS class (or several classes) to the card options. |
||
| 209 | * @return void |
||
| 210 | */ |
||
| 211 | protected function setCardClass() |
||
| 212 | { |
||
| 213 | $useStickyActions = isset($this->actionOptions['sticky']) ? $this->actionOptions['sticky'] : false; |
||
| 214 | |||
| 215 | if ($this->panel) { |
||
| 216 | Html::addCssClass($this->options, ['card-panel']); |
||
| 217 | } elseif ($this->horizontal) { |
||
| 218 | Html::addCssClass($this->options, ['card', 'horizontal']); |
||
| 219 | } elseif ($useStickyActions) { |
||
| 220 | Html::addCssClass($this->options, ['card', 'sticky-action']); |
||
| 221 | unset($this->actionOptions['sticky']); |
||
| 222 | } else { |
||
| 223 | Html::addCssClass($this->options, ['card']); |
||
| 224 | } |
||
| 225 | } |
||
| 226 | |||
| 227 | /** |
||
| 228 | * Renders card content title tag content. |
||
| 229 | * |
||
| 230 | * @param array $source data source for title and options |
||
| 231 | * @return string the rendering result |
||
| 232 | */ |
||
| 233 | protected function renderTitleContent($source) |
||
| 234 | { |
||
| 235 | $html = ''; |
||
| 236 | |||
| 237 | if (isset($source['title'])) { |
||
| 238 | $titleValue = $source['title']; |
||
| 239 | $titleOptions = isset($source['titleOptions']) ? $source['titleOptions'] : []; |
||
| 240 | $encode = isset($titleOptions['encode']) ? $titleOptions['encode'] : $this->encodeLabels; |
||
| 241 | $icon = isset($titleOptions['icon']) ? $titleOptions['icon'] : null; |
||
| 242 | unset($titleOptions['encode']); |
||
| 243 | Html::addCssClass($titleOptions, 'card-title'); |
||
| 244 | $title = $encode ? Html::encode($titleValue) : $titleValue; |
||
| 245 | $title .= !empty($icon) ? Html::icon($icon, ['class' => 'material-icons right']) : ''; |
||
| 246 | unset($titleOptions['icon']); |
||
| 247 | $html .= Html::tag('span', $title, $titleOptions); |
||
| 248 | } |
||
| 249 | |||
| 250 | return $html; |
||
| 251 | } |
||
| 252 | |||
| 253 | /** |
||
| 254 | * Renders a single card action item. |
||
| 255 | * |
||
| 256 | * @param array $link the link to be rendered. It must contain the "label" element. The "url" and "icon" element is optional. |
||
| 257 | * @return string the rendering result |
||
| 258 | * @throws InvalidConfigException if `$link` does not have "label" element. |
||
| 259 | */ |
||
| 260 | protected function renderActionItem($link) |
||
| 285 | } |
||
| 286 | } |
||
| 287 | |||
| 288 | /** |
||
| 289 | * Renders card-image tag content. |
||
| 290 | * @return string the rendering result |
||
| 291 | */ |
||
| 292 | protected function renderImageContent() |
||
| 293 | { |
||
| 294 | $html = ''; |
||
| 295 | |||
| 296 | if (!empty($this->image)) { |
||
| 297 | $contentData = $this->image; |
||
| 298 | $fabData = isset($contentData['fab']) ? $contentData['fab'] : []; |
||
| 299 | $options = isset($contentData['options']) ? $contentData['options'] : []; |
||
| 300 | $imageOptions = isset($contentData['imageOptions']) ? $contentData['imageOptions'] : []; |
||
| 301 | $imageUrl = isset($contentData['url']) ? $contentData['url'] : []; |
||
| 302 | Html::addCssClass($options, ['class' => 'card-image']); |
||
| 303 | |||
| 304 | $html .= Html::beginTag('div', $options); |
||
| 305 | $html .= Html::img($imageUrl, $imageOptions); |
||
| 306 | $html .= $this->renderTitleContent($contentData); |
||
| 307 | $html .= $this->renderActionButton($fabData); |
||
| 308 | $html .= Html::endTag('div'); |
||
| 309 | } |
||
| 310 | |||
| 311 | return $html; |
||
| 312 | } |
||
| 313 | |||
| 314 | /** |
||
| 315 | * Renders floating action button tag. |
||
| 316 | * |
||
| 317 | * @param array $config attribute values and options for Button widget. |
||
| 318 | * @return string the rendering result |
||
| 319 | */ |
||
| 320 | protected function renderActionButton($config) |
||
| 335 | } |
||
| 336 | |||
| 337 | /** |
||
| 338 | * Renders card-reveal tag content. |
||
| 339 | * @return string the rendering result |
||
| 340 | */ |
||
| 341 | protected function renderRevealContent() |
||
| 361 | } |
||
| 362 | } |
||
| 363 |