[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/administrator/components/com_modules/src/Model/ -> ModuleModel.php (source)

   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  }


Generated: Wed Sep 7 05:41:13 2022 Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer