| Total Complexity | 164 | 
| Total Lines | 1280 | 
| Duplicated Lines | 0 % | 
| Changes | 0 | ||
Complex classes like TableWidget 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 TableWidget, and based on these observations, apply Extract Interface, too.
| 1 | <?php  | 
            ||
| 29 | class TableWidget extends AdminWidget implements CollectionContainerInterface  | 
            ||
| 30 | { | 
            ||
| 31 | use ActionContainerTrait;  | 
            ||
| 32 |     use CollectionContainerTrait { | 
            ||
| 33 | CollectionContainerTrait::createCollectionLoader as createCollectionLoaderFromTrait;  | 
            ||
| 34 | CollectionContainerTrait::parsePropertyCell as parseCollectionPropertyCell;  | 
            ||
| 35 | CollectionContainerTrait::parseObjectRow as parseCollectionObjectRow;  | 
            ||
| 36 | }  | 
            ||
| 37 | use HttpAwareTrait;  | 
            ||
| 38 | |||
| 39 | /**  | 
            ||
| 40 | * Default sorting priority for an action.  | 
            ||
| 41 | *  | 
            ||
| 42 | * @const integer  | 
            ||
| 43 | */  | 
            ||
| 44 | const DEFAULT_ACTION_PRIORITY = 10;  | 
            ||
| 45 | |||
| 46 | /**  | 
            ||
| 47 | * @var array $properties  | 
            ||
| 48 | */  | 
            ||
| 49 | protected $properties;  | 
            ||
| 50 | |||
| 51 | /**  | 
            ||
| 52 | * @var boolean $parsedProperties  | 
            ||
| 53 | */  | 
            ||
| 54 | protected $parsedProperties = false;  | 
            ||
| 55 | |||
| 56 | /**  | 
            ||
| 57 | * @var array $propertiesOptions  | 
            ||
| 58 | */  | 
            ||
| 59 | protected $propertiesOptions;  | 
            ||
| 60 | |||
| 61 | /**  | 
            ||
| 62 | * @var boolean $sortable  | 
            ||
| 63 | */  | 
            ||
| 64 | protected $sortable;  | 
            ||
| 65 | |||
| 66 | /**  | 
            ||
| 67 | * @var boolean $showTableHeader  | 
            ||
| 68 | */  | 
            ||
| 69 | protected $showTableHeader = true;  | 
            ||
| 70 | |||
| 71 | /**  | 
            ||
| 72 | * @var boolean $showTableHead  | 
            ||
| 73 | */  | 
            ||
| 74 | protected $showTableHead = true;  | 
            ||
| 75 | |||
| 76 | /**  | 
            ||
| 77 | * @var boolean $showTableFoot  | 
            ||
| 78 | */  | 
            ||
| 79 | protected $showTableFoot = false;  | 
            ||
| 80 | |||
| 81 | /**  | 
            ||
| 82 | * Store the factory instance for the current class.  | 
            ||
| 83 | *  | 
            ||
| 84 | * @var FactoryInterface  | 
            ||
| 85 | */  | 
            ||
| 86 | private $widgetFactory;  | 
            ||
| 87 | |||
| 88 | /**  | 
            ||
| 89 | * @var FactoryInterface $propertyFactory  | 
            ||
| 90 | */  | 
            ||
| 91 | private $propertyFactory;  | 
            ||
| 92 | |||
| 93 | /**  | 
            ||
| 94 | * @var mixed $adminMetadata  | 
            ||
| 95 | */  | 
            ||
| 96 | private $adminMetadata;  | 
            ||
| 
                                                                                                    
                        
                         | 
                |||
| 97 | |||
| 98 | /**  | 
            ||
| 99 | * List actions ars displayed by default.  | 
            ||
| 100 | *  | 
            ||
| 101 | * @var boolean  | 
            ||
| 102 | */  | 
            ||
| 103 | private $showListActions = true;  | 
            ||
| 104 | |||
| 105 | /**  | 
            ||
| 106 | * Store the list actions.  | 
            ||
| 107 | *  | 
            ||
| 108 | * @var array|null  | 
            ||
| 109 | */  | 
            ||
| 110 | protected $listActions;  | 
            ||
| 111 | |||
| 112 | /**  | 
            ||
| 113 | * Store the default list actions.  | 
            ||
| 114 | *  | 
            ||
| 115 | * @var array|null  | 
            ||
| 116 | */  | 
            ||
| 117 | protected $defaultListActions;  | 
            ||
| 118 | |||
| 119 | /**  | 
            ||
| 120 | * Keep track if list actions are finalized.  | 
            ||
| 121 | *  | 
            ||
| 122 | * @var boolean  | 
            ||
| 123 | */  | 
            ||
| 124 | protected $parsedListActions = false;  | 
            ||
| 125 | |||
| 126 | /**  | 
            ||
| 127 | * Object actions ars displayed by default.  | 
            ||
| 128 | *  | 
            ||
| 129 | * @var boolean  | 
            ||
| 130 | */  | 
            ||
| 131 | private $showObjectActions = true;  | 
            ||
| 132 | |||
| 133 | /**  | 
            ||
| 134 | * Store the object actions.  | 
            ||
| 135 | *  | 
            ||
| 136 | * @var array|null  | 
            ||
| 137 | */  | 
            ||
| 138 | protected $objectActions;  | 
            ||
| 139 | |||
| 140 | /**  | 
            ||
| 141 | * Store the default object actions.  | 
            ||
| 142 | *  | 
            ||
| 143 | * @var array|null  | 
            ||
| 144 | */  | 
            ||
| 145 | protected $defaultObjectActions;  | 
            ||
| 146 | |||
| 147 | /**  | 
            ||
| 148 | * Keep track if object actions are finalized.  | 
            ||
| 149 | *  | 
            ||
| 150 | * @var boolean  | 
            ||
| 151 | */  | 
            ||
| 152 | protected $parsedObjectActions = false;  | 
            ||
| 153 | |||
| 154 | /**  | 
            ||
| 155 | * @param array $data The widget data.  | 
            ||
| 156 | * @return TableWidget Chainable  | 
            ||
| 157 | */  | 
            ||
| 158 | public function setData(array $data)  | 
            ||
| 159 |     { | 
            ||
| 160 | parent::setData($data);  | 
            ||
| 161 | |||
| 162 | $this->mergeDataSources($data);  | 
            ||
| 163 | |||
| 164 | return $this;  | 
            ||
| 165 | }  | 
            ||
| 166 | |||
| 167 | /**  | 
            ||
| 168 | * Fetch metadata from the current request.  | 
            ||
| 169 | *  | 
            ||
| 170 | * @return array  | 
            ||
| 171 | */  | 
            ||
| 172 | public function dataFromRequest()  | 
            ||
| 173 |     { | 
            ||
| 174 | return $this->httpRequest()->getParams($this->acceptedRequestData());  | 
            ||
| 175 | }  | 
            ||
| 176 | |||
| 177 | /**  | 
            ||
| 178 | * Retrieve the accepted metadata from the current request.  | 
            ||
| 179 | *  | 
            ||
| 180 | * @return array  | 
            ||
| 181 | */  | 
            ||
| 182 | public function acceptedRequestData()  | 
            ||
| 183 |     { | 
            ||
| 184 | return [  | 
            ||
| 185 | 'obj_type',  | 
            ||
| 186 | 'obj_id',  | 
            ||
| 187 | 'collection_ident',  | 
            ||
| 188 | 'sortable',  | 
            ||
| 189 | 'template',  | 
            ||
| 190 | ];  | 
            ||
| 191 | }  | 
            ||
| 192 | |||
| 193 | /**  | 
            ||
| 194 | * Fetch metadata from the current object type.  | 
            ||
| 195 | *  | 
            ||
| 196 | * @return array  | 
            ||
| 197 | */  | 
            ||
| 198 | public function dataFromObject()  | 
            ||
| 199 |     { | 
            ||
| 200 | $proto = $this->proto();  | 
            ||
| 201 | $objMetadata = $proto->metadata();  | 
            ||
| 202 | $adminMetadata = (isset($objMetadata['admin']) ? $objMetadata['admin'] : null);  | 
            ||
| 203 | |||
| 204 |         if (empty($adminMetadata['lists'])) { | 
            ||
| 205 | return [];  | 
            ||
| 206 | }  | 
            ||
| 207 | |||
| 208 | $collectionIdent = $this->collectionIdent();  | 
            ||
| 209 |         if (!$collectionIdent) { | 
            ||
| 210 | $collectionIdent = $this->collectionIdentFallback();  | 
            ||
| 211 | }  | 
            ||
| 212 | |||
| 213 |         if ($collectionIdent && $proto->view()) { | 
            ||
| 214 | $collectionIdent = $proto->render($collectionIdent);  | 
            ||
| 215 | }  | 
            ||
| 216 | |||
| 217 |         if (!$collectionIdent) { | 
            ||
| 218 | return [];  | 
            ||
| 219 | }  | 
            ||
| 220 | |||
| 221 |         if (isset($adminMetadata['lists'][$collectionIdent])) { | 
            ||
| 222 | $objListData = $adminMetadata['lists'][$collectionIdent];  | 
            ||
| 223 |         } else { | 
            ||
| 224 | $objListData = [];  | 
            ||
| 225 | }  | 
            ||
| 226 | |||
| 227 | $collectionConfig = [];  | 
            ||
| 228 | |||
| 229 |         if (isset($objListData['list_actions']) && isset($adminMetadata['list_actions'])) { | 
            ||
| 230 | $extraListActions = array_intersect(  | 
            ||
| 231 | array_keys($adminMetadata['list_actions']),  | 
            ||
| 232 | array_keys($objListData['list_actions'])  | 
            ||
| 233 | );  | 
            ||
| 234 |             foreach ($extraListActions as $listIdent) { | 
            ||
| 235 | $objListData['list_actions'][$listIdent] = array_replace_recursive(  | 
            ||
| 236 | $adminMetadata['list_actions'][$listIdent],  | 
            ||
| 237 | $objListData['list_actions'][$listIdent]  | 
            ||
| 238 | );  | 
            ||
| 239 | }  | 
            ||
| 240 | }  | 
            ||
| 241 | |||
| 242 |         if (isset($objListData['object_actions']) && isset($adminMetadata['list_object_actions'])) { | 
            ||
| 243 | $extraObjectActions = array_intersect(  | 
            ||
| 244 | array_keys($adminMetadata['list_object_actions']),  | 
            ||
| 245 | array_keys($objListData['object_actions'])  | 
            ||
| 246 | );  | 
            ||
| 247 |             foreach ($extraObjectActions as $listIdent) { | 
            ||
| 248 | $objListData['object_actions'][$listIdent] = array_replace_recursive(  | 
            ||
| 249 | $adminMetadata['list_object_actions'][$listIdent],  | 
            ||
| 250 | $objListData['object_actions'][$listIdent]  | 
            ||
| 251 | );  | 
            ||
| 252 | }  | 
            ||
| 253 | }  | 
            ||
| 254 | |||
| 255 |         if (isset($objListData['orders']) && isset($adminMetadata['list_orders'])) { | 
            ||
| 256 | $extraOrders = array_intersect(  | 
            ||
| 257 | array_keys($adminMetadata['list_orders']),  | 
            ||
| 258 | array_keys($objListData['orders'])  | 
            ||
| 259 | );  | 
            ||
| 260 |             foreach ($extraOrders as $listIdent) { | 
            ||
| 261 | $collectionConfig['orders'][$listIdent] = array_replace_recursive(  | 
            ||
| 262 | $adminMetadata['list_orders'][$listIdent],  | 
            ||
| 263 | $objListData['orders'][$listIdent]  | 
            ||
| 264 | );  | 
            ||
| 265 | }  | 
            ||
| 266 | }  | 
            ||
| 267 | |||
| 268 |         if (isset($objListData['filters']) && isset($adminMetadata['list_filters'])) { | 
            ||
| 269 | $extraFilters = array_intersect(  | 
            ||
| 270 | array_keys($adminMetadata['list_filters']),  | 
            ||
| 271 | array_keys($objListData['filters'])  | 
            ||
| 272 | );  | 
            ||
| 273 |             foreach ($extraFilters as $listIdent) { | 
            ||
| 274 | $collectionConfig['filters'][$listIdent] = array_replace_recursive(  | 
            ||
| 275 | $adminMetadata['list_filters'][$listIdent],  | 
            ||
| 276 | $objListData['filters'][$listIdent]  | 
            ||
| 277 | );  | 
            ||
| 278 | }  | 
            ||
| 279 | }  | 
            ||
| 280 | |||
| 281 |         if ($collectionConfig) { | 
            ||
| 282 | $this->mergeCollectionConfig($collectionConfig);  | 
            ||
| 283 | }  | 
            ||
| 284 | |||
| 285 | return $objListData;  | 
            ||
| 286 | }  | 
            ||
| 287 | |||
| 288 | /**  | 
            ||
| 289 | * Retrieve the widget's data options for JavaScript components.  | 
            ||
| 290 | *  | 
            ||
| 291 | * @return array  | 
            ||
| 292 | */  | 
            ||
| 293 | public function widgetDataForJs()  | 
            ||
| 294 |     { | 
            ||
| 295 | return [  | 
            ||
| 296 | 'obj_type' => $this->objType(),  | 
            ||
| 297 | 'template' => $this->template(),  | 
            ||
| 298 | 'collection_ident' => $this->collectionIdent(),  | 
            ||
| 299 | 'properties' => $this->propertiesIdents(),  | 
            ||
| 300 | 'filters' => $this->filters(),  | 
            ||
| 301 | 'orders' => $this->orders(),  | 
            ||
| 302 | 'list_actions' => $this->listActions(),  | 
            ||
| 303 | 'object_actions' => $this->rawObjectActions(),  | 
            ||
| 304 | 'pagination' => $this->pagination(),  | 
            ||
| 305 | ];  | 
            ||
| 306 | }  | 
            ||
| 307 | |||
| 308 | /**  | 
            ||
| 309 | * Sets and returns properties  | 
            ||
| 310 | *  | 
            ||
| 311 | * Manages which to display, and their order, as set in object metadata  | 
            ||
| 312 | *  | 
            ||
| 313 | * @return FormPropertyWidget[]  | 
            ||
| 314 | */  | 
            ||
| 315 | public function properties()  | 
            ||
| 316 |     { | 
            ||
| 317 |         if ($this->properties === null || $this->parsedProperties === false) { | 
            ||
| 318 | $this->parsedProperties = true;  | 
            ||
| 319 | |||
| 320 | $model = $this->proto();  | 
            ||
| 321 | $properties = $model->metadata()->properties();  | 
            ||
| 322 | |||
| 323 | $listProperties = null;  | 
            ||
| 324 |             if ($this->properties === null) { | 
            ||
| 325 | $collectionConfig = $this->collectionConfig();  | 
            ||
| 326 |                 if (isset($collectionConfig['properties'])) { | 
            ||
| 327 | $listProperties = array_flip($collectionConfig['properties']);  | 
            ||
| 328 | }  | 
            ||
| 329 |             } else { | 
            ||
| 330 | $listProperties = array_flip($this->properties);  | 
            ||
| 331 | }  | 
            ||
| 332 | |||
| 333 |             if ($listProperties) { | 
            ||
| 334 | // Replacing values of listProperties from index to actual property values  | 
            ||
| 335 | $properties = array_replace($listProperties, $properties);  | 
            ||
| 336 | // Get only the keys that are in listProperties from props  | 
            ||
| 337 | $properties = array_intersect_key($properties, $listProperties);  | 
            ||
| 338 | }  | 
            ||
| 339 | |||
| 340 | $this->properties = $properties;  | 
            ||
| 341 | }  | 
            ||
| 342 | |||
| 343 | return $this->properties;  | 
            ||
| 344 | }  | 
            ||
| 345 | |||
| 346 | /**  | 
            ||
| 347 | * Retrieve the property keys shown in the collection.  | 
            ||
| 348 | *  | 
            ||
| 349 | * @return array  | 
            ||
| 350 | */  | 
            ||
| 351 | public function propertiesIdents()  | 
            ||
| 352 |     { | 
            ||
| 353 | $collectionConfig = $this->collectionConfig();  | 
            ||
| 354 |         if (isset($collectionConfig['properties'])) { | 
            ||
| 355 | return $collectionConfig['properties'];  | 
            ||
| 356 | }  | 
            ||
| 357 | |||
| 358 | return [];  | 
            ||
| 359 | }  | 
            ||
| 360 | |||
| 361 | /**  | 
            ||
| 362 | * Retrieve the property customizations for the collection.  | 
            ||
| 363 | *  | 
            ||
| 364 | * @return array|null  | 
            ||
| 365 | */  | 
            ||
| 366 | public function propertiesOptions()  | 
            ||
| 367 |     { | 
            ||
| 368 |         if ($this->propertiesOptions === null) { | 
            ||
| 369 | $this->propertiesOptions = $this->defaultPropertiesOptions();  | 
            ||
| 370 | }  | 
            ||
| 371 | |||
| 372 | return $this->propertiesOptions;  | 
            ||
| 373 | }  | 
            ||
| 374 | |||
| 375 | /**  | 
            ||
| 376 | * Retrieve the view options for the given property.  | 
            ||
| 377 | *  | 
            ||
| 378 | * @param string $propertyIdent The property identifier to lookup.  | 
            ||
| 379 | * @return array  | 
            ||
| 380 | */  | 
            ||
| 381 | public function viewOptions($propertyIdent)  | 
            ||
| 382 |     { | 
            ||
| 383 |         if (!$propertyIdent) { | 
            ||
| 384 | return [];  | 
            ||
| 385 | }  | 
            ||
| 386 | |||
| 387 |         if ($propertyIdent instanceof PropertyInterface) { | 
            ||
| 388 | $propertyIdent = $propertyIdent->ident();  | 
            ||
| 389 | }  | 
            ||
| 390 | |||
| 391 | $options = $this->propertiesOptions();  | 
            ||
| 392 | |||
| 393 |         if (isset($options[$propertyIdent]['view_options'])) { | 
            ||
| 394 | return $options[$propertyIdent]['view_options'];  | 
            ||
| 395 |         } else { | 
            ||
| 396 | return [];  | 
            ||
| 397 | }  | 
            ||
| 398 | }  | 
            ||
| 399 | |||
| 400 | /**  | 
            ||
| 401 | * Properties to display in collection template, and their order, as set in object metadata  | 
            ||
| 402 | *  | 
            ||
| 403 | * @return array|Generator  | 
            ||
| 404 | */  | 
            ||
| 405 | public function collectionProperties()  | 
            ||
| 406 |     { | 
            ||
| 407 | $props = $this->properties();  | 
            ||
| 408 | |||
| 409 |         foreach ($props as $propertyIdent => $property) { | 
            ||
| 410 | $propertyMetadata = $props[$propertyIdent];  | 
            ||
| 411 | |||
| 412 | $p = $this->propertyFactory()->create($propertyMetadata['type']);  | 
            ||
| 413 | $p->setIdent($propertyIdent);  | 
            ||
| 414 | $p->setData($propertyMetadata);  | 
            ||
| 415 | |||
| 416 | $options = $this->viewOptions($propertyIdent);  | 
            ||
| 417 | $classes = $this->parsePropertyCellClasses($p);  | 
            ||
| 418 | |||
| 419 |             if (isset($options['label'])) { | 
            ||
| 420 | $label = $this->translator()->translate($options['label']);  | 
            ||
| 421 |             } else { | 
            ||
| 422 | $label = strval($p->label());  | 
            ||
| 423 | }  | 
            ||
| 424 | |||
| 425 | $column = [  | 
            ||
| 426 | 'label' => trim($label)  | 
            ||
| 427 | ];  | 
            ||
| 428 | |||
| 429 |             if (!isset($column['attr'])) { | 
            ||
| 430 | $column['attr'] = [];  | 
            ||
| 431 | }  | 
            ||
| 432 | |||
| 433 |             if (isset($options['attr'])) { | 
            ||
| 434 | $column['attr'] = array_merge($column['attr'], $options['attr']);  | 
            ||
| 435 | }  | 
            ||
| 436 | |||
| 437 |             if (isset($classes)) { | 
            ||
| 438 |                 if (isset($column['attr']['class'])) { | 
            ||
| 439 |                     if (is_string($classes)) { | 
            ||
| 440 |                         $classes = explode(' ', $column['attr']['class']); | 
            ||
| 441 | }  | 
            ||
| 442 | |||
| 443 |                     if (is_string($column['attr']['class'])) { | 
            ||
| 444 |                         $column['attr']['class'] = explode(' ', $column['attr']['class']); | 
            ||
| 445 | }  | 
            ||
| 446 | |||
| 447 | $column['attr']['class'] = array_unique(array_merge($column['attr']['class'], $classes));  | 
            ||
| 448 |                 } else { | 
            ||
| 449 | $column['attr']['class'] = $classes;  | 
            ||
| 450 | }  | 
            ||
| 451 | |||
| 452 | unset($classes);  | 
            ||
| 453 | }  | 
            ||
| 454 | |||
| 455 | $column['attr'] = html_build_attributes($column['attr']);  | 
            ||
| 456 | |||
| 457 | yield $column;  | 
            ||
| 458 | }  | 
            ||
| 459 | }  | 
            ||
| 460 | |||
| 461 | /**  | 
            ||
| 462 | * Show/hide the table's object actions.  | 
            ||
| 463 | *  | 
            ||
| 464 | * @param boolean $show Show (TRUE) or hide (FALSE) the actions.  | 
            ||
| 465 | * @return TableWidget Chainable  | 
            ||
| 466 | */  | 
            ||
| 467 | public function setShowObjectActions($show)  | 
            ||
| 468 |     { | 
            ||
| 469 | $this->showObjectActions = !!$show;  | 
            ||
| 470 | |||
| 471 | return $this;  | 
            ||
| 472 | }  | 
            ||
| 473 | |||
| 474 | /**  | 
            ||
| 475 | * Determine if the table's object actions should be shown.  | 
            ||
| 476 | *  | 
            ||
| 477 | * @return boolean  | 
            ||
| 478 | */  | 
            ||
| 479 | public function showObjectActions()  | 
            ||
| 480 |     { | 
            ||
| 481 |         if ($this->showObjectActions === false) { | 
            ||
| 482 | return false;  | 
            ||
| 483 |         } else { | 
            ||
| 484 | return count($this->objectActions());  | 
            ||
| 485 | }  | 
            ||
| 486 | }  | 
            ||
| 487 | |||
| 488 | /**  | 
            ||
| 489 | * Retrieve the table's object actions.  | 
            ||
| 490 | *  | 
            ||
| 491 | * @return array  | 
            ||
| 492 | */  | 
            ||
| 493 | public function objectActions()  | 
            ||
| 494 |     { | 
            ||
| 495 | $this->rawObjectActions();  | 
            ||
| 496 | |||
| 497 | $objectActions = [];  | 
            ||
| 498 |         if (is_array($this->objectActions)) { | 
            ||
| 499 | $objectActions = $this->parseAsObjectActions($this->objectActions);  | 
            ||
| 500 | }  | 
            ||
| 501 | |||
| 502 | return $objectActions;  | 
            ||
| 503 | }  | 
            ||
| 504 | |||
| 505 | /**  | 
            ||
| 506 | * Retrieve the table's object actions without rendering it.  | 
            ||
| 507 | *  | 
            ||
| 508 | * @return array  | 
            ||
| 509 | */  | 
            ||
| 510 | public function rawObjectActions()  | 
            ||
| 511 |     { | 
            ||
| 512 |         if ($this->objectActions === null) { | 
            ||
| 513 | $parsed = $this->parsedObjectActions;  | 
            ||
| 514 | |||
| 515 | $collectionConfig = $this->collectionConfig();  | 
            ||
| 516 |             if (isset($collectionConfig['object_actions'])) { | 
            ||
| 517 | $actions = $collectionConfig['object_actions'];  | 
            ||
| 518 |             } else { | 
            ||
| 519 | $actions = [];  | 
            ||
| 520 | }  | 
            ||
| 521 | |||
| 522 | $this->setObjectActions($actions);  | 
            ||
| 523 | |||
| 524 | $this->parsedObjectActions = $parsed;  | 
            ||
| 525 | }  | 
            ||
| 526 | |||
| 527 |         if ($this->parsedObjectActions === false) { | 
            ||
| 528 | $this->parsedObjectActions = true;  | 
            ||
| 529 | $this->objectActions = $this->createObjectActions($this->objectActions);  | 
            ||
| 530 | }  | 
            ||
| 531 | |||
| 532 | return $this->objectActions;  | 
            ||
| 533 | }  | 
            ||
| 534 | |||
| 535 | /**  | 
            ||
| 536 | * Set the table's object actions.  | 
            ||
| 537 | *  | 
            ||
| 538 | * @param array $actions One or more actions.  | 
            ||
| 539 | * @return TableWidget Chainable.  | 
            ||
| 540 | */  | 
            ||
| 541 | public function setObjectActions(array $actions)  | 
            ||
| 542 |     { | 
            ||
| 543 | $this->parsedObjectActions = false;  | 
            ||
| 544 | |||
| 545 | $actions = $this->mergeActions($this->defaultObjectActions(), $actions);  | 
            ||
| 546 | |||
| 547 | /** Enable seamless button group */  | 
            ||
| 548 |         if (isset($actions['edit'])) { | 
            ||
| 549 | $actions['edit']['actionType'] = 'seamless';  | 
            ||
| 550 | }  | 
            ||
| 551 | |||
| 552 | $this->objectActions = $actions;  | 
            ||
| 553 | |||
| 554 | return $this;  | 
            ||
| 555 | }  | 
            ||
| 556 | |||
| 557 | /**  | 
            ||
| 558 | * Build the table's object actions (row).  | 
            ||
| 559 | *  | 
            ||
| 560 | * Object actions should come from the collection settings defined by the "collection_ident".  | 
            ||
| 561 | * It is still possible to completly override those externally by setting the "object_actions"  | 
            ||
| 562 |      * with the {@see self::setObjectActions()} method. | 
            ||
| 563 | *  | 
            ||
| 564 | * @param array $actions Actions to resolve.  | 
            ||
| 565 | * @return array Object actions.  | 
            ||
| 566 | */  | 
            ||
| 567 | public function createObjectActions(array $actions)  | 
            ||
| 568 |     { | 
            ||
| 569 | $objectActions = $this->parseActions($actions);  | 
            ||
| 570 | |||
| 571 | return $objectActions;  | 
            ||
| 572 | }  | 
            ||
| 573 | |||
| 574 | /**  | 
            ||
| 575 | * Parse the given actions as (row) object actions.  | 
            ||
| 576 | *  | 
            ||
| 577 | * @param array $actions Actions to resolve.  | 
            ||
| 578 | * @return array  | 
            ||
| 579 | */  | 
            ||
| 580 | protected function parseAsObjectActions(array $actions)  | 
            ||
| 581 |     { | 
            ||
| 582 | $objectActions = [];  | 
            ||
| 583 |         foreach ($actions as $action) { | 
            ||
| 584 | $action = $this->parseActionRenderables($action, true);  | 
            ||
| 585 | |||
| 586 |             if (isset($action['ident'])) { | 
            ||
| 587 |                 if ($action['ident'] === 'view' && !$this->isObjViewable()) { | 
            ||
| 588 | $action['active'] = false;  | 
            ||
| 589 |                 } elseif ($action['ident'] === 'create' && !$this->isObjCreatable()) { | 
            ||
| 590 | $action['active'] = false;  | 
            ||
| 591 |                 } elseif ($action['ident'] === 'edit' && !$this->isObjEditable()) { | 
            ||
| 592 | $action['active'] = false;  | 
            ||
| 593 |                 } elseif ($action['ident'] === 'delete' && !$this->isObjDeletable()) { | 
            ||
| 594 | $action['active'] = false;  | 
            ||
| 595 | }  | 
            ||
| 596 | }  | 
            ||
| 597 | |||
| 598 |             if ($action['actions']) { | 
            ||
| 599 | $action['actions'] = $this->parseAsObjectActions($action['actions']);  | 
            ||
| 600 |                 $action['hasActions'] = !!array_filter($action['actions'], function ($action) { | 
            ||
| 601 | return $action['active'];  | 
            ||
| 602 | });  | 
            ||
| 603 | }  | 
            ||
| 604 | |||
| 605 | $objectActions[] = $action;  | 
            ||
| 606 | }  | 
            ||
| 607 | |||
| 608 | return $objectActions;  | 
            ||
| 609 | }  | 
            ||
| 610 | |||
| 611 | |||
| 612 | |||
| 613 | /**  | 
            ||
| 614 | * Determine if the table's empty collection actions should be shown.  | 
            ||
| 615 | *  | 
            ||
| 616 | * @return boolean  | 
            ||
| 617 | */  | 
            ||
| 618 | public function showEmptyListActions()  | 
            ||
| 619 |     { | 
            ||
| 620 | $actions = $this->emptyListActions();  | 
            ||
| 621 | |||
| 622 | return count($actions);  | 
            ||
| 623 | }  | 
            ||
| 624 | |||
| 625 | /**  | 
            ||
| 626 | * Retrieve the table's empty collection actions.  | 
            ||
| 627 | *  | 
            ||
| 628 | * @return array  | 
            ||
| 629 | */  | 
            ||
| 630 | public function emptyListActions()  | 
            ||
| 631 |     { | 
            ||
| 632 | $actions = $this->listActions();  | 
            ||
| 633 | |||
| 634 |         $filteredArray = array_filter($actions, function ($action) { | 
            ||
| 635 | return $action['empty'];  | 
            ||
| 636 | });  | 
            ||
| 637 | |||
| 638 | return array_values($filteredArray);  | 
            ||
| 639 | }  | 
            ||
| 640 | |||
| 641 | /**  | 
            ||
| 642 | * Show/hide the table's collection actions.  | 
            ||
| 643 | *  | 
            ||
| 644 | * @param boolean $show Show (TRUE) or hide (FALSE) the actions.  | 
            ||
| 645 | * @return TableWidget Chainable  | 
            ||
| 646 | */  | 
            ||
| 647 | public function setShowListActions($show)  | 
            ||
| 648 |     { | 
            ||
| 649 | $this->showListActions = !!$show;  | 
            ||
| 650 | |||
| 651 | return $this;  | 
            ||
| 652 | }  | 
            ||
| 653 | |||
| 654 | /**  | 
            ||
| 655 | * Determine if the table's collection actions should be shown.  | 
            ||
| 656 | *  | 
            ||
| 657 | * @return boolean  | 
            ||
| 658 | */  | 
            ||
| 659 | public function showListActions()  | 
            ||
| 660 |     { | 
            ||
| 661 |         if ($this->showListActions === false) { | 
            ||
| 662 | return false;  | 
            ||
| 663 |         } else { | 
            ||
| 664 | return count($this->listActions());  | 
            ||
| 665 | }  | 
            ||
| 666 | }  | 
            ||
| 667 | |||
| 668 | /**  | 
            ||
| 669 | * Retrieve the table's collection actions.  | 
            ||
| 670 | *  | 
            ||
| 671 | * @return array  | 
            ||
| 672 | */  | 
            ||
| 673 | public function listActions()  | 
            ||
| 674 |     { | 
            ||
| 675 |         if ($this->listActions === null) { | 
            ||
| 676 | $collectionConfig = $this->collectionConfig();  | 
            ||
| 677 |             if (isset($collectionConfig['list_actions'])) { | 
            ||
| 678 | $actions = $collectionConfig['list_actions'];  | 
            ||
| 679 |             } else { | 
            ||
| 680 | $actions = [];  | 
            ||
| 681 | }  | 
            ||
| 682 | $this->setListActions($actions);  | 
            ||
| 683 | }  | 
            ||
| 684 | |||
| 685 |         if ($this->parsedListActions === false) { | 
            ||
| 686 | $this->parsedListActions = true;  | 
            ||
| 687 | $this->listActions = $this->createListActions($this->listActions);  | 
            ||
| 688 | }  | 
            ||
| 689 | |||
| 690 | return $this->listActions;  | 
            ||
| 691 | }  | 
            ||
| 692 | |||
| 693 | |||
| 694 | /**  | 
            ||
| 695 | * @return PaginationWidget  | 
            ||
| 696 | */  | 
            ||
| 697 | public function paginationWidget()  | 
            ||
| 698 |     { | 
            ||
| 699 | $pagination = $this->widgetFactory()->create(PaginationWidget::class);  | 
            ||
| 700 | $pagination->setData([  | 
            ||
| 701 | 'page' => $this->page(),  | 
            ||
| 702 | 'num_per_page' => $this->numPerPage(),  | 
            ||
| 703 | 'num_total' => $this->numTotal(),  | 
            ||
| 704 |             'label'        => $this->translator()->translation('Objects list navigation') | 
            ||
| 705 | ]);  | 
            ||
| 706 | |||
| 707 | return $pagination;  | 
            ||
| 708 | }  | 
            ||
| 709 | |||
| 710 | /**  | 
            ||
| 711 | * @param boolean $show The show flag.  | 
            ||
| 712 | * @return TableWidget Chainable  | 
            ||
| 713 | */  | 
            ||
| 714 | public function setShowTableHeader($show)  | 
            ||
| 715 |     { | 
            ||
| 716 | $this->showTableHeader = !!$show;  | 
            ||
| 717 | |||
| 718 | return $this;  | 
            ||
| 719 | }  | 
            ||
| 720 | |||
| 721 | /**  | 
            ||
| 722 | * @return boolean  | 
            ||
| 723 | */  | 
            ||
| 724 | public function showTableHeader()  | 
            ||
| 727 | }  | 
            ||
| 728 | |||
| 729 | /**  | 
            ||
| 730 | * @param boolean $show The show flag.  | 
            ||
| 731 | * @return TableWidget Chainable  | 
            ||
| 732 | */  | 
            ||
| 733 | public function setShowTableHead($show)  | 
            ||
| 734 |     { | 
            ||
| 735 | $this->showTableHead = !!$show;  | 
            ||
| 736 | |||
| 737 | return $this;  | 
            ||
| 738 | }  | 
            ||
| 739 | |||
| 740 | /**  | 
            ||
| 741 | * @return boolean  | 
            ||
| 742 | */  | 
            ||
| 743 | public function showTableHead()  | 
            ||
| 744 |     { | 
            ||
| 745 | return $this->showTableHead;  | 
            ||
| 746 | }  | 
            ||
| 747 | |||
| 748 | /**  | 
            ||
| 749 | * @param boolean $show The show flag.  | 
            ||
| 750 | * @return TableWidget Chainable  | 
            ||
| 751 | */  | 
            ||
| 752 | public function setShowTableFoot($show)  | 
            ||
| 753 |     { | 
            ||
| 754 | $this->showTableFoot = !!$show;  | 
            ||
| 755 | |||
| 756 | return $this;  | 
            ||
| 757 | }  | 
            ||
| 758 | |||
| 759 | /**  | 
            ||
| 760 | * @return boolean  | 
            ||
| 761 | */  | 
            ||
| 762 | public function showTableFoot()  | 
            ||
| 763 |     { | 
            ||
| 764 | return $this->showTableFoot;  | 
            ||
| 765 | }  | 
            ||
| 766 | |||
| 767 | /**  | 
            ||
| 768 | * @param boolean $sortable The sortable flag.  | 
            ||
| 769 | * @return TableWidget Chainable  | 
            ||
| 770 | */  | 
            ||
| 771 | public function setSortable($sortable)  | 
            ||
| 772 |     { | 
            ||
| 773 | $this->sortable = !!$sortable;  | 
            ||
| 774 | |||
| 775 | return $this;  | 
            ||
| 776 | }  | 
            ||
| 777 | |||
| 778 | /**  | 
            ||
| 779 | * @return boolean  | 
            ||
| 780 | */  | 
            ||
| 781 | public function sortable()  | 
            ||
| 782 |     { | 
            ||
| 783 | return $this->sortable;  | 
            ||
| 784 | }  | 
            ||
| 785 | |||
| 786 | /**  | 
            ||
| 787 | * @return string  | 
            ||
| 788 | */  | 
            ||
| 789 | public function jsActionPrefix()  | 
            ||
| 792 | }  | 
            ||
| 793 | |||
| 794 | /**  | 
            ||
| 795 | * Generate URL for editing an object  | 
            ||
| 796 | * @return string  | 
            ||
| 797 | */  | 
            ||
| 798 | public function objectEditUrl()  | 
            ||
| 799 |     { | 
            ||
| 800 | $model = $this->proto();  | 
            ||
| 801 |         $url   = 'object/edit?main_menu={{ main_menu }}&obj_type='.$this->objType(); | 
            ||
| 802 | |||
| 803 |         if ($model->view()) { | 
            ||
| 804 | $url = $model->render((string)$url);  | 
            ||
| 805 |         } else { | 
            ||
| 806 |             $url = preg_replace('~{{\s*id\s*}}~', $this->currentObjId, $url); | 
            ||
| 807 | }  | 
            ||
| 808 | |||
| 809 | return $url;  | 
            ||
| 810 | }  | 
            ||
| 811 | |||
| 812 | /**  | 
            ||
| 813 | * Generate URL for creating an object  | 
            ||
| 814 | * @return string  | 
            ||
| 815 | */  | 
            ||
| 816 | public function objectCreateUrl()  | 
            ||
| 817 |     { | 
            ||
| 818 | $actions = $this->listActions();  | 
            ||
| 819 |         if ($actions) { | 
            ||
| 820 |             foreach ($actions as $action) { | 
            ||
| 821 |                 if (isset($action['ident']) && $action['ident'] === 'create') { | 
            ||
| 822 |                     if (isset($action['url'])) { | 
            ||
| 823 | $model = $this->proto();  | 
            ||
| 824 |                         if ($model->view()) { | 
            ||
| 825 | $action['url'] = $model->render((string)$action['url']);  | 
            ||
| 826 |                         } else { | 
            ||
| 827 |                             $action['url'] = preg_replace('~{{\s*id\s*}}~', $this->currentObjId, $action['url']); | 
            ||
| 828 | }  | 
            ||
| 829 | |||
| 830 | return $action['url'];  | 
            ||
| 831 | }  | 
            ||
| 832 | }  | 
            ||
| 833 | }  | 
            ||
| 834 | }  | 
            ||
| 835 | |||
| 836 | return $this->objectEditUrl();  | 
            ||
| 837 | }  | 
            ||
| 838 | |||
| 839 | /**  | 
            ||
| 840 | * Determine if the object can be created.  | 
            ||
| 841 | *  | 
            ||
| 842 | * If TRUE, the "Create" button is shown. Objects can still be  | 
            ||
| 843 | * inserted programmatically or via direct action on the database.  | 
            ||
| 844 | *  | 
            ||
| 845 | * @return boolean  | 
            ||
| 846 | */  | 
            ||
| 847 | public function isObjCreatable()  | 
            ||
| 848 |     { | 
            ||
| 849 | $model = $this->proto();  | 
            ||
| 850 | $method = [ $model, 'isCreatable' ];  | 
            ||
| 851 | |||
| 852 |         if (is_callable($method)) { | 
            ||
| 853 | return call_user_func($method);  | 
            ||
| 854 | }  | 
            ||
| 855 | |||
| 856 | return true;  | 
            ||
| 857 | }  | 
            ||
| 858 | |||
| 859 | /**  | 
            ||
| 860 | * Determine if the object can be modified.  | 
            ||
| 861 | *  | 
            ||
| 862 | * If TRUE, the "Modify" button is shown. Objects can still be  | 
            ||
| 863 | * updated programmatically or via direct action on the database.  | 
            ||
| 864 | *  | 
            ||
| 865 | * @return boolean  | 
            ||
| 866 | */  | 
            ||
| 867 | public function isObjEditable()  | 
            ||
| 868 |     { | 
            ||
| 869 | $model = ($this->currentObj) ? $this->currentObj : $this->proto();  | 
            ||
| 870 | $method = [ $model, 'isEditable' ];  | 
            ||
| 871 | |||
| 872 |         if (is_callable($method)) { | 
            ||
| 873 | return call_user_func($method);  | 
            ||
| 874 | }  | 
            ||
| 875 | |||
| 876 | return true;  | 
            ||
| 877 | }  | 
            ||
| 878 | |||
| 879 | /**  | 
            ||
| 880 | * Determine if the object can be deleted.  | 
            ||
| 881 | *  | 
            ||
| 882 | * If TRUE, the "Delete" button is shown. Objects can still be  | 
            ||
| 883 | * deleted programmatically or via direct action on the database.  | 
            ||
| 884 | *  | 
            ||
| 885 | * @return boolean  | 
            ||
| 886 | */  | 
            ||
| 887 | public function isObjDeletable()  | 
            ||
| 888 |     { | 
            ||
| 889 | $model = ($this->currentObj) ? $this->currentObj : $this->proto();  | 
            ||
| 890 | $method = [ $model, 'isDeletable' ];  | 
            ||
| 891 | |||
| 892 |         if (is_callable($method)) { | 
            ||
| 893 | return call_user_func($method);  | 
            ||
| 894 | }  | 
            ||
| 895 | |||
| 896 | return true;  | 
            ||
| 897 | }  | 
            ||
| 898 | |||
| 899 | /**  | 
            ||
| 900 | * Determine if the object can be viewed (on the front-end).  | 
            ||
| 901 | *  | 
            ||
| 902 | * If TRUE, any "View" button is shown. The object can still be  | 
            ||
| 903 | * saved programmatically.  | 
            ||
| 904 | *  | 
            ||
| 905 | * @return boolean  | 
            ||
| 906 | */  | 
            ||
| 907 | public function isObjViewable()  | 
            ||
| 908 |     { | 
            ||
| 909 | $model = ($this->currentObj) ? $this->currentObj : $this->proto();  | 
            ||
| 910 |         if (!$model->id()) { | 
            ||
| 911 | return false;  | 
            ||
| 912 | }  | 
            ||
| 913 | |||
| 914 | $method = [ $model, 'isViewable' ];  | 
            ||
| 915 |         if (is_callable($method)) { | 
            ||
| 916 | return call_user_func($method);  | 
            ||
| 917 | }  | 
            ||
| 918 | |||
| 919 | return true;  | 
            ||
| 920 | }  | 
            ||
| 921 | |||
| 922 | /**  | 
            ||
| 923 | * @param Container $container Pimple DI container.  | 
            ||
| 924 | * @return void  | 
            ||
| 925 | */  | 
            ||
| 926 | protected function setDependencies(Container $container)  | 
            ||
| 927 |     { | 
            ||
| 928 | parent::setDependencies($container);  | 
            ||
| 929 | |||
| 930 | // Satisfies HttpAwareTrait dependencies  | 
            ||
| 931 | $this->setHttpRequest($container['request']);  | 
            ||
| 932 | |||
| 933 | $this->setView($container['view']);  | 
            ||
| 934 | $this->setCollectionLoader($container['model/collection/loader']);  | 
            ||
| 935 | $this->setWidgetFactory($container['widget/factory']);  | 
            ||
| 936 | $this->setPropertyFactory($container['property/factory']);  | 
            ||
| 937 | $this->setPropertyDisplayFactory($container['property/display/factory']);  | 
            ||
| 938 | }  | 
            ||
| 939 | |||
| 940 | /**  | 
            ||
| 941 | * Create a collection loader.  | 
            ||
| 942 | *  | 
            ||
| 943 | * @return CollectionLoader  | 
            ||
| 944 | */  | 
            ||
| 945 | protected function createCollectionLoader()  | 
            ||
| 946 |     { | 
            ||
| 947 | $loader = $this->createCollectionLoaderFromTrait();  | 
            ||
| 948 | |||
| 949 | $mainMenu = filter_input(INPUT_GET, 'main_menu', FILTER_SANITIZE_STRING);  | 
            ||
| 950 |         if ($mainMenu) { | 
            ||
| 951 |             $loader->setCallback(function (&$obj) use ($mainMenu) { | 
            ||
| 952 |                 if (!$obj['main_menu']) { | 
            ||
| 953 | $obj['main_menu'] = $mainMenu;  | 
            ||
| 954 | }  | 
            ||
| 955 | });  | 
            ||
| 956 | }  | 
            ||
| 957 | |||
| 958 | return $loader;  | 
            ||
| 959 | }  | 
            ||
| 960 | |||
| 961 | /**  | 
            ||
| 962 | * Retrieve the widget factory.  | 
            ||
| 963 | *  | 
            ||
| 964 | * @throws RuntimeException If the widget factory was not previously set.  | 
            ||
| 965 | * @return FactoryInterface  | 
            ||
| 966 | */  | 
            ||
| 967 | protected function widgetFactory()  | 
            ||
| 968 |     { | 
            ||
| 969 |         if ($this->widgetFactory === null) { | 
            ||
| 970 | throw new RuntimeException(  | 
            ||
| 971 |                 sprintf('Widget Factory is not defined for "%s"', get_class($this)) | 
            ||
| 972 | );  | 
            ||
| 973 | }  | 
            ||
| 974 | |||
| 975 | return $this->widgetFactory;  | 
            ||
| 976 | }  | 
            ||
| 977 | |||
| 978 | /**  | 
            ||
| 979 | * @throws RuntimeException If the property factory was not previously set / injected.  | 
            ||
| 980 | * @return FactoryInterface  | 
            ||
| 981 | */  | 
            ||
| 982 | protected function propertyFactory()  | 
            ||
| 983 |     { | 
            ||
| 984 |         if ($this->propertyFactory === null) { | 
            ||
| 985 | throw new RuntimeException(  | 
            ||
| 986 | 'Property factory is not set for table widget'  | 
            ||
| 987 | );  | 
            ||
| 988 | }  | 
            ||
| 989 | |||
| 990 | return $this->propertyFactory;  | 
            ||
| 991 | }  | 
            ||
| 992 | |||
| 993 | /**  | 
            ||
| 994 | * Retrieve the default data source filters (when setting data on an entity).  | 
            ||
| 995 | *  | 
            ||
| 996 |      * Note: Adapted from {@see \Slim\CallableResolver}. | 
            ||
| 997 | *  | 
            ||
| 998 | * @link https://github.com/slimphp/Slim/blob/3.x/Slim/CallableResolver.php  | 
            ||
| 999 | * @param mixed $toResolve A callable used when merging data.  | 
            ||
| 1000 | * @return callable|null  | 
            ||
| 1001 | */  | 
            ||
| 1002 | protected function resolveDataSourceFilter($toResolve)  | 
            ||
| 1003 |     { | 
            ||
| 1004 |         if (is_string($toResolve)) { | 
            ||
| 1005 | $model = $this->proto();  | 
            ||
| 1006 | |||
| 1007 | $resolved = [ $model, $toResolve ];  | 
            ||
| 1008 | |||
| 1009 | // Check for Slim callable  | 
            ||
| 1010 | $callablePattern = '!^([^\:]+)\:([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)$!';  | 
            ||
| 1011 |             if (preg_match($callablePattern, $toResolve, $matches)) { | 
            ||
| 1012 | $class = $matches[1];  | 
            ||
| 1013 | $method = $matches[2];  | 
            ||
| 1014 | |||
| 1015 |                 if ($class === 'parent') { | 
            ||
| 1016 | $resolved = [ $model, $class.'::'.$method ];  | 
            ||
| 1017 | }  | 
            ||
| 1018 | }  | 
            ||
| 1019 | |||
| 1020 | $toResolve = $resolved;  | 
            ||
| 1021 | }  | 
            ||
| 1022 | |||
| 1023 | return parent::resolveDataSourceFilter($toResolve);  | 
            ||
| 1024 | }  | 
            ||
| 1025 | |||
| 1026 | /**  | 
            ||
| 1027 | * Set the table's collection actions.  | 
            ||
| 1028 | *  | 
            ||
| 1029 | * @param array $actions One or more actions.  | 
            ||
| 1030 | * @return TableWidget Chainable.  | 
            ||
| 1031 | */  | 
            ||
| 1032 | protected function setListActions(array $actions)  | 
            ||
| 1033 |     { | 
            ||
| 1034 | $this->parsedListActions = false;  | 
            ||
| 1035 | |||
| 1036 | $this->listActions = $this->mergeActions($this->defaultListActions(), $actions);  | 
            ||
| 1037 | |||
| 1038 | return $this;  | 
            ||
| 1039 | }  | 
            ||
| 1040 | |||
| 1041 | /**  | 
            ||
| 1042 | * Build the table collection actions.  | 
            ||
| 1043 | *  | 
            ||
| 1044 | * List actions should come from the collection settings defined by the "collection_ident".  | 
            ||
| 1045 | * It is still possible to completly override those externally by setting the "list_actions"  | 
            ||
| 1046 |      * with the {@see self::setListActions()} method. | 
            ||
| 1047 | *  | 
            ||
| 1048 | * @param array $actions Actions to resolve.  | 
            ||
| 1049 | * @return array List actions.  | 
            ||
| 1050 | */  | 
            ||
| 1051 | protected function createListActions(array $actions)  | 
            ||
| 1052 |     { | 
            ||
| 1053 | $this->actionsPriority = $this->defaultActionPriority();  | 
            ||
| 1054 | |||
| 1055 | $listActions = $this->parseAsListActions($actions);  | 
            ||
| 1056 | |||
| 1057 | return $listActions;  | 
            ||
| 1058 | }  | 
            ||
| 1059 | |||
| 1060 | /**  | 
            ||
| 1061 | * Parse the given actions as collection actions.  | 
            ||
| 1062 | *  | 
            ||
| 1063 | * @param array $actions Actions to resolve.  | 
            ||
| 1064 | * @return array  | 
            ||
| 1065 | */  | 
            ||
| 1066 | protected function parseAsListActions(array $actions)  | 
            ||
| 1067 |     { | 
            ||
| 1068 | $listActions = [];  | 
            ||
| 1069 |         foreach ($actions as $ident => $action) { | 
            ||
| 1070 | $ident = $this->parseActionIdent($ident, $action);  | 
            ||
| 1071 | $action = $this->parseActionItem($action, $ident, true);  | 
            ||
| 1072 | |||
| 1073 |             if (!isset($action['priority'])) { | 
            ||
| 1074 | $action['priority'] = $this->actionsPriority++;  | 
            ||
| 1075 | }  | 
            ||
| 1076 | |||
| 1077 |             if ($action['ident'] === 'create') { | 
            ||
| 1078 | $action['empty'] = true;  | 
            ||
| 1079 | |||
| 1080 |                 if (!$this->isObjCreatable()) { | 
            ||
| 1081 | $action['active'] = false;  | 
            ||
| 1082 | }  | 
            ||
| 1083 |             } else { | 
            ||
| 1084 | $action['empty'] = (isset($action['empty']) ? boolval($action['empty']) : false);  | 
            ||
| 1085 | }  | 
            ||
| 1086 | |||
| 1087 |             if (is_array($action['actions'])) { | 
            ||
| 1088 | $action['actions'] = $this->parseAsListActions($action['actions']);  | 
            ||
| 1089 |                 $action['hasActions'] = !!array_filter($action['actions'], function ($action) { | 
            ||
| 1090 | return $action['active'];  | 
            ||
| 1091 | });  | 
            ||
| 1092 | }  | 
            ||
| 1093 | |||
| 1094 |             if (isset($listActions[$ident])) { | 
            ||
| 1095 | $hasPriority = ($action['priority'] > $listActions[$ident]['priority']);  | 
            ||
| 1096 |                 if ($hasPriority || $action['isSubmittable']) { | 
            ||
| 1097 | $listActions[$ident] = array_replace($listActions[$ident], $action);  | 
            ||
| 1098 |                 } else { | 
            ||
| 1099 | $listActions[$ident] = array_replace($action, $listActions[$ident]);  | 
            ||
| 1100 | }  | 
            ||
| 1101 |             } else { | 
            ||
| 1102 | $listActions[$ident] = $action;  | 
            ||
| 1103 | }  | 
            ||
| 1104 | }  | 
            ||
| 1105 | |||
| 1106 | usort($listActions, [ $this, 'sortActionsByPriority' ]);  | 
            ||
| 1107 | |||
| 1108 |         while (($first = reset($listActions)) && $first['isSeparator']) { | 
            ||
| 1109 | array_shift($listActions);  | 
            ||
| 1110 | }  | 
            ||
| 1111 | |||
| 1112 |         while (($last = end($listActions)) && $last['isSeparator']) { | 
            ||
| 1113 | array_pop($listActions);  | 
            ||
| 1114 | }  | 
            ||
| 1115 | |||
| 1116 | return $listActions;  | 
            ||
| 1117 | }  | 
            ||
| 1118 | |||
| 1119 | /**  | 
            ||
| 1120 | * Retrieve the table's default collection actions.  | 
            ||
| 1121 | *  | 
            ||
| 1122 | * @return array  | 
            ||
| 1123 | */  | 
            ||
| 1124 | protected function defaultListActions()  | 
            ||
| 1125 |     { | 
            ||
| 1126 |         if ($this->defaultListActions === null) { | 
            ||
| 1127 | $this->defaultListActions = [];  | 
            ||
| 1128 | }  | 
            ||
| 1129 | |||
| 1130 | return $this->defaultListActions;  | 
            ||
| 1131 | }  | 
            ||
| 1132 | |||
| 1133 | /**  | 
            ||
| 1134 | * Retrieve the table's default object actions.  | 
            ||
| 1135 | *  | 
            ||
| 1136 | * @return array  | 
            ||
| 1137 | */  | 
            ||
| 1138 | protected function defaultObjectActions()  | 
            ||
| 1139 |     { | 
            ||
| 1140 |         if ($this->defaultObjectActions === null) { | 
            ||
| 1141 | $edit = [  | 
            ||
| 1142 |                 'label'    => $this->translator()->translation('Modify'), | 
            ||
| 1143 |                 'url'      => $this->objectEditUrl().'&obj_id={{id}}', | 
            ||
| 1144 | 'ident' => 'edit',  | 
            ||
| 1145 | 'priority' => 1  | 
            ||
| 1146 | ];  | 
            ||
| 1147 | $this->defaultObjectActions = [ $edit ];  | 
            ||
| 1148 | }  | 
            ||
| 1149 | |||
| 1150 | return $this->defaultObjectActions;  | 
            ||
| 1151 | }  | 
            ||
| 1152 | |||
| 1153 | /**  | 
            ||
| 1154 | * Retrieve the default property customizations.  | 
            ||
| 1155 | *  | 
            ||
| 1156 | * The default configset is determined by the collection ident and object type, if assigned.  | 
            ||
| 1157 | *  | 
            ||
| 1158 | * @return array|null  | 
            ||
| 1159 | */  | 
            ||
| 1160 | protected function defaultPropertiesOptions()  | 
            ||
| 1161 |     { | 
            ||
| 1162 | $collectionConfig = $this->collectionConfig();  | 
            ||
| 1163 | |||
| 1164 |         if (empty($collectionConfig['properties_options'])) { | 
            ||
| 1165 | return [];  | 
            ||
| 1166 | }  | 
            ||
| 1167 | |||
| 1168 | return $collectionConfig['properties_options'];  | 
            ||
| 1169 | }  | 
            ||
| 1170 | |||
| 1171 | /**  | 
            ||
| 1172 | * Filter the property before its assigned to the object row.  | 
            ||
| 1173 | *  | 
            ||
| 1174 | * This method is useful for classes using this trait.  | 
            ||
| 1175 | *  | 
            ||
| 1176 | * @param ModelInterface $object The current row's object.  | 
            ||
| 1177 | * @param PropertyInterface $property The current property.  | 
            ||
| 1178 | * @param string $propertyValue The property $key's display value.  | 
            ||
| 1179 | * @return array  | 
            ||
| 1180 | */  | 
            ||
| 1181 | protected function parsePropertyCell(  | 
            ||
| 1182 | ModelInterface $object,  | 
            ||
| 1183 | PropertyInterface $property,  | 
            ||
| 1184 | $propertyValue  | 
            ||
| 1185 |     ) { | 
            ||
| 1186 | $cell = $this->parseCollectionPropertyCell($object, $property, $propertyValue);  | 
            ||
| 1187 | $ident = $property->ident();  | 
            ||
| 1188 | $options = $this->viewOptions($ident);  | 
            ||
| 1189 | $classes = $this->parsePropertyCellClasses($property, $object);  | 
            ||
| 1190 | |||
| 1191 | $cell['truncate'] = (isset($options['truncate']) ? boolval($options['truncate']) : false);  | 
            ||
| 1192 | |||
| 1193 |         if (!isset($cell['attr'])) { | 
            ||
| 1194 | $cell['attr'] = [];  | 
            ||
| 1195 | }  | 
            ||
| 1196 | |||
| 1197 |         if (isset($options['attr'])) { | 
            ||
| 1198 | unset($options['attr']['width']);  | 
            ||
| 1199 | $cell['attr'] = array_merge($cell['attr'], $options['attr']);  | 
            ||
| 1200 | }  | 
            ||
| 1201 | |||
| 1202 |         if (isset($classes)) { | 
            ||
| 1203 |             if (isset($cell['attr']['class'])) { | 
            ||
| 1204 |                 if (is_string($classes)) { | 
            ||
| 1205 |                     $classes = explode(' ', $cell['attr']['class']); | 
            ||
| 1206 | }  | 
            ||
| 1207 | |||
| 1208 |                 if (is_string($cell['attr']['class'])) { | 
            ||
| 1209 |                     $cell['attr']['class'] = explode(' ', $cell['attr']['class']); | 
            ||
| 1210 | }  | 
            ||
| 1211 | |||
| 1212 | $cell['attr']['class'] = array_unique(array_merge($cell['attr']['class'], $classes));  | 
            ||
| 1213 |             } else { | 
            ||
| 1214 | $cell['attr']['class'] = $classes;  | 
            ||
| 1215 | }  | 
            ||
| 1216 | |||
| 1217 | unset($classes);  | 
            ||
| 1218 | }  | 
            ||
| 1219 | |||
| 1220 | $cell['attr'] = html_build_attributes($cell['attr']);  | 
            ||
| 1221 | |||
| 1222 | return $cell;  | 
            ||
| 1223 | }  | 
            ||
| 1224 | |||
| 1225 | /**  | 
            ||
| 1226 | * Filter the table cell's CSS classes before the property is assigned  | 
            ||
| 1227 | * to the object row.  | 
            ||
| 1228 | *  | 
            ||
| 1229 | * This method is useful for classes using this trait.  | 
            ||
| 1230 | *  | 
            ||
| 1231 | * @param PropertyInterface $property The current property.  | 
            ||
| 1232 | * @param ModelInterface|null $object Optional. The current row's object.  | 
            ||
| 1233 | * @return array  | 
            ||
| 1234 | */  | 
            ||
| 1235 | protected function parsePropertyCellClasses(  | 
            ||
| 1236 | PropertyInterface $property,  | 
            ||
| 1237 | ModelInterface $object = null  | 
            ||
| 1238 |     ) { | 
            ||
| 1239 | unset($object);  | 
            ||
| 1240 | |||
| 1241 | $ident = $property->ident();  | 
            ||
| 1242 |         $classes = [ sprintf('property-%s', $ident) ]; | 
            ||
| 1243 | $options = $this->viewOptions($ident);  | 
            ||
| 1244 | |||
| 1245 |         if (isset($options['classes'])) { | 
            ||
| 1246 |             if (is_array($options['classes'])) { | 
            ||
| 1247 | $classes = array_merge($classes, $options['classes']);  | 
            ||
| 1248 |             } else { | 
            ||
| 1249 | $classes[] = $options['classes'];  | 
            ||
| 1250 | }  | 
            ||
| 1251 | }  | 
            ||
| 1252 | |||
| 1253 | return $classes;  | 
            ||
| 1254 | }  | 
            ||
| 1255 | |||
| 1256 | /**  | 
            ||
| 1257 | * Filter the object before its assigned to the row.  | 
            ||
| 1258 | *  | 
            ||
| 1259 | * This method is useful for classes using this trait.  | 
            ||
| 1260 | *  | 
            ||
| 1261 | * @param ModelInterface $object The current row's object.  | 
            ||
| 1262 | * @param array $objectProperties The $object's display properties.  | 
            ||
| 1263 | * @return array  | 
            ||
| 1264 | */  | 
            ||
| 1265 | protected function parseObjectRow(ModelInterface $object, array $objectProperties)  | 
            ||
| 1266 |     { | 
            ||
| 1267 | $row = $this->parseCollectionObjectRow($object, $objectProperties);  | 
            ||
| 1268 | $row['objectActions'] = $this->objectActions();  | 
            ||
| 1269 | $row['showObjectActions'] = ($this->showObjectActions() === false) ? false : !!$row['objectActions'];  | 
            ||
| 1270 | |||
| 1271 | $row['attr'] = [  | 
            ||
| 1272 | 'class' => []  | 
            ||
| 1273 | ];  | 
            ||
| 1274 | |||
| 1275 | $method = [ $object, 'isActiveTableRow' ];  | 
            ||
| 1276 |         if (is_callable($method)) { | 
            ||
| 1277 |             if (call_user_func($method)) { | 
            ||
| 1278 | $row['attr']['class'][] = 'active';  | 
            ||
| 1279 | }  | 
            ||
| 1280 | }  | 
            ||
| 1281 | |||
| 1282 | $row['attr']['class'][] = 'js-table-row';  | 
            ||
| 1283 | |||
| 1284 | $row['attr'] = html_build_attributes($row['attr']);  | 
            ||
| 1285 | |||
| 1286 | return $row;  | 
            ||
| 1287 | }  | 
            ||
| 1288 | |||
| 1289 | /**  | 
            ||
| 1290 | * Set an widget factory.  | 
            ||
| 1291 | *  | 
            ||
| 1292 | * @param FactoryInterface $factory The factory to create widgets.  | 
            ||
| 1293 | * @return void  | 
            ||
| 1294 | */  | 
            ||
| 1295 | private function setWidgetFactory(FactoryInterface $factory)  | 
            ||
| 1298 | }  | 
            ||
| 1299 | |||
| 1300 | /**  | 
            ||
| 1301 | * @param FactoryInterface $factory The property factory, to create properties.  | 
            ||
| 1302 | * @return TableWidget Chainable  | 
            ||
| 1303 | */  | 
            ||
| 1304 | private function setPropertyFactory(FactoryInterface $factory)  | 
            ||
| 1305 |     { | 
            ||
| 1306 | $this->propertyFactory = $factory;  | 
            ||
| 1307 | |||
| 1308 | return $this;  | 
            ||
| 1309 | }  | 
            ||
| 1310 | }  | 
            ||
| 1311 |