[ Index ] |
PHP Cross Reference of Joomla 4.2.2 documentation |
[Summary view] [Print] [Text view]
1 <?php 2 3 /** 4 * @package Joomla.Administrator 5 * @subpackage com_modules 6 * 7 * @copyright (C) 2007 Open Source Matters, Inc. <https://www.joomla.org> 8 * @license GNU General Public License version 2 or later; see LICENSE.txt 9 */ 10 11 namespace Joomla\Component\Modules\Administrator\Model; 12 13 use Joomla\CMS\Application\ApplicationHelper; 14 use Joomla\CMS\Component\ComponentHelper; 15 use Joomla\CMS\Factory; 16 use Joomla\CMS\Filesystem\Folder; 17 use Joomla\CMS\Filesystem\Path; 18 use Joomla\CMS\Form\Form; 19 use Joomla\CMS\Helper\ModuleHelper; 20 use Joomla\CMS\Language\Text; 21 use Joomla\CMS\MVC\Model\AdminModel; 22 use Joomla\CMS\Object\CMSObject; 23 use Joomla\CMS\Plugin\PluginHelper; 24 use Joomla\CMS\Router\Route; 25 use Joomla\CMS\Table\Table; 26 use Joomla\Component\Modules\Administrator\Helper\ModulesHelper; 27 use Joomla\Database\ParameterType; 28 use Joomla\Registry\Registry; 29 use Joomla\String\StringHelper; 30 use Joomla\Utilities\ArrayHelper; 31 32 // phpcs:disable PSR1.Files.SideEffects 33 \defined('_JEXEC') or die; 34 // phpcs:enable PSR1.Files.SideEffects 35 36 /** 37 * Module model. 38 * 39 * @since 1.6 40 */ 41 class ModuleModel extends AdminModel 42 { 43 /** 44 * The type alias for this content type. 45 * 46 * @var string 47 * @since 3.4 48 */ 49 public $typeAlias = 'com_modules.module'; 50 51 /** 52 * @var string The prefix to use with controller messages. 53 * @since 1.6 54 */ 55 protected $text_prefix = 'COM_MODULES'; 56 57 /** 58 * @var string The help screen key for the module. 59 * @since 1.6 60 */ 61 protected $helpKey = ''; 62 63 /** 64 * @var string The help screen base URL for the module. 65 * @since 1.6 66 */ 67 protected $helpURL; 68 69 /** 70 * Batch copy/move command. If set to false, 71 * the batch copy/move command is not supported 72 * 73 * @var string 74 */ 75 protected $batch_copymove = 'position_id'; 76 77 /** 78 * Allowed batch commands 79 * 80 * @var array 81 */ 82 protected $batch_commands = array( 83 'assetgroup_id' => 'batchAccess', 84 'language_id' => 'batchLanguage', 85 ); 86 87 /** 88 * Constructor. 89 * 90 * @param array $config An optional associative array of configuration settings. 91 */ 92 public function __construct($config = array()) 93 { 94 $config = array_merge( 95 array( 96 'event_after_delete' => 'onExtensionAfterDelete', 97 'event_after_save' => 'onExtensionAfterSave', 98 'event_before_delete' => 'onExtensionBeforeDelete', 99 'event_before_save' => 'onExtensionBeforeSave', 100 'events_map' => array( 101 'save' => 'extension', 102 'delete' => 'extension' 103 ) 104 ), 105 $config 106 ); 107 108 parent::__construct($config); 109 } 110 111 /** 112 * Method to auto-populate the model state. 113 * 114 * Note. Calling getState in this method will result in recursion. 115 * 116 * @return void 117 * 118 * @since 1.6 119 */ 120 protected function populateState() 121 { 122 $app = Factory::getApplication(); 123 124 // Load the User state. 125 $pk = $app->input->getInt('id'); 126 127 if (!$pk) { 128 if ($extensionId = (int) $app->getUserState('com_modules.add.module.extension_id')) { 129 $this->setState('extension.id', $extensionId); 130 } 131 } 132 133 $this->setState('module.id', $pk); 134 135 // Load the parameters. 136 $params = ComponentHelper::getParams('com_modules'); 137 $this->setState('params', $params); 138 } 139 140 /** 141 * Batch copy modules to a new position or current. 142 * 143 * @param integer $value The new value matching a module position. 144 * @param array $pks An array of row IDs. 145 * @param array $contexts An array of item contexts. 146 * 147 * @return boolean True if successful, false otherwise and internal error is set. 148 * 149 * @since 2.5 150 */ 151 protected function batchCopy($value, $pks, $contexts) 152 { 153 // Set the variables 154 $user = Factory::getUser(); 155 $table = $this->getTable(); 156 $newIds = array(); 157 158 foreach ($pks as $pk) { 159 if ($user->authorise('core.create', 'com_modules')) { 160 $table->reset(); 161 $table->load($pk); 162 163 // Set the new position 164 if ($value == 'noposition') { 165 $position = ''; 166 } elseif ($value == 'nochange') { 167 $position = $table->position; 168 } else { 169 $position = $value; 170 } 171 172 $table->position = $position; 173 174 // Copy of the Asset ID 175 $oldAssetId = $table->asset_id; 176 177 // Alter the title if necessary 178 $data = $this->generateNewTitle(0, $table->title, $table->position); 179 $table->title = $data['0']; 180 181 // Reset the ID because we are making a copy 182 $table->id = 0; 183 184 // Unpublish the new module 185 $table->published = 0; 186 187 if (!$table->store()) { 188 $this->setError($table->getError()); 189 190 return false; 191 } 192 193 // Get the new item ID 194 $newId = $table->get('id'); 195 196 // Add the new ID to the array 197 $newIds[$pk] = $newId; 198 199 // Now we need to handle the module assignments 200 $db = $this->getDatabase(); 201 $query = $db->getQuery(true) 202 ->select($db->quoteName('menuid')) 203 ->from($db->quoteName('#__modules_menu')) 204 ->where($db->quoteName('moduleid') . ' = :moduleid') 205 ->bind(':moduleid', $pk, ParameterType::INTEGER); 206 $db->setQuery($query); 207 $menus = $db->loadColumn(); 208 209 // Insert the new records into the table 210 foreach ($menus as $i => $menu) { 211 $query->clear() 212 ->insert($db->quoteName('#__modules_menu')) 213 ->columns($db->quoteName(['moduleid', 'menuid'])) 214 ->values(implode(', ', [':newid' . $i, ':menu' . $i])) 215 ->bind(':newid' . $i, $newId, ParameterType::INTEGER) 216 ->bind(':menu' . $i, $menu, ParameterType::INTEGER); 217 $db->setQuery($query); 218 $db->execute(); 219 } 220 221 // Copy rules 222 $query->clear() 223 ->update($db->quoteName('#__assets', 't')) 224 ->join('INNER', $db->quoteName('#__assets', 's') . 225 ' ON ' . $db->quoteName('s.id') . ' = ' . $oldAssetId) 226 ->set($db->quoteName('t.rules') . ' = ' . $db->quoteName('s.rules')) 227 ->where($db->quoteName('t.id') . ' = ' . $table->asset_id); 228 229 $db->setQuery($query)->execute(); 230 } else { 231 $this->setError(Text::_('JLIB_APPLICATION_ERROR_BATCH_CANNOT_CREATE')); 232 233 return false; 234 } 235 } 236 237 // Clean the cache 238 $this->cleanCache(); 239 240 return $newIds; 241 } 242 243 /** 244 * Batch move modules to a new position or current. 245 * 246 * @param integer $value The new value matching a module position. 247 * @param array $pks An array of row IDs. 248 * @param array $contexts An array of item contexts. 249 * 250 * @return boolean True if successful, false otherwise and internal error is set. 251 * 252 * @since 2.5 253 */ 254 protected function batchMove($value, $pks, $contexts) 255 { 256 // Set the variables 257 $user = Factory::getUser(); 258 $table = $this->getTable(); 259 260 foreach ($pks as $pk) { 261 if ($user->authorise('core.edit', 'com_modules')) { 262 $table->reset(); 263 $table->load($pk); 264 265 // Set the new position 266 if ($value == 'noposition') { 267 $position = ''; 268 } elseif ($value == 'nochange') { 269 $position = $table->position; 270 } else { 271 $position = $value; 272 } 273 274 $table->position = $position; 275 276 if (!$table->store()) { 277 $this->setError($table->getError()); 278 279 return false; 280 } 281 } else { 282 $this->setError(Text::_('JLIB_APPLICATION_ERROR_BATCH_CANNOT_EDIT')); 283 284 return false; 285 } 286 } 287 288 // Clean the cache 289 $this->cleanCache(); 290 291 return true; 292 } 293 294 /** 295 * Method to test whether a record can have its state edited. 296 * 297 * @param object $record A record object. 298 * 299 * @return boolean True if allowed to change the state of the record. Defaults to the permission set in the component. 300 * 301 * @since 3.2 302 */ 303 protected function canEditState($record) 304 { 305 // Check for existing module. 306 if (!empty($record->id)) { 307 return Factory::getUser()->authorise('core.edit.state', 'com_modules.module.' . (int) $record->id); 308 } 309 310 // Default to component settings if module not known. 311 return parent::canEditState($record); 312 } 313 314 /** 315 * Method to delete rows. 316 * 317 * @param array &$pks An array of item ids. 318 * 319 * @return boolean Returns true on success, false on failure. 320 * 321 * @since 1.6 322 * @throws \Exception 323 */ 324 public function delete(&$pks) 325 { 326 $app = Factory::getApplication(); 327 $pks = (array) $pks; 328 $user = Factory::getUser(); 329 $table = $this->getTable(); 330 $context = $this->option . '.' . $this->name; 331 332 // Include the plugins for the on delete events. 333 PluginHelper::importPlugin($this->events_map['delete']); 334 335 // Iterate the items to delete each one. 336 foreach ($pks as $pk) { 337 if ($table->load($pk)) { 338 // Access checks. 339 if (!$user->authorise('core.delete', 'com_modules.module.' . (int) $pk) || $table->published != -2) { 340 Factory::getApplication()->enqueueMessage(Text::_('JERROR_CORE_DELETE_NOT_PERMITTED'), 'error'); 341 342 return; 343 } 344 345 // Trigger the before delete event. 346 $result = $app->triggerEvent($this->event_before_delete, array($context, $table)); 347 348 if (in_array(false, $result, true) || !$table->delete($pk)) { 349 throw new \Exception($table->getError()); 350 } else { 351 // Delete the menu assignments 352 $pk = (int) $pk; 353 $db = $this->getDatabase(); 354 $query = $db->getQuery(true) 355 ->delete($db->quoteName('#__modules_menu')) 356 ->where($db->quoteName('moduleid') . ' = :moduleid') 357 ->bind(':moduleid', $pk, ParameterType::INTEGER); 358 $db->setQuery($query); 359 $db->execute(); 360 361 // Trigger the after delete event. 362 $app->triggerEvent($this->event_after_delete, array($context, $table)); 363 } 364 365 // Clear module cache 366 parent::cleanCache($table->module); 367 } else { 368 throw new \Exception($table->getError()); 369 } 370 } 371 372 // Clear modules cache 373 $this->cleanCache(); 374 375 return true; 376 } 377 378 /** 379 * Method to duplicate modules. 380 * 381 * @param array &$pks An array of primary key IDs. 382 * 383 * @return boolean Boolean true on success 384 * 385 * @since 1.6 386 * @throws \Exception 387 */ 388 public function duplicate(&$pks) 389 { 390 $user = Factory::getUser(); 391 $db = $this->getDatabase(); 392 393 // Access checks. 394 if (!$user->authorise('core.create', 'com_modules')) { 395 throw new \Exception(Text::_('JERROR_CORE_CREATE_NOT_PERMITTED')); 396 } 397 398 $table = $this->getTable(); 399 400 foreach ($pks as $pk) { 401 if ($table->load($pk, true)) { 402 // Reset the id to create a new record. 403 $table->id = 0; 404 405 // Alter the title. 406 $m = null; 407 408 if (preg_match('#\((\d+)\)$#', $table->title, $m)) { 409 $table->title = preg_replace('#\(\d+\)$#', '(' . ($m[1] + 1) . ')', $table->title); 410 } 411 412 $data = $this->generateNewTitle(0, $table->title, $table->position); 413 $table->title = $data[0]; 414 415 // Unpublish duplicate module 416 $table->published = 0; 417 418 if (!$table->check() || !$table->store()) { 419 throw new \Exception($table->getError()); 420 } 421 422 $pk = (int) $pk; 423 $query = $db->getQuery(true) 424 ->select($db->quoteName('menuid')) 425 ->from($db->quoteName('#__modules_menu')) 426 ->where($db->quoteName('moduleid') . ' = :moduleid') 427 ->bind(':moduleid', $pk, ParameterType::INTEGER); 428 429 $db->setQuery($query); 430 $rows = $db->loadColumn(); 431 432 foreach ($rows as $menuid) { 433 $tuples[] = (int) $table->id . ',' . (int) $menuid; 434 } 435 } else { 436 throw new \Exception($table->getError()); 437 } 438 } 439 440 if (!empty($tuples)) { 441 // Module-Menu Mapping: Do it in one query 442 $query = $db->getQuery(true) 443 ->insert($db->quoteName('#__modules_menu')) 444 ->columns($db->quoteName(array('moduleid', 'menuid'))) 445 ->values($tuples); 446 447 $db->setQuery($query); 448 449 try { 450 $db->execute(); 451 } catch (\RuntimeException $e) { 452 Factory::getApplication()->enqueueMessage($e->getMessage(), 'error'); 453 454 return false; 455 } 456 } 457 458 // Clear modules cache 459 $this->cleanCache(); 460 461 return true; 462 } 463 464 /** 465 * Method to change the title. 466 * 467 * @param integer $categoryId The id of the category. Not used here. 468 * @param string $title The title. 469 * @param string $position The position. 470 * 471 * @return array Contains the modified title. 472 * 473 * @since 2.5 474 */ 475 protected function generateNewTitle($categoryId, $title, $position) 476 { 477 // Alter the title & alias 478 $table = $this->getTable(); 479 480 while ($table->load(array('position' => $position, 'title' => $title))) { 481 $title = StringHelper::increment($title); 482 } 483 484 return array($title); 485 } 486 487 /** 488 * Method to get the client object 489 * 490 * @return void 491 * 492 * @since 1.6 493 */ 494 public function &getClient() 495 { 496 return $this->_client; 497 } 498 499 /** 500 * Method to get the record form. 501 * 502 * @param array $data Data for the form. 503 * @param boolean $loadData True if the form is to load its own data (default case), false if not. 504 * 505 * @return Form|bool A Form object on success, false on failure 506 * 507 * @since 1.6 508 */ 509 public function getForm($data = array(), $loadData = true) 510 { 511 // The folder and element vars are passed when saving the form. 512 if (empty($data)) { 513 $item = $this->getItem(); 514 $clientId = $item->client_id; 515 $module = $item->module; 516 $id = $item->id; 517 } else { 518 $clientId = ArrayHelper::getValue($data, 'client_id'); 519 $module = ArrayHelper::getValue($data, 'module'); 520 $id = ArrayHelper::getValue($data, 'id'); 521 } 522 523 // Add the default fields directory 524 $baseFolder = $clientId ? JPATH_ADMINISTRATOR : JPATH_SITE; 525 Form::addFieldPath($baseFolder . '/modules/' . $module . '/field'); 526 527 // These variables are used to add data from the plugin XML files. 528 $this->setState('item.client_id', $clientId); 529 $this->setState('item.module', $module); 530 531 // Get the form. 532 if ($clientId == 1) { 533 $form = $this->loadForm('com_modules.module.admin', 'moduleadmin', array('control' => 'jform', 'load_data' => $loadData), true); 534 535 // Display language field to filter admin custom menus per language 536 if (!ModuleHelper::isAdminMultilang()) { 537 $form->setFieldAttribute('language', 'type', 'hidden'); 538 } 539 } else { 540 $form = $this->loadForm('com_modules.module', 'module', array('control' => 'jform', 'load_data' => $loadData), true); 541 } 542 543 if (empty($form)) { 544 return false; 545 } 546 547 $user = Factory::getUser(); 548 549 /** 550 * Check for existing module 551 * Modify the form based on Edit State access controls. 552 */ 553 if ( 554 $id != 0 && (!$user->authorise('core.edit.state', 'com_modules.module.' . (int) $id)) 555 || ($id == 0 && !$user->authorise('core.edit.state', 'com_modules')) 556 ) { 557 // Disable fields for display. 558 $form->setFieldAttribute('ordering', 'disabled', 'true'); 559 $form->setFieldAttribute('published', 'disabled', 'true'); 560 $form->setFieldAttribute('publish_up', 'disabled', 'true'); 561 $form->setFieldAttribute('publish_down', 'disabled', 'true'); 562 563 // Disable fields while saving. 564 // The controller has already verified this is a record you can edit. 565 $form->setFieldAttribute('ordering', 'filter', 'unset'); 566 $form->setFieldAttribute('published', 'filter', 'unset'); 567 $form->setFieldAttribute('publish_up', 'filter', 'unset'); 568 $form->setFieldAttribute('publish_down', 'filter', 'unset'); 569 } 570 571 return $form; 572 } 573 574 /** 575 * Method to get the data that should be injected in the form. 576 * 577 * @return mixed The data for the form. 578 * 579 * @since 1.6 580 */ 581 protected function loadFormData() 582 { 583 $app = Factory::getApplication(); 584 585 // Check the session for previously entered form data. 586 $data = $app->getUserState('com_modules.edit.module.data', array()); 587 588 if (empty($data)) { 589 $data = $this->getItem(); 590 591 // Pre-select some filters (Status, Module Position, Language, Access Level) in edit form if those have been selected in Module Manager 592 if (!$data->id) { 593 $clientId = $app->input->getInt('client_id', 0); 594 $filters = (array) $app->getUserState('com_modules.modules.' . $clientId . '.filter'); 595 $data->set('published', $app->input->getInt('published', ((isset($filters['state']) && $filters['state'] !== '') ? $filters['state'] : null))); 596 $data->set('position', $app->input->getInt('position', (!empty($filters['position']) ? $filters['position'] : null))); 597 $data->set('language', $app->input->getString('language', (!empty($filters['language']) ? $filters['language'] : null))); 598 $data->set('access', $app->input->getInt('access', (!empty($filters['access']) ? $filters['access'] : $app->get('access')))); 599 } 600 601 // Avoid to delete params of a second module opened in a new browser tab while new one is not saved yet. 602 if (empty($data->params)) { 603 // This allows us to inject parameter settings into a new module. 604 $params = $app->getUserState('com_modules.add.module.params'); 605 606 if (is_array($params)) { 607 $data->set('params', $params); 608 } 609 } 610 } 611 612 $this->preprocessData('com_modules.module', $data); 613 614 return $data; 615 } 616 617 /** 618 * Method to get a single record. 619 * 620 * @param integer $pk The id of the primary key. 621 * 622 * @return mixed Object on success, false on failure. 623 * 624 * @since 1.6 625 */ 626 public function getItem($pk = null) 627 { 628 $pk = (!empty($pk)) ? (int) $pk : (int) $this->getState('module.id'); 629 $db = $this->getDatabase(); 630 631 if (!isset($this->_cache[$pk])) { 632 // Get a row instance. 633 $table = $this->getTable(); 634 635 // Attempt to load the row. 636 $return = $table->load($pk); 637 638 // Check for a table object error. 639 if ($return === false && $error = $table->getError()) { 640 $this->setError($error); 641 642 return false; 643 } 644 645 // Check if we are creating a new extension. 646 if (empty($pk)) { 647 if ($extensionId = (int) $this->getState('extension.id')) { 648 $query = $db->getQuery(true) 649 ->select($db->quoteName(['element', 'client_id'])) 650 ->from($db->quoteName('#__extensions')) 651 ->where($db->quoteName('extension_id') . ' = :extensionid') 652 ->where($db->quoteName('type') . ' = ' . $db->quote('module')) 653 ->bind(':extensionid', $extensionId, ParameterType::INTEGER); 654 $db->setQuery($query); 655 656 try { 657 $extension = $db->loadObject(); 658 } catch (\RuntimeException $e) { 659 $this->setError($e->getMessage()); 660 661 return false; 662 } 663 664 if (empty($extension)) { 665 $this->setError('COM_MODULES_ERROR_CANNOT_FIND_MODULE'); 666 667 return false; 668 } 669 670 // Extension found, prime some module values. 671 $table->module = $extension->element; 672 $table->client_id = $extension->client_id; 673 } else { 674 Factory::getApplication()->redirect(Route::_('index.php?option=com_modules&view=modules', false)); 675 676 return false; 677 } 678 } 679 680 // Convert to the \Joomla\CMS\Object\CMSObject before adding other data. 681 $properties = $table->getProperties(1); 682 $this->_cache[$pk] = ArrayHelper::toObject($properties, CMSObject::class); 683 684 // Convert the params field to an array. 685 $registry = new Registry($table->params); 686 $this->_cache[$pk]->params = $registry->toArray(); 687 688 // Determine the page assignment mode. 689 $query = $db->getQuery(true) 690 ->select($db->quoteName('menuid')) 691 ->from($db->quoteName('#__modules_menu')) 692 ->where($db->quoteName('moduleid') . ' = :moduleid') 693 ->bind(':moduleid', $pk, ParameterType::INTEGER); 694 $db->setQuery($query); 695 $assigned = $db->loadColumn(); 696 697 if (empty($pk)) { 698 // If this is a new module, assign to all pages. 699 $assignment = 0; 700 } elseif (empty($assigned)) { 701 // For an existing module it is assigned to none. 702 $assignment = '-'; 703 } else { 704 if ($assigned[0] > 0) { 705 $assignment = 1; 706 } elseif ($assigned[0] < 0) { 707 $assignment = -1; 708 } else { 709 $assignment = 0; 710 } 711 } 712 713 $this->_cache[$pk]->assigned = $assigned; 714 $this->_cache[$pk]->assignment = $assignment; 715 716 // Get the module XML. 717 $client = ApplicationHelper::getClientInfo($table->client_id); 718 $path = Path::clean($client->path . '/modules/' . $table->module . '/' . $table->module . '.xml'); 719 720 if (file_exists($path)) { 721 $this->_cache[$pk]->xml = simplexml_load_file($path); 722 } else { 723 $this->_cache[$pk]->xml = null; 724 } 725 } 726 727 return $this->_cache[$pk]; 728 } 729 730 /** 731 * Get the necessary data to load an item help screen. 732 * 733 * @return object An object with key, url, and local properties for loading the item help screen. 734 * 735 * @since 1.6 736 */ 737 public function getHelp() 738 { 739 return (object) array('key' => $this->helpKey, 'url' => $this->helpURL); 740 } 741 742 /** 743 * Returns a reference to the a Table object, always creating it. 744 * 745 * @param string $type The table type to instantiate 746 * @param string $prefix A prefix for the table class name. Optional. 747 * @param array $config Configuration array for model. Optional. 748 * 749 * @return Table A database object 750 * 751 * @since 1.6 752 */ 753 public function getTable($type = 'Module', $prefix = 'JTable', $config = array()) 754 { 755 return Table::getInstance($type, $prefix, $config); 756 } 757 758 /** 759 * Prepare and sanitise the table prior to saving. 760 * 761 * @param Table $table The database object 762 * 763 * @return void 764 * 765 * @since 1.6 766 */ 767 protected function prepareTable($table) 768 { 769 $table->title = htmlspecialchars_decode($table->title, ENT_QUOTES); 770 $table->position = trim($table->position); 771 } 772 773 /** 774 * Method to preprocess the form 775 * 776 * @param Form $form A form object. 777 * @param mixed $data The data expected for the form. 778 * @param string $group The name of the plugin group to import (defaults to "content"). 779 * 780 * @return void 781 * 782 * @since 1.6 783 * @throws \Exception if there is an error loading the form. 784 */ 785 protected function preprocessForm(Form $form, $data, $group = 'content') 786 { 787 $lang = Factory::getLanguage(); 788 $clientId = $this->getState('item.client_id'); 789 $module = $this->getState('item.module'); 790 791 $client = ApplicationHelper::getClientInfo($clientId); 792 $formFile = Path::clean($client->path . '/modules/' . $module . '/' . $module . '.xml'); 793 794 // Load the core and/or local language file(s). 795 $lang->load($module, $client->path) 796 || $lang->load($module, $client->path . '/modules/' . $module); 797 798 if (file_exists($formFile)) { 799 // Get the module form. 800 if (!$form->loadFile($formFile, false, '//config')) { 801 throw new \Exception(Text::_('JERROR_LOADFILE_FAILED')); 802 } 803 804 // Attempt to load the xml file. 805 if (!$xml = simplexml_load_file($formFile)) { 806 throw new \Exception(Text::_('JERROR_LOADFILE_FAILED')); 807 } 808 809 // Get the help data from the XML file if present. 810 $help = $xml->xpath('/extension/help'); 811 812 if (!empty($help)) { 813 $helpKey = trim((string) $help[0]['key']); 814 $helpURL = trim((string) $help[0]['url']); 815 816 $this->helpKey = $helpKey ?: $this->helpKey; 817 $this->helpURL = $helpURL ?: $this->helpURL; 818 } 819 } 820 821 // Load the default advanced params 822 Form::addFormPath(JPATH_ADMINISTRATOR . '/components/com_modules/models/forms'); 823 $form->loadFile('advanced', false); 824 825 // Load chrome specific params for global files 826 $chromePath = JPATH_SITE . '/layouts/chromes'; 827 $chromeFormFiles = Folder::files($chromePath, '.*\.xml'); 828 829 if ($chromeFormFiles) { 830 Form::addFormPath($chromePath); 831 832 foreach ($chromeFormFiles as $formFile) { 833 $form->loadFile(basename($formFile, '.xml'), false); 834 } 835 } 836 837 // Load chrome specific params for template files 838 $templates = ModulesHelper::getTemplates($clientId); 839 840 foreach ($templates as $template) { 841 $chromePath = $client->path . '/templates/' . $template->element . '/html/layouts/chromes'; 842 843 // Skip if there is no chrome folder in that template. 844 if (!is_dir($chromePath)) { 845 continue; 846 } 847 848 $chromeFormFiles = Folder::files($chromePath, '.*\.xml'); 849 850 if ($chromeFormFiles) { 851 Form::addFormPath($chromePath); 852 853 foreach ($chromeFormFiles as $formFile) { 854 $form->loadFile(basename($formFile, '.xml'), false); 855 } 856 } 857 } 858 859 // Trigger the default form events. 860 parent::preprocessForm($form, $data, $group); 861 } 862 863 /** 864 * Loads ContentHelper for filters before validating data. 865 * 866 * @param object $form The form to validate against. 867 * @param array $data The data to validate. 868 * @param string $group The name of the group(defaults to null). 869 * 870 * @return mixed Array of filtered data if valid, false otherwise. 871 * 872 * @since 1.1 873 */ 874 public function validate($form, $data, $group = null) 875 { 876 if (!Factory::getUser()->authorise('core.admin', 'com_modules')) { 877 if (isset($data['rules'])) { 878 unset($data['rules']); 879 } 880 } 881 882 return parent::validate($form, $data, $group); 883 } 884 885 /** 886 * Method to save the form data. 887 * 888 * @param array $data The form data. 889 * 890 * @return boolean True on success. 891 * 892 * @since 1.6 893 */ 894 public function save($data) 895 { 896 $input = Factory::getApplication()->input; 897 $table = $this->getTable(); 898 $pk = (!empty($data['id'])) ? $data['id'] : (int) $this->getState('module.id'); 899 $isNew = true; 900 $context = $this->option . '.' . $this->name; 901 902 // Include the plugins for the save event. 903 PluginHelper::importPlugin($this->events_map['save']); 904 905 // Load the row if saving an existing record. 906 if ($pk > 0) { 907 $table->load($pk); 908 $isNew = false; 909 } 910 911 // Alter the title and published state for Save as Copy 912 if ($input->get('task') == 'save2copy') { 913 $orig_table = clone $this->getTable(); 914 $orig_table->load((int) $input->getInt('id')); 915 $data['published'] = 0; 916 917 if ($data['title'] == $orig_table->title) { 918 $data['title'] = StringHelper::increment($data['title']); 919 } 920 } 921 922 // Bind the data. 923 if (!$table->bind($data)) { 924 $this->setError($table->getError()); 925 926 return false; 927 } 928 929 // Prepare the row for saving 930 $this->prepareTable($table); 931 932 // Check the data. 933 if (!$table->check()) { 934 $this->setError($table->getError()); 935 936 return false; 937 } 938 939 // Trigger the before save event. 940 $result = Factory::getApplication()->triggerEvent($this->event_before_save, array($context, &$table, $isNew)); 941 942 if (in_array(false, $result, true)) { 943 $this->setError($table->getError()); 944 945 return false; 946 } 947 948 // Store the data. 949 if (!$table->store()) { 950 $this->setError($table->getError()); 951 952 return false; 953 } 954 955 // Process the menu link mappings. 956 $assignment = $data['assignment'] ?? 0; 957 958 $table->id = (int) $table->id; 959 960 // Delete old module to menu item associations 961 $db = $this->getDatabase(); 962 $query = $db->getQuery(true) 963 ->delete($db->quoteName('#__modules_menu')) 964 ->where($db->quoteName('moduleid') . ' = :moduleid') 965 ->bind(':moduleid', $table->id, ParameterType::INTEGER); 966 $db->setQuery($query); 967 968 try { 969 $db->execute(); 970 } catch (\RuntimeException $e) { 971 $this->setError($e->getMessage()); 972 973 return false; 974 } 975 976 // If the assignment is numeric, then something is selected (otherwise it's none). 977 if (is_numeric($assignment)) { 978 // Variable is numeric, but could be a string. 979 $assignment = (int) $assignment; 980 981 // Logic check: if no module excluded then convert to display on all. 982 if ($assignment == -1 && empty($data['assigned'])) { 983 $assignment = 0; 984 } 985 986 // Check needed to stop a module being assigned to `All` 987 // and other menu items resulting in a module being displayed twice. 988 if ($assignment === 0) { 989 // Assign new module to `all` menu item associations. 990 $query->clear() 991 ->insert($db->quoteName('#__modules_menu')) 992 ->columns($db->quoteName(['moduleid', 'menuid'])) 993 ->values(implode(', ', [':moduleid', 0])) 994 ->bind(':moduleid', $table->id, ParameterType::INTEGER); 995 $db->setQuery($query); 996 997 try { 998 $db->execute(); 999 } catch (\RuntimeException $e) { 1000 $this->setError($e->getMessage()); 1001 1002 return false; 1003 } 1004 } elseif (!empty($data['assigned'])) { 1005 // Get the sign of the number. 1006 $sign = $assignment < 0 ? -1 : 1; 1007 1008 $query->clear() 1009 ->insert($db->quoteName('#__modules_menu')) 1010 ->columns($db->quoteName(array('moduleid', 'menuid'))); 1011 1012 foreach ($data['assigned'] as &$pk) { 1013 $query->values((int) $table->id . ',' . (int) $pk * $sign); 1014 } 1015 1016 $db->setQuery($query); 1017 1018 try { 1019 $db->execute(); 1020 } catch (\RuntimeException $e) { 1021 $this->setError($e->getMessage()); 1022 1023 return false; 1024 } 1025 } 1026 } 1027 1028 // Trigger the after save event. 1029 Factory::getApplication()->triggerEvent($this->event_after_save, array($context, &$table, $isNew)); 1030 1031 // Compute the extension id of this module in case the controller wants it. 1032 $query->clear() 1033 ->select($db->quoteName('extension_id')) 1034 ->from($db->quoteName('#__extensions', 'e')) 1035 ->join( 1036 'LEFT', 1037 $db->quoteName('#__modules', 'm') . ' ON ' . $db->quoteName('e.client_id') . ' = ' . (int) $table->client_id . 1038 ' AND ' . $db->quoteName('e.element') . ' = ' . $db->quoteName('m.module') 1039 ) 1040 ->where($db->quoteName('m.id') . ' = :id') 1041 ->bind(':id', $table->id, ParameterType::INTEGER); 1042 $db->setQuery($query); 1043 1044 try { 1045 $extensionId = $db->loadResult(); 1046 } catch (\RuntimeException $e) { 1047 Factory::getApplication()->enqueueMessage($e->getMessage(), 'error'); 1048 1049 return false; 1050 } 1051 1052 $this->setState('module.extension_id', $extensionId); 1053 $this->setState('module.id', $table->id); 1054 1055 // Clear modules cache 1056 $this->cleanCache(); 1057 1058 // Clean module cache 1059 parent::cleanCache($table->module); 1060 1061 return true; 1062 } 1063 1064 /** 1065 * A protected method to get a set of ordering conditions. 1066 * 1067 * @param object $table A record object. 1068 * 1069 * @return array An array of conditions to add to ordering queries. 1070 * 1071 * @since 1.6 1072 */ 1073 protected function getReorderConditions($table) 1074 { 1075 $db = $this->getDatabase(); 1076 1077 return [ 1078 $db->quoteName('client_id') . ' = ' . (int) $table->client_id, 1079 $db->quoteName('position') . ' = ' . $db->quote($table->position), 1080 ]; 1081 } 1082 1083 /** 1084 * Custom clean cache method for different clients 1085 * 1086 * @param string $group The name of the plugin group to import (defaults to null). 1087 * @param integer $clientId @deprecated 5.0 No longer used. 1088 * 1089 * @return void 1090 * 1091 * @since 1.6 1092 */ 1093 protected function cleanCache($group = null, $clientId = 0) 1094 { 1095 parent::cleanCache('com_modules'); 1096 } 1097 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Sep 7 05:41:13 2022 | Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer |