[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/administrator/components/com_content/src/Model/ -> ArticleModel.php (source)

   1  <?php
   2  
   3  /**
   4   * @package     Joomla.Administrator
   5   * @subpackage  com_content
   6   *
   7   * @copyright   (C) 2008 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\Content\Administrator\Model;
  12  
  13  use Joomla\CMS\Date\Date;
  14  use Joomla\CMS\Event\AbstractEvent;
  15  use Joomla\CMS\Factory;
  16  use Joomla\CMS\Filter\InputFilter;
  17  use Joomla\CMS\Filter\OutputFilter;
  18  use Joomla\CMS\Form\Form;
  19  use Joomla\CMS\Form\FormFactoryInterface;
  20  use Joomla\CMS\Helper\TagsHelper;
  21  use Joomla\CMS\Language\Associations;
  22  use Joomla\CMS\Language\LanguageHelper;
  23  use Joomla\CMS\Language\Text;
  24  use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
  25  use Joomla\CMS\MVC\Model\AdminModel;
  26  use Joomla\CMS\MVC\Model\WorkflowBehaviorTrait;
  27  use Joomla\CMS\MVC\Model\WorkflowModelInterface;
  28  use Joomla\CMS\Plugin\PluginHelper;
  29  use Joomla\CMS\String\PunycodeHelper;
  30  use Joomla\CMS\Table\TableInterface;
  31  use Joomla\CMS\Tag\TaggableTableInterface;
  32  use Joomla\CMS\UCM\UCMType;
  33  use Joomla\CMS\Versioning\VersionableModelTrait;
  34  use Joomla\CMS\Workflow\Workflow;
  35  use Joomla\Component\Categories\Administrator\Helper\CategoriesHelper;
  36  use Joomla\Component\Fields\Administrator\Helper\FieldsHelper;
  37  use Joomla\Database\ParameterType;
  38  use Joomla\Registry\Registry;
  39  use Joomla\Utilities\ArrayHelper;
  40  
  41  // phpcs:disable PSR1.Files.SideEffects
  42  \defined('_JEXEC') or die;
  43  // phpcs:enable PSR1.Files.SideEffects
  44  
  45  /**
  46   * Item Model for an Article.
  47   *
  48   * @since  1.6
  49   */
  50  
  51  class ArticleModel extends AdminModel implements WorkflowModelInterface
  52  {
  53      use WorkflowBehaviorTrait;
  54      use VersionableModelTrait;
  55  
  56      /**
  57       * The prefix to use with controller messages.
  58       *
  59       * @var    string
  60       * @since  1.6
  61       */
  62      protected $text_prefix = 'COM_CONTENT';
  63  
  64      /**
  65       * The type alias for this content type (for example, 'com_content.article').
  66       *
  67       * @var    string
  68       * @since  3.2
  69       */
  70      public $typeAlias = 'com_content.article';
  71  
  72      /**
  73       * The context used for the associations table
  74       *
  75       * @var    string
  76       * @since  3.4.4
  77       */
  78      protected $associationsContext = 'com_content.item';
  79  
  80      /**
  81       * The event to trigger before changing featured status one or more items.
  82       *
  83       * @var    string
  84       * @since  4.0.0
  85       */
  86      protected $event_before_change_featured = null;
  87  
  88      /**
  89       * The event to trigger after changing featured status one or more items.
  90       *
  91       * @var    string
  92       * @since  4.0.0
  93       */
  94      protected $event_after_change_featured = null;
  95  
  96      /**
  97       * Constructor.
  98       *
  99       * @param   array                 $config       An array of configuration options (name, state, dbo, table_path, ignore_request).
 100       * @param   MVCFactoryInterface   $factory      The factory.
 101       * @param   FormFactoryInterface  $formFactory  The form factory.
 102       *
 103       * @since   1.6
 104       * @throws  \Exception
 105       */
 106      public function __construct($config = array(), MVCFactoryInterface $factory = null, FormFactoryInterface $formFactory = null)
 107      {
 108          $config['events_map'] = $config['events_map'] ?? [];
 109  
 110          $config['events_map'] = array_merge(
 111              ['featured' => 'content'],
 112              $config['events_map']
 113          );
 114  
 115          parent::__construct($config, $factory, $formFactory);
 116  
 117          // Set the featured status change events
 118          $this->event_before_change_featured = $config['event_before_change_featured'] ?? $this->event_before_change_featured;
 119          $this->event_before_change_featured = $this->event_before_change_featured ?? 'onContentBeforeChangeFeatured';
 120          $this->event_after_change_featured  = $config['event_after_change_featured'] ?? $this->event_after_change_featured;
 121          $this->event_after_change_featured  = $this->event_after_change_featured ?? 'onContentAfterChangeFeatured';
 122  
 123          $this->setUpWorkflow('com_content.article');
 124      }
 125  
 126      /**
 127       * Function that can be overridden to do any data cleanup after batch copying data
 128       *
 129       * @param   TableInterface  $table  The table object containing the newly created item
 130       * @param   integer         $newId  The id of the new item
 131       * @param   integer         $oldId  The original item id
 132       *
 133       * @return  void
 134       *
 135       * @since  3.8.12
 136       */
 137      protected function cleanupPostBatchCopy(TableInterface $table, $newId, $oldId)
 138      {
 139          // Check if the article was featured and update the #__content_frontpage table
 140          if ($table->featured == 1) {
 141              $db = $this->getDatabase();
 142              $query = $db->getQuery(true)
 143                  ->select(
 144                      [
 145                          $db->quoteName('featured_up'),
 146                          $db->quoteName('featured_down'),
 147                      ]
 148                  )
 149                  ->from($db->quoteName('#__content_frontpage'))
 150                  ->where($db->quoteName('content_id') . ' = :oldId')
 151                  ->bind(':oldId', $oldId, ParameterType::INTEGER);
 152  
 153              $featured = $db->setQuery($query)->loadObject();
 154  
 155              if ($featured) {
 156                  $query = $db->getQuery(true)
 157                      ->insert($db->quoteName('#__content_frontpage'))
 158                      ->values(':newId, 0, :featuredUp, :featuredDown')
 159                      ->bind(':newId', $newId, ParameterType::INTEGER)
 160                      ->bind(':featuredUp', $featured->featured_up, $featured->featured_up ? ParameterType::STRING : ParameterType::NULL)
 161                      ->bind(':featuredDown', $featured->featured_down, $featured->featured_down ? ParameterType::STRING : ParameterType::NULL);
 162  
 163                      $db->setQuery($query);
 164                      $db->execute();
 165              }
 166          }
 167  
 168          $this->workflowCleanupBatchMove($oldId, $newId);
 169  
 170          $oldItem = $this->getTable();
 171          $oldItem->load($oldId);
 172          $fields = FieldsHelper::getFields('com_content.article', $oldItem, true);
 173  
 174          $fieldsData = array();
 175  
 176          if (!empty($fields)) {
 177              $fieldsData['com_fields'] = array();
 178  
 179              foreach ($fields as $field) {
 180                  $fieldsData['com_fields'][$field->name] = $field->rawvalue;
 181              }
 182          }
 183  
 184          Factory::getApplication()->triggerEvent('onContentAfterSave', array('com_content.article', &$this->table, false, $fieldsData));
 185      }
 186  
 187      /**
 188       * Batch move categories to a new category.
 189       *
 190       * @param   integer  $value     The new category ID.
 191       * @param   array    $pks       An array of row IDs.
 192       * @param   array    $contexts  An array of item contexts.
 193       *
 194       * @return  boolean  True on success.
 195       *
 196       * @since   3.8.6
 197       */
 198      protected function batchMove($value, $pks, $contexts)
 199      {
 200          if (empty($this->batchSet)) {
 201              // Set some needed variables.
 202              $this->user = Factory::getUser();
 203              $this->table = $this->getTable();
 204              $this->tableClassName = get_class($this->table);
 205              $this->contentType = new UCMType();
 206              $this->type = $this->contentType->getTypeByTable($this->tableClassName);
 207          }
 208  
 209          $categoryId = (int) $value;
 210  
 211          if (!$this->checkCategoryId($categoryId)) {
 212              return false;
 213          }
 214  
 215          PluginHelper::importPlugin('system');
 216  
 217          // Parent exists so we proceed
 218          foreach ($pks as $pk) {
 219              if (!$this->user->authorise('core.edit', $contexts[$pk])) {
 220                  $this->setError(Text::_('JLIB_APPLICATION_ERROR_BATCH_CANNOT_EDIT'));
 221  
 222                  return false;
 223              }
 224  
 225              // Check that the row actually exists
 226              if (!$this->table->load($pk)) {
 227                  if ($error = $this->table->getError()) {
 228                      // Fatal error
 229                      $this->setError($error);
 230  
 231                      return false;
 232                  } else {
 233                      // Not fatal error
 234                      $this->setError(Text::sprintf('JLIB_APPLICATION_ERROR_BATCH_MOVE_ROW_NOT_FOUND', $pk));
 235                      continue;
 236                  }
 237              }
 238  
 239              $fields = FieldsHelper::getFields('com_content.article', $this->table, true);
 240  
 241              $fieldsData = array();
 242  
 243              if (!empty($fields)) {
 244                  $fieldsData['com_fields'] = array();
 245  
 246                  foreach ($fields as $field) {
 247                      $fieldsData['com_fields'][$field->name] = $field->rawvalue;
 248                  }
 249              }
 250  
 251              // Set the new category ID
 252              $this->table->catid = $categoryId;
 253  
 254              // We don't want to modify tags - so remove the associated tags helper
 255              if ($this->table instanceof TaggableTableInterface) {
 256                  $this->table->clearTagsHelper();
 257              }
 258  
 259              // Check the row.
 260              if (!$this->table->check()) {
 261                  $this->setError($this->table->getError());
 262  
 263                  return false;
 264              }
 265  
 266              // Store the row.
 267              if (!$this->table->store()) {
 268                  $this->setError($this->table->getError());
 269  
 270                  return false;
 271              }
 272  
 273              // Run event for moved article
 274              Factory::getApplication()->triggerEvent('onContentAfterSave', array('com_content.article', &$this->table, false, $fieldsData));
 275          }
 276  
 277          // Clean the cache
 278          $this->cleanCache();
 279  
 280          return true;
 281      }
 282  
 283      /**
 284       * Method to test whether a record can be deleted.
 285       *
 286       * @param   object  $record  A record object.
 287       *
 288       * @return  boolean  True if allowed to delete the record. Defaults to the permission set in the component.
 289       *
 290       * @since   1.6
 291       */
 292      protected function canDelete($record)
 293      {
 294          if (empty($record->id) || ($record->state != -2)) {
 295              return false;
 296          }
 297  
 298          return Factory::getUser()->authorise('core.delete', 'com_content.article.' . (int) $record->id);
 299      }
 300  
 301      /**
 302       * Method to test whether a record can have its state edited.
 303       *
 304       * @param   object  $record  A record object.
 305       *
 306       * @return  boolean  True if allowed to change the state of the record. Defaults to the permission set in the component.
 307       *
 308       * @since   1.6
 309       */
 310      protected function canEditState($record)
 311      {
 312          $user = Factory::getUser();
 313  
 314          // Check for existing article.
 315          if (!empty($record->id)) {
 316              return $user->authorise('core.edit.state', 'com_content.article.' . (int) $record->id);
 317          }
 318  
 319          // New article, so check against the category.
 320          if (!empty($record->catid)) {
 321              return $user->authorise('core.edit.state', 'com_content.category.' . (int) $record->catid);
 322          }
 323  
 324          // Default to component settings if neither article nor category known.
 325          return parent::canEditState($record);
 326      }
 327  
 328      /**
 329       * Prepare and sanitise the table data prior to saving.
 330       *
 331       * @param   \Joomla\CMS\Table\Table  $table  A Table object.
 332       *
 333       * @return  void
 334       *
 335       * @since   1.6
 336       */
 337      protected function prepareTable($table)
 338      {
 339          // Set the publish date to now
 340          if ($table->state == Workflow::CONDITION_PUBLISHED && (int) $table->publish_up == 0) {
 341              $table->publish_up = Factory::getDate()->toSql();
 342          }
 343  
 344          if ($table->state == Workflow::CONDITION_PUBLISHED && intval($table->publish_down) == 0) {
 345              $table->publish_down = null;
 346          }
 347  
 348          // Increment the content version number.
 349          $table->version++;
 350  
 351          // Reorder the articles within the category so the new article is first
 352          if (empty($table->id)) {
 353              $table->reorder('catid = ' . (int) $table->catid . ' AND state >= 0');
 354          }
 355      }
 356  
 357      /**
 358       * Method to change the published state of one or more records.
 359       *
 360       * @param   array    &$pks   A list of the primary keys to change.
 361       * @param   integer  $value  The value of the published state.
 362       *
 363       * @return  boolean  True on success.
 364       *
 365       * @since   4.0.0
 366       */
 367      public function publish(&$pks, $value = 1)
 368      {
 369          $this->workflowBeforeStageChange();
 370  
 371          return parent::publish($pks, $value);
 372      }
 373  
 374      /**
 375       * Method to get a single record.
 376       *
 377       * @param   integer  $pk  The id of the primary key.
 378       *
 379       * @return  mixed  Object on success, false on failure.
 380       */
 381      public function getItem($pk = null)
 382      {
 383          if ($item = parent::getItem($pk)) {
 384              // Convert the params field to an array.
 385              $registry = new Registry($item->attribs);
 386              $item->attribs = $registry->toArray();
 387  
 388              // Convert the metadata field to an array.
 389              $registry = new Registry($item->metadata);
 390              $item->metadata = $registry->toArray();
 391  
 392              // Convert the images field to an array.
 393              $registry = new Registry($item->images);
 394              $item->images = $registry->toArray();
 395  
 396              // Convert the urls field to an array.
 397              $registry = new Registry($item->urls);
 398              $item->urls = $registry->toArray();
 399  
 400              $item->articletext = ($item->fulltext !== null && trim($item->fulltext) != '') ? $item->introtext . '<hr id="system-readmore">' . $item->fulltext : $item->introtext;
 401  
 402              if (!empty($item->id)) {
 403                  $item->tags = new TagsHelper();
 404                  $item->tags->getTagIds($item->id, 'com_content.article');
 405  
 406                  $item->featured_up   = null;
 407                  $item->featured_down = null;
 408  
 409                  if ($item->featured) {
 410                      // Get featured dates.
 411                      $db = $this->getDatabase();
 412                      $query = $db->getQuery(true)
 413                          ->select(
 414                              [
 415                                  $db->quoteName('featured_up'),
 416                                  $db->quoteName('featured_down'),
 417                              ]
 418                          )
 419                          ->from($db->quoteName('#__content_frontpage'))
 420                          ->where($db->quoteName('content_id') . ' = :id')
 421                          ->bind(':id', $item->id, ParameterType::INTEGER);
 422  
 423                      $featured = $db->setQuery($query)->loadObject();
 424  
 425                      if ($featured) {
 426                          $item->featured_up   = $featured->featured_up;
 427                          $item->featured_down = $featured->featured_down;
 428                      }
 429                  }
 430              }
 431          }
 432  
 433          // Load associated content items
 434          $assoc = Associations::isEnabled();
 435  
 436          if ($assoc) {
 437              $item->associations = array();
 438  
 439              if ($item->id != null) {
 440                  $associations = Associations::getAssociations('com_content', '#__content', 'com_content.item', $item->id);
 441  
 442                  foreach ($associations as $tag => $association) {
 443                      $item->associations[$tag] = $association->id;
 444                  }
 445              }
 446          }
 447  
 448          return $item;
 449      }
 450  
 451      /**
 452       * Method to get the record form.
 453       *
 454       * @param   array    $data      Data for the form.
 455       * @param   boolean  $loadData  True if the form is to load its own data (default case), false if not.
 456       *
 457       * @return  Form|boolean  A Form object on success, false on failure
 458       *
 459       * @since   1.6
 460       */
 461      public function getForm($data = array(), $loadData = true)
 462      {
 463          $app  = Factory::getApplication();
 464  
 465          // Get the form.
 466          $form = $this->loadForm('com_content.article', 'article', array('control' => 'jform', 'load_data' => $loadData));
 467  
 468          if (empty($form)) {
 469              return false;
 470          }
 471  
 472          // Object uses for checking edit state permission of article
 473          $record = new \stdClass();
 474  
 475          // Get ID of the article from input, for frontend, we use a_id while backend uses id
 476          $articleIdFromInput = $app->isClient('site')
 477              ? $app->input->getInt('a_id', 0)
 478              : $app->input->getInt('id', 0);
 479  
 480          // On edit article, we get ID of article from article.id state, but on save, we use data from input
 481          $id = (int) $this->getState('article.id', $articleIdFromInput);
 482  
 483          $record->id = $id;
 484  
 485          // For new articles we load the potential state + associations
 486          if ($id == 0 && $formField = $form->getField('catid')) {
 487              $assignedCatids = $data['catid'] ?? $form->getValue('catid');
 488  
 489              $assignedCatids = is_array($assignedCatids)
 490                  ? (int) reset($assignedCatids)
 491                  : (int) $assignedCatids;
 492  
 493              // Try to get the category from the category field
 494              if (empty($assignedCatids)) {
 495                  $assignedCatids = $formField->getAttribute('default', null);
 496  
 497                  if (!$assignedCatids) {
 498                      // Choose the first category available
 499                      $catOptions = $formField->options;
 500  
 501                      if ($catOptions && !empty($catOptions[0]->value)) {
 502                          $assignedCatids = (int) $catOptions[0]->value;
 503                      }
 504                  }
 505              }
 506  
 507              // Activate the reload of the form when category is changed
 508              $form->setFieldAttribute('catid', 'refresh-enabled', true);
 509              $form->setFieldAttribute('catid', 'refresh-cat-id', $assignedCatids);
 510              $form->setFieldAttribute('catid', 'refresh-section', 'article');
 511  
 512              // Store ID of the category uses for edit state permission check
 513              $record->catid = $assignedCatids;
 514          } else {
 515              // Get the category which the article is being added to
 516              if (!empty($data['catid'])) {
 517                  $catId = (int) $data['catid'];
 518              } else {
 519                  $catIds  = $form->getValue('catid');
 520  
 521                  $catId = is_array($catIds)
 522                      ? (int) reset($catIds)
 523                      : (int) $catIds;
 524  
 525                  if (!$catId) {
 526                      $catId = (int) $form->getFieldAttribute('catid', 'default', 0);
 527                  }
 528              }
 529  
 530              $record->catid = $catId;
 531          }
 532  
 533          // Modify the form based on Edit State access controls.
 534          if (!$this->canEditState($record)) {
 535              // Disable fields for display.
 536              $form->setFieldAttribute('featured', 'disabled', 'true');
 537              $form->setFieldAttribute('featured_up', 'disabled', 'true');
 538              $form->setFieldAttribute('featured_down', 'disabled', 'true');
 539              $form->setFieldAttribute('ordering', 'disabled', 'true');
 540              $form->setFieldAttribute('publish_up', 'disabled', 'true');
 541              $form->setFieldAttribute('publish_down', 'disabled', 'true');
 542              $form->setFieldAttribute('state', 'disabled', 'true');
 543  
 544              // Disable fields while saving.
 545              // The controller has already verified this is an article you can edit.
 546              $form->setFieldAttribute('featured', 'filter', 'unset');
 547              $form->setFieldAttribute('featured_up', 'filter', 'unset');
 548              $form->setFieldAttribute('featured_down', 'filter', 'unset');
 549              $form->setFieldAttribute('ordering', 'filter', 'unset');
 550              $form->setFieldAttribute('publish_up', 'filter', 'unset');
 551              $form->setFieldAttribute('publish_down', 'filter', 'unset');
 552              $form->setFieldAttribute('state', 'filter', 'unset');
 553          }
 554  
 555          // Don't allow to change the created_by user if not allowed to access com_users.
 556          if (!Factory::getUser()->authorise('core.manage', 'com_users')) {
 557              $form->setFieldAttribute('created_by', 'filter', 'unset');
 558          }
 559  
 560          return $form;
 561      }
 562  
 563      /**
 564       * Method to get the data that should be injected in the form.
 565       *
 566       * @return  mixed  The data for the form.
 567       *
 568       * @since   1.6
 569       */
 570      protected function loadFormData()
 571      {
 572          // Check the session for previously entered form data.
 573          $app = Factory::getApplication();
 574          $data = $app->getUserState('com_content.edit.article.data', array());
 575  
 576          if (empty($data)) {
 577              $data = $this->getItem();
 578  
 579              // Pre-select some filters (Status, Category, Language, Access) in edit form if those have been selected in Article Manager: Articles
 580              if ($this->getState('article.id') == 0) {
 581                  $filters = (array) $app->getUserState('com_content.articles.filter');
 582                  $data->set(
 583                      'state',
 584                      $app->input->getInt(
 585                          'state',
 586                          ((isset($filters['published']) && $filters['published'] !== '') ? $filters['published'] : null)
 587                      )
 588                  );
 589                  $data->set('catid', $app->input->getInt('catid', (!empty($filters['category_id']) ? $filters['category_id'] : null)));
 590  
 591                  if ($app->isClient('administrator')) {
 592                      $data->set('language', $app->input->getString('language', (!empty($filters['language']) ? $filters['language'] : null)));
 593                  }
 594  
 595                  $data->set(
 596                      'access',
 597                      $app->input->getInt('access', (!empty($filters['access']) ? $filters['access'] : $app->get('access')))
 598                  );
 599              }
 600          }
 601  
 602          // If there are params fieldsets in the form it will fail with a registry object
 603          if (isset($data->params) && $data->params instanceof Registry) {
 604              $data->params = $data->params->toArray();
 605          }
 606  
 607          $this->preprocessData('com_content.article', $data);
 608  
 609          return $data;
 610      }
 611  
 612      /**
 613       * Method to validate the form data.
 614       *
 615       * @param   Form    $form   The form to validate against.
 616       * @param   array   $data   The data to validate.
 617       * @param   string  $group  The name of the field group to validate.
 618       *
 619       * @return  array|boolean  Array of filtered data if valid, false otherwise.
 620       *
 621       * @see     \Joomla\CMS\Form\FormRule
 622       * @see     JFilterInput
 623       * @since   3.7.0
 624       */
 625      public function validate($form, $data, $group = null)
 626      {
 627          if (!Factory::getUser()->authorise('core.admin', 'com_content')) {
 628              if (isset($data['rules'])) {
 629                  unset($data['rules']);
 630              }
 631          }
 632  
 633          return parent::validate($form, $data, $group);
 634      }
 635  
 636      /**
 637       * Method to save the form data.
 638       *
 639       * @param   array  $data  The form data.
 640       *
 641       * @return  boolean  True on success.
 642       *
 643       * @since   1.6
 644       */
 645      public function save($data)
 646      {
 647          $app    = Factory::getApplication();
 648          $input  = $app->input;
 649          $filter = InputFilter::getInstance();
 650  
 651          if (isset($data['metadata']) && isset($data['metadata']['author'])) {
 652              $data['metadata']['author'] = $filter->clean($data['metadata']['author'], 'TRIM');
 653          }
 654  
 655          if (isset($data['created_by_alias'])) {
 656              $data['created_by_alias'] = $filter->clean($data['created_by_alias'], 'TRIM');
 657          }
 658  
 659          if (isset($data['images']) && is_array($data['images'])) {
 660              $registry = new Registry($data['images']);
 661  
 662              $data['images'] = (string) $registry;
 663          }
 664  
 665          $this->workflowBeforeSave();
 666  
 667          // Create new category, if needed.
 668          $createCategory = true;
 669  
 670          if (is_null($data['catid'])) {
 671              // When there is no catid passed don't try to create one
 672              $createCategory = false;
 673          }
 674  
 675          // If category ID is provided, check if it's valid.
 676          if (is_numeric($data['catid']) && $data['catid']) {
 677              $createCategory = !CategoriesHelper::validateCategoryId($data['catid'], 'com_content');
 678          }
 679  
 680          // Save New Category
 681          if ($createCategory && $this->canCreateCategory()) {
 682              $category = [
 683                  // Remove #new# prefix, if exists.
 684                  'title'     => strpos($data['catid'], '#new#') === 0 ? substr($data['catid'], 5) : $data['catid'],
 685                  'parent_id' => 1,
 686                  'extension' => 'com_content',
 687                  'language'  => $data['language'],
 688                  'published' => 1,
 689              ];
 690  
 691              /** @var \Joomla\Component\Categories\Administrator\Model\CategoryModel $categoryModel */
 692              $categoryModel = Factory::getApplication()->bootComponent('com_categories')
 693                  ->getMVCFactory()->createModel('Category', 'Administrator', ['ignore_request' => true]);
 694  
 695              // Create new category.
 696              if (!$categoryModel->save($category)) {
 697                  $this->setError($categoryModel->getError());
 698  
 699                  return false;
 700              }
 701  
 702              // Get the Category ID.
 703              $data['catid'] = $categoryModel->getState('category.id');
 704          }
 705  
 706          if (isset($data['urls']) && is_array($data['urls'])) {
 707              $check = $input->post->get('jform', array(), 'array');
 708  
 709              foreach ($data['urls'] as $i => $url) {
 710                  if ($url != false && ($i == 'urla' || $i == 'urlb' || $i == 'urlc')) {
 711                      if (preg_match('~^#[a-zA-Z]{1}[a-zA-Z0-9-_:.]*$~', $check['urls'][$i]) == 1) {
 712                          $data['urls'][$i] = $check['urls'][$i];
 713                      } else {
 714                          $data['urls'][$i] = PunycodeHelper::urlToPunycode($url);
 715                      }
 716                  }
 717              }
 718  
 719              unset($check);
 720  
 721              $registry = new Registry($data['urls']);
 722  
 723              $data['urls'] = (string) $registry;
 724          }
 725  
 726          // Alter the title for save as copy
 727          if ($input->get('task') == 'save2copy') {
 728              $origTable = $this->getTable();
 729  
 730              if ($app->isClient('site')) {
 731                  $origTable->load($input->getInt('a_id'));
 732  
 733                  if ($origTable->title === $data['title']) {
 734                      /**
 735                       * If title of article is not changed, set alias to original article alias so that Joomla! will generate
 736                       * new Title and Alias for the copied article
 737                       */
 738                      $data['alias'] = $origTable->alias;
 739                  } else {
 740                      $data['alias'] = '';
 741                  }
 742              } else {
 743                  $origTable->load($input->getInt('id'));
 744              }
 745  
 746              if ($data['title'] == $origTable->title) {
 747                  list($title, $alias) = $this->generateNewTitle($data['catid'], $data['alias'], $data['title']);
 748                  $data['title'] = $title;
 749                  $data['alias'] = $alias;
 750              } elseif ($data['alias'] == $origTable->alias) {
 751                  $data['alias'] = '';
 752              }
 753          }
 754  
 755          // Automatic handling of alias for empty fields
 756          if (in_array($input->get('task'), array('apply', 'save', 'save2new')) && (!isset($data['id']) || (int) $data['id'] == 0)) {
 757              if ($data['alias'] == null) {
 758                  if ($app->get('unicodeslugs') == 1) {
 759                      $data['alias'] = OutputFilter::stringUrlUnicodeSlug($data['title']);
 760                  } else {
 761                      $data['alias'] = OutputFilter::stringURLSafe($data['title']);
 762                  }
 763  
 764                  $table = $this->getTable();
 765  
 766                  if ($table->load(array('alias' => $data['alias'], 'catid' => $data['catid']))) {
 767                      $msg = Text::_('COM_CONTENT_SAVE_WARNING');
 768                  }
 769  
 770                  list($title, $alias) = $this->generateNewTitle($data['catid'], $data['alias'], $data['title']);
 771                  $data['alias'] = $alias;
 772  
 773                  if (isset($msg)) {
 774                      $app->enqueueMessage($msg, 'warning');
 775                  }
 776              }
 777          }
 778  
 779          if (parent::save($data)) {
 780              // Check if featured is set and if not managed by workflow
 781              if (isset($data['featured']) && !$this->bootComponent('com_content')->isFunctionalityUsed('core.featured', 'com_content.article')) {
 782                  if (
 783                      !$this->featured(
 784                          $this->getState($this->getName() . '.id'),
 785                          $data['featured'],
 786                          $data['featured_up'] ?? null,
 787                          $data['featured_down'] ?? null
 788                      )
 789                  ) {
 790                      return false;
 791                  }
 792              }
 793  
 794              $this->workflowAfterSave($data);
 795  
 796              return true;
 797          }
 798  
 799          return false;
 800      }
 801  
 802      /**
 803       * Method to toggle the featured setting of articles.
 804       *
 805       * @param   array        $pks           The ids of the items to toggle.
 806       * @param   integer      $value         The value to toggle to.
 807       * @param   string|Date  $featuredUp    The date which item featured up.
 808       * @param   string|Date  $featuredDown  The date which item featured down.
 809       *
 810       * @return  boolean  True on success.
 811       */
 812      public function featured($pks, $value = 0, $featuredUp = null, $featuredDown = null)
 813      {
 814          // Sanitize the ids.
 815          $pks     = (array) $pks;
 816          $pks     = ArrayHelper::toInteger($pks);
 817          $value   = (int) $value;
 818          $context = $this->option . '.' . $this->name;
 819  
 820          $this->workflowBeforeStageChange();
 821  
 822          // Include the plugins for the change of state event.
 823          PluginHelper::importPlugin($this->events_map['featured']);
 824  
 825          // Convert empty strings to null for the query.
 826          if ($featuredUp === '') {
 827              $featuredUp = null;
 828          }
 829  
 830          if ($featuredDown === '') {
 831              $featuredDown = null;
 832          }
 833  
 834          if (empty($pks)) {
 835              $this->setError(Text::_('COM_CONTENT_NO_ITEM_SELECTED'));
 836  
 837              return false;
 838          }
 839  
 840          $table = $this->getTable('Featured', 'Administrator');
 841  
 842          // Trigger the before change state event.
 843          $eventResult = Factory::getApplication()->getDispatcher()->dispatch(
 844              $this->event_before_change_featured,
 845              AbstractEvent::create(
 846                  $this->event_before_change_featured,
 847                  [
 848                      'eventClass' => 'Joomla\Component\Content\Administrator\Event\Model\FeatureEvent',
 849                      'subject'    => $this,
 850                      'extension'  => $context,
 851                      'pks'        => $pks,
 852                      'value'      => $value,
 853                  ]
 854              )
 855          );
 856  
 857          if ($eventResult->getArgument('abort', false)) {
 858              $this->setError(Text::_($eventResult->getArgument('abortReason')));
 859  
 860              return false;
 861          }
 862  
 863          try {
 864              $db = $this->getDatabase();
 865              $query = $db->getQuery(true)
 866                  ->update($db->quoteName('#__content'))
 867                  ->set($db->quoteName('featured') . ' = :featured')
 868                  ->whereIn($db->quoteName('id'), $pks)
 869                  ->bind(':featured', $value, ParameterType::INTEGER);
 870              $db->setQuery($query);
 871              $db->execute();
 872  
 873              if ($value === 0) {
 874                  // Adjust the mapping table.
 875                  // Clear the existing features settings.
 876                  $query = $db->getQuery(true)
 877                      ->delete($db->quoteName('#__content_frontpage'))
 878                      ->whereIn($db->quoteName('content_id'), $pks);
 879                  $db->setQuery($query);
 880                  $db->execute();
 881              } else {
 882                  // First, we find out which of our new featured articles are already featured.
 883                  $query = $db->getQuery(true)
 884                      ->select($db->quoteName('content_id'))
 885                      ->from($db->quoteName('#__content_frontpage'))
 886                      ->whereIn($db->quoteName('content_id'), $pks);
 887                  $db->setQuery($query);
 888  
 889                  $oldFeatured = $db->loadColumn();
 890  
 891                  // Update old featured articles
 892                  if (count($oldFeatured)) {
 893                      $query = $db->getQuery(true)
 894                          ->update($db->quoteName('#__content_frontpage'))
 895                          ->set(
 896                              [
 897                                  $db->quoteName('featured_up') . ' = :featuredUp',
 898                                  $db->quoteName('featured_down') . ' = :featuredDown',
 899                              ]
 900                          )
 901                          ->whereIn($db->quoteName('content_id'), $oldFeatured)
 902                          ->bind(':featuredUp', $featuredUp, $featuredUp ? ParameterType::STRING : ParameterType::NULL)
 903                          ->bind(':featuredDown', $featuredDown, $featuredDown ? ParameterType::STRING : ParameterType::NULL);
 904                      $db->setQuery($query);
 905                      $db->execute();
 906                  }
 907  
 908                  // We diff the arrays to get a list of the articles that are newly featured
 909                  $newFeatured = array_diff($pks, $oldFeatured);
 910  
 911                  // Featuring.
 912                  if ($newFeatured) {
 913                      $query = $db->getQuery(true)
 914                          ->insert($db->quoteName('#__content_frontpage'))
 915                          ->columns(
 916                              [
 917                                  $db->quoteName('content_id'),
 918                                  $db->quoteName('ordering'),
 919                                  $db->quoteName('featured_up'),
 920                                  $db->quoteName('featured_down'),
 921                              ]
 922                          );
 923  
 924                      $dataTypes = [
 925                          ParameterType::INTEGER,
 926                          ParameterType::INTEGER,
 927                          $featuredUp ? ParameterType::STRING : ParameterType::NULL,
 928                          $featuredDown ? ParameterType::STRING : ParameterType::NULL,
 929                      ];
 930  
 931                      foreach ($newFeatured as $pk) {
 932                          $query->values(implode(',', $query->bindArray([$pk, 0, $featuredUp, $featuredDown], $dataTypes)));
 933                      }
 934  
 935                      $db->setQuery($query);
 936                      $db->execute();
 937                  }
 938              }
 939          } catch (\Exception $e) {
 940              $this->setError($e->getMessage());
 941  
 942              return false;
 943          }
 944  
 945          $table->reorder();
 946  
 947          // Trigger the change state event.
 948          Factory::getApplication()->getDispatcher()->dispatch(
 949              $this->event_after_change_featured,
 950              AbstractEvent::create(
 951                  $this->event_after_change_featured,
 952                  [
 953                      'eventClass' => 'Joomla\Component\Content\Administrator\Event\Model\FeatureEvent',
 954                      'subject'    => $this,
 955                      'extension'  => $context,
 956                      'pks'        => $pks,
 957                      'value'      => $value,
 958                  ]
 959              )
 960          );
 961  
 962          $this->cleanCache();
 963  
 964          return true;
 965      }
 966  
 967      /**
 968       * A protected method to get a set of ordering conditions.
 969       *
 970       * @param   object  $table  A record object.
 971       *
 972       * @return  array  An array of conditions to add to ordering queries.
 973       *
 974       * @since   1.6
 975       */
 976      protected function getReorderConditions($table)
 977      {
 978          return [
 979              $this->getDatabase()->quoteName('catid') . ' = ' . (int) $table->catid,
 980          ];
 981      }
 982  
 983      /**
 984       * Allows preprocessing of the Form object.
 985       *
 986       * @param   Form    $form   The form object
 987       * @param   array   $data   The data to be merged into the form object
 988       * @param   string  $group  The plugin group to be executed
 989       *
 990       * @return  void
 991       *
 992       * @since   3.0
 993       */
 994      protected function preprocessForm(Form $form, $data, $group = 'content')
 995      {
 996          if ($this->canCreateCategory()) {
 997              $form->setFieldAttribute('catid', 'allowAdd', 'true');
 998  
 999              // Add a prefix for categories created on the fly.
1000              $form->setFieldAttribute('catid', 'customPrefix', '#new#');
1001          }
1002  
1003          // Association content items
1004          if (Associations::isEnabled()) {
1005              $languages = LanguageHelper::getContentLanguages(false, false, null, 'ordering', 'asc');
1006  
1007              if (count($languages) > 1) {
1008                  $addform = new \SimpleXMLElement('<form />');
1009                  $fields = $addform->addChild('fields');
1010                  $fields->addAttribute('name', 'associations');
1011                  $fieldset = $fields->addChild('fieldset');
1012                  $fieldset->addAttribute('name', 'item_associations');
1013  
1014                  foreach ($languages as $language) {
1015                      $field = $fieldset->addChild('field');
1016                      $field->addAttribute('name', $language->lang_code);
1017                      $field->addAttribute('type', 'modal_article');
1018                      $field->addAttribute('language', $language->lang_code);
1019                      $field->addAttribute('label', $language->title);
1020                      $field->addAttribute('translate_label', 'false');
1021                      $field->addAttribute('select', 'true');
1022                      $field->addAttribute('new', 'true');
1023                      $field->addAttribute('edit', 'true');
1024                      $field->addAttribute('clear', 'true');
1025                      $field->addAttribute('propagate', 'true');
1026                  }
1027  
1028                  $form->load($addform, false);
1029              }
1030          }
1031  
1032          $this->workflowPreprocessForm($form, $data);
1033  
1034          parent::preprocessForm($form, $data, $group);
1035      }
1036  
1037      /**
1038       * Custom clean the cache of com_content and content modules
1039       *
1040       * @param   string   $group     The cache group
1041       * @param   integer  $clientId  @deprecated   5.0   No longer used.
1042       *
1043       * @return  void
1044       *
1045       * @since   1.6
1046       */
1047      protected function cleanCache($group = null, $clientId = 0)
1048      {
1049          parent::cleanCache('com_content');
1050          parent::cleanCache('mod_articles_archive');
1051          parent::cleanCache('mod_articles_categories');
1052          parent::cleanCache('mod_articles_category');
1053          parent::cleanCache('mod_articles_latest');
1054          parent::cleanCache('mod_articles_news');
1055          parent::cleanCache('mod_articles_popular');
1056      }
1057  
1058      /**
1059       * Void hit function for pagebreak when editing content from frontend
1060       *
1061       * @return  void
1062       *
1063       * @since   3.6.0
1064       */
1065      public function hit()
1066      {
1067      }
1068  
1069      /**
1070       * Is the user allowed to create an on the fly category?
1071       *
1072       * @return  boolean
1073       *
1074       * @since   3.6.1
1075       */
1076      private function canCreateCategory()
1077      {
1078          return Factory::getUser()->authorise('core.create', 'com_content');
1079      }
1080  
1081      /**
1082       * Delete #__content_frontpage items if the deleted articles was featured
1083       *
1084       * @param   object  $pks  The primary key related to the contents that was deleted.
1085       *
1086       * @return  boolean
1087       *
1088       * @since   3.7.0
1089       */
1090      public function delete(&$pks)
1091      {
1092          $return = parent::delete($pks);
1093  
1094          if ($return) {
1095              // Now check to see if this articles was featured if so delete it from the #__content_frontpage table
1096              $db = $this->getDatabase();
1097              $query = $db->getQuery(true)
1098                  ->delete($db->quoteName('#__content_frontpage'))
1099                  ->whereIn($db->quoteName('content_id'), $pks);
1100              $db->setQuery($query);
1101              $db->execute();
1102  
1103              $this->workflow->deleteAssociation($pks);
1104          }
1105  
1106          return $return;
1107      }
1108  }


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