[ 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_postinstall 6 * 7 * @copyright (C) 2013 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\Postinstall\Administrator\Model; 12 13 use Joomla\CMS\Cache\CacheControllerFactoryInterface; 14 use Joomla\CMS\Cache\Controller\CallbackController; 15 use Joomla\CMS\Extension\ExtensionHelper; 16 use Joomla\CMS\Factory; 17 use Joomla\CMS\Filesystem\File; 18 use Joomla\CMS\HTML\HTMLHelper; 19 use Joomla\CMS\Language\Text; 20 use Joomla\CMS\MVC\Model\BaseDatabaseModel; 21 use Joomla\Component\Postinstall\Administrator\Helper\PostinstallHelper; 22 use Joomla\Database\ParameterType; 23 24 // phpcs:disable PSR1.Files.SideEffects 25 \defined('_JEXEC') or die; 26 // phpcs:enable PSR1.Files.SideEffects 27 28 /** 29 * Model class to manage postinstall messages 30 * 31 * @since 3.2 32 */ 33 class MessagesModel extends BaseDatabaseModel 34 { 35 /** 36 * Method to auto-populate the state. 37 * 38 * This method should only be called once per instantiation and is designed 39 * to be called on the first call to the getState() method unless the 40 * configuration flag to ignore the request is set. 41 * 42 * @return void 43 * 44 * @note Calling getState in this method will result in recursion. 45 * @since 4.0.0 46 */ 47 protected function populateState() 48 { 49 parent::populateState(); 50 51 $eid = (int) Factory::getApplication()->input->getInt('eid'); 52 53 if ($eid) { 54 $this->setState('eid', $eid); 55 } 56 } 57 58 /** 59 * Gets an item with the given id from the database 60 * 61 * @param integer $id The item id 62 * 63 * @return Object 64 * 65 * @since 3.2 66 */ 67 public function getItem($id) 68 { 69 $db = $this->getDatabase(); 70 $id = (int) $id; 71 72 $query = $db->getQuery(true); 73 $query->select( 74 [ 75 $db->quoteName('postinstall_message_id'), 76 $db->quoteName('extension_id'), 77 $db->quoteName('title_key'), 78 $db->quoteName('description_key'), 79 $db->quoteName('action_key'), 80 $db->quoteName('language_extension'), 81 $db->quoteName('language_client_id'), 82 $db->quoteName('type'), 83 $db->quoteName('action_file'), 84 $db->quoteName('action'), 85 $db->quoteName('condition_file'), 86 $db->quoteName('condition_method'), 87 $db->quoteName('version_introduced'), 88 $db->quoteName('enabled'), 89 ] 90 ) 91 ->from($db->quoteName('#__postinstall_messages')) 92 ->where($db->quoteName('postinstall_message_id') . ' = :id') 93 ->bind(':id', $id, ParameterType::INTEGER); 94 95 $db->setQuery($query); 96 97 $result = $db->loadObject(); 98 99 return $result; 100 } 101 102 /** 103 * Unpublishes specified post-install message 104 * 105 * @param integer $id The message id 106 * 107 * @return void 108 */ 109 public function unpublishMessage($id) 110 { 111 $db = $this->getDatabase(); 112 $id = (int) $id; 113 114 $query = $db->getQuery(true); 115 $query 116 ->update($db->quoteName('#__postinstall_messages')) 117 ->set($db->quoteName('enabled') . ' = 0') 118 ->where($db->quoteName('postinstall_message_id') . ' = :id') 119 ->bind(':id', $id, ParameterType::INTEGER); 120 $db->setQuery($query); 121 $db->execute(); 122 Factory::getCache()->clean('com_postinstall'); 123 } 124 125 /** 126 * Archives specified post-install message 127 * 128 * @param integer $id The message id 129 * 130 * @return void 131 * 132 * @since 4.2.0 133 */ 134 public function archiveMessage($id) 135 { 136 $db = $this->getDatabase(); 137 $id = (int) $id; 138 139 $query = $db->getQuery(true); 140 $query 141 ->update($db->quoteName('#__postinstall_messages')) 142 ->set($db->quoteName('enabled') . ' = 2') 143 ->where($db->quoteName('postinstall_message_id') . ' = :id') 144 ->bind(':id', $id, ParameterType::INTEGER); 145 $db->setQuery($query); 146 $db->execute(); 147 Factory::getCache()->clean('com_postinstall'); 148 } 149 150 /** 151 * Republishes specified post-install message 152 * 153 * @param integer $id The message id 154 * 155 * @return void 156 * 157 * @since 4.2.0 158 */ 159 public function republishMessage($id) 160 { 161 $db = $this->getDatabase(); 162 $id = (int) $id; 163 164 $query = $db->getQuery(true); 165 $query 166 ->update($db->quoteName('#__postinstall_messages')) 167 ->set($db->quoteName('enabled') . ' = 1') 168 ->where($db->quoteName('postinstall_message_id') . ' = :id') 169 ->bind(':id', $id, ParameterType::INTEGER); 170 $db->setQuery($query); 171 $db->execute(); 172 Factory::getCache()->clean('com_postinstall'); 173 } 174 175 /** 176 * Returns a list of messages from the #__postinstall_messages table 177 * 178 * @return array 179 * 180 * @since 3.2 181 */ 182 public function getItems() 183 { 184 // Add a forced extension filtering to the list 185 $eid = (int) $this->getState('eid', $this->getJoomlaFilesExtensionId()); 186 187 // Build a cache ID for the resulting data object 188 $cacheId = 'postinstall_messages.' . $eid; 189 190 $db = $this->getDatabase(); 191 $query = $db->getQuery(true); 192 $query->select( 193 [ 194 $db->quoteName('postinstall_message_id'), 195 $db->quoteName('extension_id'), 196 $db->quoteName('title_key'), 197 $db->quoteName('description_key'), 198 $db->quoteName('action_key'), 199 $db->quoteName('language_extension'), 200 $db->quoteName('language_client_id'), 201 $db->quoteName('type'), 202 $db->quoteName('action_file'), 203 $db->quoteName('action'), 204 $db->quoteName('condition_file'), 205 $db->quoteName('condition_method'), 206 $db->quoteName('version_introduced'), 207 $db->quoteName('enabled'), 208 ] 209 ) 210 ->from($db->quoteName('#__postinstall_messages')); 211 $query->where($db->quoteName('extension_id') . ' = :eid') 212 ->bind(':eid', $eid, ParameterType::INTEGER); 213 214 // Force filter only enabled messages 215 $query->whereIn($db->quoteName('enabled'), [1, 2]); 216 $db->setQuery($query); 217 218 try { 219 /** @var CallbackController $cache */ 220 $cache = $this->getCacheControllerFactory()->createCacheController('callback', ['defaultgroup' => 'com_postinstall']); 221 222 $result = $cache->get(array($db, 'loadObjectList'), array(), md5($cacheId), false); 223 } catch (\RuntimeException $e) { 224 $app = Factory::getApplication(); 225 $app->getLogger()->warning( 226 Text::sprintf('JLIB_APPLICATION_ERROR_MODULE_LOAD', $e->getMessage()), 227 array('category' => 'jerror') 228 ); 229 230 return array(); 231 } 232 233 $this->onProcessList($result); 234 235 return $result; 236 } 237 238 /** 239 * Returns a count of all enabled messages from the #__postinstall_messages table 240 * 241 * @return integer 242 * 243 * @since 4.0.0 244 */ 245 public function getItemsCount() 246 { 247 $db = $this->getDatabase(); 248 $query = $db->getQuery(true); 249 $query->select( 250 [ 251 $db->quoteName('language_extension'), 252 $db->quoteName('language_client_id'), 253 $db->quoteName('condition_file'), 254 $db->quoteName('condition_method'), 255 ] 256 ) 257 ->from($db->quoteName('#__postinstall_messages')); 258 259 // Force filter only enabled messages 260 $query->where($db->quoteName('enabled') . ' = 1'); 261 $db->setQuery($query); 262 263 try { 264 /** @var CallbackController $cache */ 265 $cache = Factory::getContainer()->get(CacheControllerFactoryInterface::class) 266 ->createCacheController('callback', ['defaultgroup' => 'com_postinstall']); 267 268 // Get the resulting data object for cache ID 'all.1' from com_postinstall group. 269 $result = $cache->get(array($db, 'loadObjectList'), array(), md5('all.1'), false); 270 } catch (\RuntimeException $e) { 271 $app = Factory::getApplication(); 272 $app->getLogger()->warning( 273 Text::sprintf('JLIB_APPLICATION_ERROR_MODULE_LOAD', $e->getMessage()), 274 array('category' => 'jerror') 275 ); 276 277 return 0; 278 } 279 280 $this->onProcessList($result); 281 282 return \count($result); 283 } 284 285 /** 286 * Returns the name of an extension, as registered in the #__extensions table 287 * 288 * @param integer $eid The extension ID 289 * 290 * @return string The extension name 291 * 292 * @since 3.2 293 */ 294 public function getExtensionName($eid) 295 { 296 // Load the extension's information from the database 297 $db = $this->getDatabase(); 298 $eid = (int) $eid; 299 300 $query = $db->getQuery(true) 301 ->select( 302 [ 303 $db->quoteName('name'), 304 $db->quoteName('element'), 305 $db->quoteName('client_id'), 306 ] 307 ) 308 ->from($db->quoteName('#__extensions')) 309 ->where($db->quoteName('extension_id') . ' = :eid') 310 ->bind(':eid', $eid, ParameterType::INTEGER) 311 ->setLimit(1); 312 313 $db->setQuery($query); 314 315 $extension = $db->loadObject(); 316 317 if (!is_object($extension)) { 318 return ''; 319 } 320 321 // Load language files 322 $basePath = JPATH_ADMINISTRATOR; 323 324 if ($extension->client_id == 0) { 325 $basePath = JPATH_SITE; 326 } 327 328 $lang = Factory::getApplication()->getLanguage(); 329 $lang->load($extension->element, $basePath); 330 331 // Return the localised name 332 return Text::_(strtoupper($extension->name)); 333 } 334 335 /** 336 * Resets all messages for an extension 337 * 338 * @param integer $eid The extension ID whose messages we'll reset 339 * 340 * @return mixed False if we fail, a db cursor otherwise 341 * 342 * @since 3.2 343 */ 344 public function resetMessages($eid) 345 { 346 $db = $this->getDatabase(); 347 $eid = (int) $eid; 348 349 $query = $db->getQuery(true) 350 ->update($db->quoteName('#__postinstall_messages')) 351 ->set($db->quoteName('enabled') . ' = 1') 352 ->where($db->quoteName('extension_id') . ' = :eid') 353 ->bind(':eid', $eid, ParameterType::INTEGER); 354 $db->setQuery($query); 355 356 $result = $db->execute(); 357 Factory::getCache()->clean('com_postinstall'); 358 359 return $result; 360 } 361 362 /** 363 * Hides all messages for an extension 364 * 365 * @param integer $eid The extension ID whose messages we'll hide 366 * 367 * @return mixed False if we fail, a db cursor otherwise 368 * 369 * @since 3.8.7 370 */ 371 public function hideMessages($eid) 372 { 373 $db = $this->getDatabase(); 374 $eid = (int) $eid; 375 376 $query = $db->getQuery(true) 377 ->update($db->quoteName('#__postinstall_messages')) 378 ->set($db->quoteName('enabled') . ' = 0') 379 ->where($db->quoteName('extension_id') . ' = :eid') 380 ->bind(':eid', $eid, ParameterType::INTEGER); 381 $db->setQuery($query); 382 383 $result = $db->execute(); 384 Factory::getCache()->clean('com_postinstall'); 385 386 return $result; 387 } 388 389 /** 390 * List post-processing. This is used to run the programmatic display 391 * conditions against each list item and decide if we have to show it or 392 * not. 393 * 394 * Do note that this a core method of the RAD Layer which operates directly 395 * on the list it's being fed. A little touch of modern magic. 396 * 397 * @param array &$resultArray A list of items to process 398 * 399 * @return void 400 * 401 * @since 3.2 402 */ 403 protected function onProcessList(&$resultArray) 404 { 405 $unset_keys = array(); 406 $language_extensions = array(); 407 408 // Order the results DESC so the newest is on the top. 409 $resultArray = array_reverse($resultArray); 410 411 foreach ($resultArray as $key => $item) { 412 // Filter out messages based on dynamically loaded programmatic conditions. 413 if (!empty($item->condition_file) && !empty($item->condition_method)) { 414 $helper = new PostinstallHelper(); 415 $file = $helper->parsePath($item->condition_file); 416 417 if (File::exists($file)) { 418 require_once $file; 419 420 $result = call_user_func($item->condition_method); 421 422 if ($result === false) { 423 $unset_keys[] = $key; 424 } 425 } 426 } 427 428 // Load the necessary language files. 429 if (!empty($item->language_extension)) { 430 $hash = $item->language_client_id . '-' . $item->language_extension; 431 432 if (!in_array($hash, $language_extensions)) { 433 $language_extensions[] = $hash; 434 Factory::getApplication()->getLanguage()->load($item->language_extension, $item->language_client_id == 0 ? JPATH_SITE : JPATH_ADMINISTRATOR); 435 } 436 } 437 } 438 439 if (!empty($unset_keys)) { 440 foreach ($unset_keys as $key) { 441 unset($resultArray[$key]); 442 } 443 } 444 } 445 446 /** 447 * Get the dropdown options for the list of component with post-installation messages 448 * 449 * @since 3.4 450 * 451 * @return array Compatible with JHtmlSelect::genericList 452 */ 453 public function getComponentOptions() 454 { 455 $db = $this->getDatabase(); 456 457 $query = $db->getQuery(true) 458 ->select($db->quoteName('extension_id')) 459 ->from($db->quoteName('#__postinstall_messages')) 460 ->group($db->quoteName('extension_id')); 461 $db->setQuery($query); 462 $extension_ids = $db->loadColumn(); 463 464 $options = array(); 465 466 Factory::getApplication()->getLanguage()->load('files_joomla.sys', JPATH_SITE, null, false, false); 467 468 foreach ($extension_ids as $eid) { 469 $options[] = HTMLHelper::_('select.option', $eid, $this->getExtensionName($eid)); 470 } 471 472 return $options; 473 } 474 475 /** 476 * Adds or updates a post-installation message (PIM) definition. You can use this in your post-installation script using this code: 477 * 478 * require_once JPATH_LIBRARIES . '/fof/include.php'; 479 * FOFModel::getTmpInstance('Messages', 'PostinstallModel')->addPostInstallationMessage($options); 480 * 481 * The $options array contains the following mandatory keys: 482 * 483 * extension_id The numeric ID of the extension this message is for (see the #__extensions table) 484 * 485 * type One of message, link or action. Their meaning is: 486 * message Informative message. The user can dismiss it. 487 * link The action button links to a URL. The URL is defined in the action parameter. 488 * action A PHP action takes place when the action button is clicked. You need to specify the action_file 489 * (RAD path to the PHP file) and action (PHP function name) keys. See below for more information. 490 * 491 * title_key The Text language key for the title of this PIM. 492 * Example: COM_FOOBAR_POSTINSTALL_MESSAGEONE_TITLE 493 * 494 * description_key The Text language key for the main body (description) of this PIM 495 * Example: COM_FOOBAR_POSTINSTALL_MESSAGEONE_DESCRIPTION 496 * 497 * action_key The Text language key for the action button. Ignored and not required when type=message 498 * Example: COM_FOOBAR_POSTINSTALL_MESSAGEONE_ACTION 499 * 500 * language_extension The extension name which holds the language keys used above. 501 * For example, com_foobar, mod_something, plg_system_whatever, tpl_mytemplate 502 * 503 * language_client_id Should we load the frontend (0) or backend (1) language keys? 504 * 505 * version_introduced Which was the version of your extension where this message appeared for the first time? 506 * Example: 3.2.1 507 * 508 * enabled Must be 1 for this message to be enabled. If you omit it, it defaults to 1. 509 * 510 * condition_file The RAD path to a PHP file containing a PHP function which determines whether this message should be shown to 511 * the user. @see FOFTemplateUtils::parsePath() for RAD path format. Joomla! will include this file before calling 512 * the condition_method. 513 * Example: admin://components/com_foobar/helpers/postinstall.php 514 * 515 * condition_method The name of a PHP function which will be used to determine whether to show this message to the user. This must be 516 * a simple PHP user function (not a class method, static method etc) which returns true to show the message and false 517 * to hide it. This function is defined in the condition_file. 518 * Example: com_foobar_postinstall_messageone_condition 519 * 520 * When type=message no additional keys are required. 521 * 522 * When type=link the following additional keys are required: 523 * 524 * action The URL which will open when the user clicks on the PIM's action button 525 * Example: index.php?option=com_foobar&view=tools&task=installSampleData 526 * 527 * When type=action the following additional keys are required: 528 * 529 * action_file The RAD path to a PHP file containing a PHP function which performs the action of this PIM. @see FOFTemplateUtils::parsePath() 530 * for RAD path format. Joomla! will include this file before calling the function defined in the action key below. 531 * Example: admin://components/com_foobar/helpers/postinstall.php 532 * 533 * action The name of a PHP function which will be used to run the action of this PIM. This must be a simple PHP user function 534 * (not a class method, static method etc) which returns no result. 535 * Example: com_foobar_postinstall_messageone_action 536 * 537 * @param array $options See description 538 * 539 * @return $this 540 * 541 * @throws \Exception 542 */ 543 public function addPostInstallationMessage(array $options) 544 { 545 // Make sure there are options set 546 if (!is_array($options)) { 547 throw new \Exception('Post-installation message definitions must be of type array', 500); 548 } 549 550 // Initialise array keys 551 $defaultOptions = array( 552 'extension_id' => '', 553 'type' => '', 554 'title_key' => '', 555 'description_key' => '', 556 'action_key' => '', 557 'language_extension' => '', 558 'language_client_id' => '', 559 'action_file' => '', 560 'action' => '', 561 'condition_file' => '', 562 'condition_method' => '', 563 'version_introduced' => '', 564 'enabled' => '1', 565 ); 566 567 $options = array_merge($defaultOptions, $options); 568 569 // Array normalisation. Removes array keys not belonging to a definition. 570 $defaultKeys = array_keys($defaultOptions); 571 $allKeys = array_keys($options); 572 $extraKeys = array_diff($allKeys, $defaultKeys); 573 574 if (!empty($extraKeys)) { 575 foreach ($extraKeys as $key) { 576 unset($options[$key]); 577 } 578 } 579 580 // Normalisation of integer values 581 $options['extension_id'] = (int) $options['extension_id']; 582 $options['language_client_id'] = (int) $options['language_client_id']; 583 $options['enabled'] = (int) $options['enabled']; 584 585 // Normalisation of 0/1 values 586 foreach (array('language_client_id', 'enabled') as $key) { 587 $options[$key] = $options[$key] ? 1 : 0; 588 } 589 590 // Make sure there's an extension_id 591 if (!(int) $options['extension_id']) { 592 throw new \Exception('Post-installation message definitions need an extension_id', 500); 593 } 594 595 // Make sure there's a valid type 596 if (!in_array($options['type'], array('message', 'link', 'action'))) { 597 throw new \Exception('Post-installation message definitions need to declare a type of message, link or action', 500); 598 } 599 600 // Make sure there's a title key 601 if (empty($options['title_key'])) { 602 throw new \Exception('Post-installation message definitions need a title key', 500); 603 } 604 605 // Make sure there's a description key 606 if (empty($options['description_key'])) { 607 throw new \Exception('Post-installation message definitions need a description key', 500); 608 } 609 610 // If the type is anything other than message you need an action key 611 if (($options['type'] != 'message') && empty($options['action_key'])) { 612 throw new \Exception('Post-installation message definitions need an action key when they are of type "' . $options['type'] . '"', 500); 613 } 614 615 // You must specify the language extension 616 if (empty($options['language_extension'])) { 617 throw new \Exception('Post-installation message definitions need to specify which extension contains their language keys', 500); 618 } 619 620 // The action file and method are only required for the "action" type 621 if ($options['type'] == 'action') { 622 if (empty($options['action_file'])) { 623 throw new \Exception('Post-installation message definitions need an action file when they are of type "action"', 500); 624 } 625 626 $helper = new PostinstallHelper(); 627 $file_path = $helper->parsePath($options['action_file']); 628 629 if (!@is_file($file_path)) { 630 throw new \Exception('The action file ' . $options['action_file'] . ' of your post-installation message definition does not exist', 500); 631 } 632 633 if (empty($options['action'])) { 634 throw new \Exception('Post-installation message definitions need an action (function name) when they are of type "action"', 500); 635 } 636 } 637 638 if ($options['type'] == 'link') { 639 if (empty($options['link'])) { 640 throw new \Exception('Post-installation message definitions need an action (URL) when they are of type "link"', 500); 641 } 642 } 643 644 // The condition file and method are only required when the type is not "message" 645 if ($options['type'] != 'message') { 646 if (empty($options['condition_file'])) { 647 throw new \Exception('Post-installation message definitions need a condition file when they are of type "' . $options['type'] . '"', 500); 648 } 649 650 $helper = new PostinstallHelper(); 651 $file_path = $helper->parsePath($options['condition_file']); 652 653 if (!@is_file($file_path)) { 654 throw new \Exception('The condition file ' . $options['condition_file'] . ' of your post-installation message definition does not exist', 500); 655 } 656 657 if (empty($options['condition_method'])) { 658 throw new \Exception( 659 'Post-installation message definitions need a condition method (function name) when they are of type "' 660 . $options['type'] . '"', 661 500 662 ); 663 } 664 } 665 666 // Check if the definition exists 667 $table = $this->getTable(); 668 $tableName = $table->getTableName(); 669 $extensionId = (int) $options['extension_id']; 670 671 $db = $this->getDatabase(); 672 $query = $db->getQuery(true) 673 ->select('*') 674 ->from($db->quoteName($tableName)) 675 ->where( 676 [ 677 $db->quoteName('extension_id') . ' = :extensionId', 678 $db->quoteName('type') . ' = :type', 679 $db->quoteName('title_key') . ' = :titleKey', 680 ] 681 ) 682 ->bind(':extensionId', $extensionId, ParameterType::INTEGER) 683 ->bind(':type', $options['type']) 684 ->bind(':titleKey', $options['title_key']); 685 686 $existingRow = $db->setQuery($query)->loadAssoc(); 687 688 // Is the existing definition the same as the one we're trying to save? 689 if (!empty($existingRow)) { 690 $same = true; 691 692 foreach ($options as $k => $v) { 693 if ($existingRow[$k] != $v) { 694 $same = false; 695 break; 696 } 697 } 698 699 // Trying to add the same row as the existing one; quit 700 if ($same) { 701 return $this; 702 } 703 704 // Otherwise it's not the same row. Remove the old row before insert a new one. 705 $query = $db->getQuery(true) 706 ->delete($db->quoteName($tableName)) 707 ->where( 708 [ 709 $db->quoteName('extension_id') . ' = :extensionId', 710 $db->quoteName('type') . ' = :type', 711 $db->quoteName('title_key') . ' = :titleKey', 712 ] 713 ) 714 ->bind(':extensionId', $extensionId, ParameterType::INTEGER) 715 ->bind(':type', $options['type']) 716 ->bind(':titleKey', $options['title_key']); 717 718 $db->setQuery($query)->execute(); 719 } 720 721 // Insert the new row 722 $options = (object) $options; 723 $db->insertObject($tableName, $options); 724 Factory::getCache()->clean('com_postinstall'); 725 726 return $this; 727 } 728 729 /** 730 * Returns the library extension ID. 731 * 732 * @return integer 733 * 734 * @since 4.0.0 735 */ 736 public function getJoomlaFilesExtensionId() 737 { 738 return ExtensionHelper::getExtensionRecord('joomla', 'file')->extension_id; 739 } 740 }
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 |