[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

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

   1  <?php
   2  
   3  /**
   4   * @package     Joomla.Site
   5   * @subpackage  com_content
   6   *
   7   * @copyright   (C) 2009 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\Site\Model;
  12  
  13  use Joomla\CMS\Component\ComponentHelper;
  14  use Joomla\CMS\Factory;
  15  use Joomla\CMS\Helper\TagsHelper;
  16  use Joomla\CMS\Language\Associations;
  17  use Joomla\CMS\Language\Multilanguage;
  18  use Joomla\CMS\MVC\Model\ListModel;
  19  use Joomla\CMS\Plugin\PluginHelper;
  20  use Joomla\Component\Content\Administrator\Extension\ContentComponent;
  21  use Joomla\Component\Content\Site\Helper\AssociationHelper;
  22  use Joomla\Database\ParameterType;
  23  use Joomla\Registry\Registry;
  24  use Joomla\String\StringHelper;
  25  use Joomla\Utilities\ArrayHelper;
  26  
  27  // phpcs:disable PSR1.Files.SideEffects
  28  \defined('_JEXEC') or die;
  29  // phpcs:enable PSR1.Files.SideEffects
  30  
  31  /**
  32   * This models supports retrieving lists of articles.
  33   *
  34   * @since  1.6
  35   */
  36  class ArticlesModel extends ListModel
  37  {
  38      /**
  39       * Constructor.
  40       *
  41       * @param   array  $config  An optional associative array of configuration settings.
  42       *
  43       * @see     \JController
  44       * @since   1.6
  45       */
  46      public function __construct($config = array())
  47      {
  48          if (empty($config['filter_fields'])) {
  49              $config['filter_fields'] = array(
  50                  'id', 'a.id',
  51                  'title', 'a.title',
  52                  'alias', 'a.alias',
  53                  'checked_out', 'a.checked_out',
  54                  'checked_out_time', 'a.checked_out_time',
  55                  'catid', 'a.catid', 'category_title',
  56                  'state', 'a.state',
  57                  'access', 'a.access', 'access_level',
  58                  'created', 'a.created',
  59                  'created_by', 'a.created_by',
  60                  'ordering', 'a.ordering',
  61                  'featured', 'a.featured',
  62                  'language', 'a.language',
  63                  'hits', 'a.hits',
  64                  'publish_up', 'a.publish_up',
  65                  'publish_down', 'a.publish_down',
  66                  'images', 'a.images',
  67                  'urls', 'a.urls',
  68                  'filter_tag',
  69              );
  70          }
  71  
  72          parent::__construct($config);
  73      }
  74  
  75      /**
  76       * Method to auto-populate the model state.
  77       *
  78       * This method should only be called once per instantiation and is designed
  79       * to be called on the first call to the getState() method unless the model
  80       * configuration flag to ignore the request is set.
  81       *
  82       * Note. Calling getState in this method will result in recursion.
  83       *
  84       * @param   string  $ordering   An optional ordering field.
  85       * @param   string  $direction  An optional direction (asc|desc).
  86       *
  87       * @return  void
  88       *
  89       * @since   3.0.1
  90       */
  91      protected function populateState($ordering = 'ordering', $direction = 'ASC')
  92      {
  93          $app = Factory::getApplication();
  94  
  95          // List state information
  96          $value = $app->input->get('limit', $app->get('list_limit', 0), 'uint');
  97          $this->setState('list.limit', $value);
  98  
  99          $value = $app->input->get('limitstart', 0, 'uint');
 100          $this->setState('list.start', $value);
 101  
 102          $value = $app->input->get('filter_tag', 0, 'uint');
 103          $this->setState('filter.tag', $value);
 104  
 105          $orderCol = $app->input->get('filter_order', 'a.ordering');
 106  
 107          if (!in_array($orderCol, $this->filter_fields)) {
 108              $orderCol = 'a.ordering';
 109          }
 110  
 111          $this->setState('list.ordering', $orderCol);
 112  
 113          $listOrder = $app->input->get('filter_order_Dir', 'ASC');
 114  
 115          if (!in_array(strtoupper($listOrder), array('ASC', 'DESC', ''))) {
 116              $listOrder = 'ASC';
 117          }
 118  
 119          $this->setState('list.direction', $listOrder);
 120  
 121          $params = $app->getParams();
 122          $this->setState('params', $params);
 123  
 124          $user = Factory::getUser();
 125  
 126          if ((!$user->authorise('core.edit.state', 'com_content')) && (!$user->authorise('core.edit', 'com_content'))) {
 127              // Filter on published for those who do not have edit or edit.state rights.
 128              $this->setState('filter.published', ContentComponent::CONDITION_PUBLISHED);
 129          }
 130  
 131          $this->setState('filter.language', Multilanguage::isEnabled());
 132  
 133          // Process show_noauth parameter
 134          if ((!$params->get('show_noauth')) || (!ComponentHelper::getParams('com_content')->get('show_noauth'))) {
 135              $this->setState('filter.access', true);
 136          } else {
 137              $this->setState('filter.access', false);
 138          }
 139  
 140          $this->setState('layout', $app->input->getString('layout'));
 141      }
 142  
 143      /**
 144       * Method to get a store id based on model configuration state.
 145       *
 146       * This is necessary because the model is used by the component and
 147       * different modules that might need different sets of data or different
 148       * ordering requirements.
 149       *
 150       * @param   string  $id  A prefix for the store id.
 151       *
 152       * @return  string  A store id.
 153       *
 154       * @since   1.6
 155       */
 156      protected function getStoreId($id = '')
 157      {
 158          // Compile the store id.
 159          $id .= ':' . serialize($this->getState('filter.published'));
 160          $id .= ':' . $this->getState('filter.access');
 161          $id .= ':' . $this->getState('filter.featured');
 162          $id .= ':' . serialize($this->getState('filter.article_id'));
 163          $id .= ':' . $this->getState('filter.article_id.include');
 164          $id .= ':' . serialize($this->getState('filter.category_id'));
 165          $id .= ':' . $this->getState('filter.category_id.include');
 166          $id .= ':' . serialize($this->getState('filter.author_id'));
 167          $id .= ':' . $this->getState('filter.author_id.include');
 168          $id .= ':' . serialize($this->getState('filter.author_alias'));
 169          $id .= ':' . $this->getState('filter.author_alias.include');
 170          $id .= ':' . $this->getState('filter.date_filtering');
 171          $id .= ':' . $this->getState('filter.date_field');
 172          $id .= ':' . $this->getState('filter.start_date_range');
 173          $id .= ':' . $this->getState('filter.end_date_range');
 174          $id .= ':' . $this->getState('filter.relative_date');
 175          $id .= ':' . serialize($this->getState('filter.tag'));
 176  
 177          return parent::getStoreId($id);
 178      }
 179  
 180      /**
 181       * Get the master query for retrieving a list of articles subject to the model state.
 182       *
 183       * @return  \Joomla\Database\DatabaseQuery
 184       *
 185       * @since   1.6
 186       */
 187      protected function getListQuery()
 188      {
 189          $user = Factory::getUser();
 190  
 191          // Create a new query object.
 192          $db = $this->getDatabase();
 193  
 194          /** @var \Joomla\Database\DatabaseQuery $query */
 195          $query = $db->getQuery(true);
 196  
 197          $nowDate = Factory::getDate()->toSql();
 198  
 199          $conditionArchived    = ContentComponent::CONDITION_ARCHIVED;
 200          $conditionUnpublished = ContentComponent::CONDITION_UNPUBLISHED;
 201  
 202          // Select the required fields from the table.
 203          $query->select(
 204              $this->getState(
 205                  'list.select',
 206                  [
 207                      $db->quoteName('a.id'),
 208                      $db->quoteName('a.title'),
 209                      $db->quoteName('a.alias'),
 210                      $db->quoteName('a.introtext'),
 211                      $db->quoteName('a.fulltext'),
 212                      $db->quoteName('a.checked_out'),
 213                      $db->quoteName('a.checked_out_time'),
 214                      $db->quoteName('a.catid'),
 215                      $db->quoteName('a.created'),
 216                      $db->quoteName('a.created_by'),
 217                      $db->quoteName('a.created_by_alias'),
 218                      $db->quoteName('a.modified'),
 219                      $db->quoteName('a.modified_by'),
 220                      // Use created if publish_up is null
 221                      'CASE WHEN ' . $db->quoteName('a.publish_up') . ' IS NULL THEN ' . $db->quoteName('a.created')
 222                          . ' ELSE ' . $db->quoteName('a.publish_up') . ' END AS ' . $db->quoteName('publish_up'),
 223                      $db->quoteName('a.publish_down'),
 224                      $db->quoteName('a.images'),
 225                      $db->quoteName('a.urls'),
 226                      $db->quoteName('a.attribs'),
 227                      $db->quoteName('a.metadata'),
 228                      $db->quoteName('a.metakey'),
 229                      $db->quoteName('a.metadesc'),
 230                      $db->quoteName('a.access'),
 231                      $db->quoteName('a.hits'),
 232                      $db->quoteName('a.featured'),
 233                      $db->quoteName('a.language'),
 234                      $query->length($db->quoteName('a.fulltext')) . ' AS ' . $db->quoteName('readmore'),
 235                      $db->quoteName('a.ordering'),
 236                  ]
 237              )
 238          )
 239              ->select(
 240                  [
 241                      $db->quoteName('fp.featured_up'),
 242                      $db->quoteName('fp.featured_down'),
 243                      // Published/archived article in archived category is treated as archived article. If category is not published then force 0.
 244                      'CASE WHEN ' . $db->quoteName('c.published') . ' = 2 AND ' . $db->quoteName('a.state') . ' > 0 THEN ' . $conditionArchived
 245                          . ' WHEN ' . $db->quoteName('c.published') . ' != 1 THEN ' . $conditionUnpublished
 246                          . ' ELSE ' . $db->quoteName('a.state') . ' END AS ' . $db->quoteName('state'),
 247                      $db->quoteName('c.title', 'category_title'),
 248                      $db->quoteName('c.path', 'category_route'),
 249                      $db->quoteName('c.access', 'category_access'),
 250                      $db->quoteName('c.alias', 'category_alias'),
 251                      $db->quoteName('c.language', 'category_language'),
 252                      $db->quoteName('c.published'),
 253                      $db->quoteName('c.published', 'parents_published'),
 254                      $db->quoteName('c.lft'),
 255                      'CASE WHEN ' . $db->quoteName('a.created_by_alias') . ' > ' . $db->quote(' ') . ' THEN ' . $db->quoteName('a.created_by_alias')
 256                          . ' ELSE ' . $db->quoteName('ua.name') . ' END AS ' . $db->quoteName('author'),
 257                      $db->quoteName('ua.email', 'author_email'),
 258                      $db->quoteName('uam.name', 'modified_by_name'),
 259                      $db->quoteName('parent.title', 'parent_title'),
 260                      $db->quoteName('parent.id', 'parent_id'),
 261                      $db->quoteName('parent.path', 'parent_route'),
 262                      $db->quoteName('parent.alias', 'parent_alias'),
 263                      $db->quoteName('parent.language', 'parent_language'),
 264                  ]
 265              )
 266              ->from($db->quoteName('#__content', 'a'))
 267              ->join('LEFT', $db->quoteName('#__categories', 'c'), $db->quoteName('c.id') . ' = ' . $db->quoteName('a.catid'))
 268              ->join('LEFT', $db->quoteName('#__users', 'ua'), $db->quoteName('ua.id') . ' = ' . $db->quoteName('a.created_by'))
 269              ->join('LEFT', $db->quoteName('#__users', 'uam'), $db->quoteName('uam.id') . ' = ' . $db->quoteName('a.modified_by'))
 270              ->join('LEFT', $db->quoteName('#__categories', 'parent'), $db->quoteName('parent.id') . ' = ' . $db->quoteName('c.parent_id'));
 271  
 272          $params      = $this->getState('params');
 273          $orderby_sec = $params->get('orderby_sec');
 274  
 275          // Join over the frontpage articles if required.
 276          $frontpageJoin = 'LEFT';
 277  
 278          if ($this->getState('filter.frontpage')) {
 279              if ($orderby_sec === 'front') {
 280                  $query->select($db->quoteName('fp.ordering'));
 281                  $frontpageJoin = 'INNER';
 282              } else {
 283                  $query->where($db->quoteName('a.featured') . ' = 1');
 284              }
 285  
 286              $query->where(
 287                  [
 288                      '(' . $db->quoteName('fp.featured_up') . ' IS NULL OR ' . $db->quoteName('fp.featured_up') . ' <= :frontpageUp)',
 289                      '(' . $db->quoteName('fp.featured_down') . ' IS NULL OR ' . $db->quoteName('fp.featured_down') . ' >= :frontpageDown)',
 290                  ]
 291              )
 292                  ->bind(':frontpageUp', $nowDate)
 293                  ->bind(':frontpageDown', $nowDate);
 294          } elseif ($orderby_sec === 'front' || $this->getState('list.ordering') === 'fp.ordering') {
 295              $query->select($db->quoteName('fp.ordering'));
 296          }
 297  
 298          $query->join($frontpageJoin, $db->quoteName('#__content_frontpage', 'fp'), $db->quoteName('fp.content_id') . ' = ' . $db->quoteName('a.id'));
 299  
 300          if (PluginHelper::isEnabled('content', 'vote')) {
 301              // Join on voting table
 302              $query->select(
 303                  [
 304                      'COALESCE(NULLIF(ROUND(' . $db->quoteName('v.rating_sum') . ' / ' . $db->quoteName('v.rating_count') . ', 1), 0), 0)'
 305                          . ' AS ' . $db->quoteName('rating'),
 306                      'COALESCE(NULLIF(' . $db->quoteName('v.rating_count') . ', 0), 0) AS ' . $db->quoteName('rating_count'),
 307                  ]
 308              )
 309                  ->join('LEFT', $db->quoteName('#__content_rating', 'v'), $db->quoteName('a.id') . ' = ' . $db->quoteName('v.content_id'));
 310          }
 311  
 312          // Filter by access level.
 313          if ($this->getState('filter.access', true)) {
 314              $groups = $this->getState('filter.viewlevels', $user->getAuthorisedViewLevels());
 315              $query->whereIn($db->quoteName('a.access'), $groups)
 316                  ->whereIn($db->quoteName('c.access'), $groups);
 317          }
 318  
 319          // Filter by published state
 320          $condition = $this->getState('filter.published');
 321  
 322          if (is_numeric($condition) && $condition == 2) {
 323              /**
 324               * If category is archived then article has to be published or archived.
 325               * Or category is published then article has to be archived.
 326               */
 327              $query->where('((' . $db->quoteName('c.published') . ' = 2 AND ' . $db->quoteName('a.state') . ' > :conditionUnpublished)'
 328                  . ' OR (' . $db->quoteName('c.published') . ' = 1 AND ' . $db->quoteName('a.state') . ' = :conditionArchived))')
 329                  ->bind(':conditionUnpublished', $conditionUnpublished, ParameterType::INTEGER)
 330                  ->bind(':conditionArchived', $conditionArchived, ParameterType::INTEGER);
 331          } elseif (is_numeric($condition)) {
 332              $condition = (int) $condition;
 333  
 334              // Category has to be published
 335              $query->where($db->quoteName('c.published') . ' = 1 AND ' . $db->quoteName('a.state') . ' = :condition')
 336                  ->bind(':condition', $condition, ParameterType::INTEGER);
 337          } elseif (is_array($condition)) {
 338              // Category has to be published
 339              $query->where(
 340                  $db->quoteName('c.published') . ' = 1 AND ' . $db->quoteName('a.state')
 341                      . ' IN (' . implode(',', $query->bindArray($condition)) . ')'
 342              );
 343          }
 344  
 345          // Filter by featured state
 346          $featured = $this->getState('filter.featured');
 347  
 348          switch ($featured) {
 349              case 'hide':
 350                  $query->where($db->quoteName('a.featured') . ' = 0');
 351                  break;
 352  
 353              case 'only':
 354                  $query->where(
 355                      [
 356                          $db->quoteName('a.featured') . ' = 1',
 357                          '(' . $db->quoteName('fp.featured_up') . ' IS NULL OR ' . $db->quoteName('fp.featured_up') . ' <= :featuredUp)',
 358                          '(' . $db->quoteName('fp.featured_down') . ' IS NULL OR ' . $db->quoteName('fp.featured_down') . ' >= :featuredDown)',
 359                      ]
 360                  )
 361                      ->bind(':featuredUp', $nowDate)
 362                      ->bind(':featuredDown', $nowDate);
 363                  break;
 364  
 365              case 'show':
 366              default:
 367                  // Normally we do not discriminate between featured/unfeatured items.
 368                  break;
 369          }
 370  
 371          // Filter by a single or group of articles.
 372          $articleId = $this->getState('filter.article_id');
 373  
 374          if (is_numeric($articleId)) {
 375              $articleId = (int) $articleId;
 376              $type      = $this->getState('filter.article_id.include', true) ? ' = ' : ' <> ';
 377              $query->where($db->quoteName('a.id') . $type . ':articleId')
 378                  ->bind(':articleId', $articleId, ParameterType::INTEGER);
 379          } elseif (is_array($articleId)) {
 380              $articleId = ArrayHelper::toInteger($articleId);
 381  
 382              if ($this->getState('filter.article_id.include', true)) {
 383                  $query->whereIn($db->quoteName('a.id'), $articleId);
 384              } else {
 385                  $query->whereNotIn($db->quoteName('a.id'), $articleId);
 386              }
 387          }
 388  
 389          // Filter by a single or group of categories
 390          $categoryId = $this->getState('filter.category_id');
 391  
 392          if (is_numeric($categoryId)) {
 393              $type = $this->getState('filter.category_id.include', true) ? ' = ' : ' <> ';
 394  
 395              // Add subcategory check
 396              $includeSubcategories = $this->getState('filter.subcategories', false);
 397  
 398              if ($includeSubcategories) {
 399                  $categoryId = (int) $categoryId;
 400                  $levels     = (int) $this->getState('filter.max_category_levels', 1);
 401  
 402                  // Create a subquery for the subcategory list
 403                  $subQuery = $db->getQuery(true)
 404                      ->select($db->quoteName('sub.id'))
 405                      ->from($db->quoteName('#__categories', 'sub'))
 406                      ->join(
 407                          'INNER',
 408                          $db->quoteName('#__categories', 'this'),
 409                          $db->quoteName('sub.lft') . ' > ' . $db->quoteName('this.lft')
 410                              . ' AND ' . $db->quoteName('sub.rgt') . ' < ' . $db->quoteName('this.rgt')
 411                      )
 412                      ->where($db->quoteName('this.id') . ' = :subCategoryId');
 413  
 414                  $query->bind(':subCategoryId', $categoryId, ParameterType::INTEGER);
 415  
 416                  if ($levels >= 0) {
 417                      $subQuery->where($db->quoteName('sub.level') . ' <= ' . $db->quoteName('this.level') . ' + :levels');
 418                      $query->bind(':levels', $levels, ParameterType::INTEGER);
 419                  }
 420  
 421                  // Add the subquery to the main query
 422                  $query->where(
 423                      '(' . $db->quoteName('a.catid') . $type . ':categoryId OR ' . $db->quoteName('a.catid') . ' IN (' . $subQuery . '))'
 424                  );
 425                  $query->bind(':categoryId', $categoryId, ParameterType::INTEGER);
 426              } else {
 427                  $query->where($db->quoteName('a.catid') . $type . ':categoryId');
 428                  $query->bind(':categoryId', $categoryId, ParameterType::INTEGER);
 429              }
 430          } elseif (is_array($categoryId) && (count($categoryId) > 0)) {
 431              $categoryId = ArrayHelper::toInteger($categoryId);
 432  
 433              if (!empty($categoryId)) {
 434                  if ($this->getState('filter.category_id.include', true)) {
 435                      $query->whereIn($db->quoteName('a.catid'), $categoryId);
 436                  } else {
 437                      $query->whereNotIn($db->quoteName('a.catid'), $categoryId);
 438                  }
 439              }
 440          }
 441  
 442          // Filter by author
 443          $authorId    = $this->getState('filter.author_id');
 444          $authorWhere = '';
 445  
 446          if (is_numeric($authorId)) {
 447              $authorId    = (int) $authorId;
 448              $type        = $this->getState('filter.author_id.include', true) ? ' = ' : ' <> ';
 449              $authorWhere = $db->quoteName('a.created_by') . $type . ':authorId';
 450              $query->bind(':authorId', $authorId, ParameterType::INTEGER);
 451          } elseif (is_array($authorId)) {
 452              $authorId = array_values(array_filter($authorId, 'is_numeric'));
 453  
 454              if ($authorId) {
 455                  $type        = $this->getState('filter.author_id.include', true) ? ' IN' : ' NOT IN';
 456                  $authorWhere = $db->quoteName('a.created_by') . $type . ' (' . implode(',', $query->bindArray($authorId)) . ')';
 457              }
 458          }
 459  
 460          // Filter by author alias
 461          $authorAlias      = $this->getState('filter.author_alias');
 462          $authorAliasWhere = '';
 463  
 464          if (is_string($authorAlias)) {
 465              $type             = $this->getState('filter.author_alias.include', true) ? ' = ' : ' <> ';
 466              $authorAliasWhere = $db->quoteName('a.created_by_alias') . $type . ':authorAlias';
 467              $query->bind(':authorAlias', $authorAlias);
 468          } elseif (\is_array($authorAlias) && !empty($authorAlias)) {
 469              $type             = $this->getState('filter.author_alias.include', true) ? ' IN' : ' NOT IN';
 470              $authorAliasWhere = $db->quoteName('a.created_by_alias') . $type
 471                  . ' (' . implode(',', $query->bindArray($authorAlias, ParameterType::STRING)) . ')';
 472          }
 473  
 474          if (!empty($authorWhere) && !empty($authorAliasWhere)) {
 475              $query->where('(' . $authorWhere . ' OR ' . $authorAliasWhere . ')');
 476          } elseif (!empty($authorWhere) || !empty($authorAliasWhere)) {
 477              // One of these is empty, the other is not so we just add both
 478              $query->where($authorWhere . $authorAliasWhere);
 479          }
 480  
 481          // Filter by start and end dates.
 482          if ((!$user->authorise('core.edit.state', 'com_content')) && (!$user->authorise('core.edit', 'com_content'))) {
 483              $query->where(
 484                  [
 485                      '(' . $db->quoteName('a.publish_up') . ' IS NULL OR ' . $db->quoteName('a.publish_up') . ' <= :publishUp)',
 486                      '(' . $db->quoteName('a.publish_down') . ' IS NULL OR ' . $db->quoteName('a.publish_down') . ' >= :publishDown)',
 487                  ]
 488              )
 489                  ->bind(':publishUp', $nowDate)
 490                  ->bind(':publishDown', $nowDate);
 491          }
 492  
 493          // Filter by Date Range or Relative Date
 494          $dateFiltering = $this->getState('filter.date_filtering', 'off');
 495          $dateField     = $db->escape($this->getState('filter.date_field', 'a.created'));
 496  
 497          switch ($dateFiltering) {
 498              case 'range':
 499                  $startDateRange = $this->getState('filter.start_date_range', '');
 500                  $endDateRange   = $this->getState('filter.end_date_range', '');
 501  
 502                  if ($startDateRange || $endDateRange) {
 503                      $query->where($db->quoteName($dateField) . ' IS NOT NULL');
 504  
 505                      if ($startDateRange) {
 506                          $query->where($db->quoteName($dateField) . ' >= :startDateRange')
 507                              ->bind(':startDateRange', $startDateRange);
 508                      }
 509  
 510                      if ($endDateRange) {
 511                          $query->where($db->quoteName($dateField) . ' <= :endDateRange')
 512                              ->bind(':endDateRange', $endDateRange);
 513                      }
 514                  }
 515  
 516                  break;
 517  
 518              case 'relative':
 519                  $relativeDate = (int) $this->getState('filter.relative_date', 0);
 520                  $query->where(
 521                      $db->quoteName($dateField) . ' IS NOT NULL AND '
 522                      . $db->quoteName($dateField) . ' >= ' . $query->dateAdd($db->quote($nowDate), -1 * $relativeDate, 'DAY')
 523                  );
 524                  break;
 525  
 526              case 'off':
 527              default:
 528                  break;
 529          }
 530  
 531          // Process the filter for list views with user-entered filters
 532          if (is_object($params) && ($params->get('filter_field') !== 'hide') && ($filter = $this->getState('list.filter'))) {
 533              // Clean filter variable
 534              $filter      = StringHelper::strtolower($filter);
 535              $monthFilter = $filter;
 536              $hitsFilter  = (int) $filter;
 537              $textFilter  = '%' . $filter . '%';
 538  
 539              switch ($params->get('filter_field')) {
 540                  case 'author':
 541                      $query->where(
 542                          'LOWER(CASE WHEN ' . $db->quoteName('a.created_by_alias') . ' > ' . $db->quote(' ')
 543                          . ' THEN ' . $db->quoteName('a.created_by_alias') . ' ELSE ' . $db->quoteName('ua.name') . ' END) LIKE :search'
 544                      )
 545                          ->bind(':search', $textFilter);
 546                      break;
 547  
 548                  case 'hits':
 549                      $query->where($db->quoteName('a.hits') . ' >= :hits')
 550                          ->bind(':hits', $hitsFilter, ParameterType::INTEGER);
 551                      break;
 552  
 553                  case 'month':
 554                      if ($monthFilter != '') {
 555                          $monthStart = date("Y-m-d", strtotime($monthFilter)) . ' 00:00:00';
 556                          $monthEnd   = date("Y-m-t", strtotime($monthFilter)) . ' 23:59:59';
 557  
 558                          $query->where(
 559                              [
 560                                  ':monthStart <= CASE WHEN a.publish_up IS NULL THEN a.created ELSE a.publish_up END',
 561                                  ':monthEnd >= CASE WHEN a.publish_up IS NULL THEN a.created ELSE a.publish_up END',
 562                              ]
 563                          )
 564                              ->bind(':monthStart', $monthStart)
 565                              ->bind(':monthEnd', $monthEnd);
 566                      }
 567                      break;
 568  
 569                  case 'title':
 570                  default:
 571                      // Default to 'title' if parameter is not valid
 572                      $query->where('LOWER(' . $db->quoteName('a.title') . ') LIKE :search')
 573                          ->bind(':search', $textFilter);
 574                      break;
 575              }
 576          }
 577  
 578          // Filter by language
 579          if ($this->getState('filter.language')) {
 580              $query->whereIn($db->quoteName('a.language'), [Factory::getApplication()->getLanguage()->getTag(), '*'], ParameterType::STRING);
 581          }
 582  
 583          // Filter by a single or group of tags.
 584          $tagId = $this->getState('filter.tag');
 585  
 586          if (is_array($tagId) && count($tagId) === 1) {
 587              $tagId = current($tagId);
 588          }
 589  
 590          if (is_array($tagId)) {
 591              $tagId = ArrayHelper::toInteger($tagId);
 592  
 593              if ($tagId) {
 594                  $subQuery = $db->getQuery(true)
 595                      ->select('DISTINCT ' . $db->quoteName('content_item_id'))
 596                      ->from($db->quoteName('#__contentitem_tag_map'))
 597                      ->where(
 598                          [
 599                              $db->quoteName('tag_id') . ' IN (' . implode(',', $query->bindArray($tagId)) . ')',
 600                              $db->quoteName('type_alias') . ' = ' . $db->quote('com_content.article'),
 601                          ]
 602                      );
 603  
 604                  $query->join(
 605                      'INNER',
 606                      '(' . $subQuery . ') AS ' . $db->quoteName('tagmap'),
 607                      $db->quoteName('tagmap.content_item_id') . ' = ' . $db->quoteName('a.id')
 608                  );
 609              }
 610          } elseif ($tagId = (int) $tagId) {
 611              $query->join(
 612                  'INNER',
 613                  $db->quoteName('#__contentitem_tag_map', 'tagmap'),
 614                  $db->quoteName('tagmap.content_item_id') . ' = ' . $db->quoteName('a.id')
 615                      . ' AND ' . $db->quoteName('tagmap.type_alias') . ' = ' . $db->quote('com_content.article')
 616              )
 617                  ->where($db->quoteName('tagmap.tag_id') . ' = :tagId')
 618                  ->bind(':tagId', $tagId, ParameterType::INTEGER);
 619          }
 620  
 621          // Add the list ordering clause.
 622          $query->order(
 623              $db->escape($this->getState('list.ordering', 'a.ordering')) . ' ' . $db->escape($this->getState('list.direction', 'ASC'))
 624          );
 625  
 626          return $query;
 627      }
 628  
 629      /**
 630       * Method to get a list of articles.
 631       *
 632       * Overridden to inject convert the attribs field into a Registry object.
 633       *
 634       * @return  mixed  An array of objects on success, false on failure.
 635       *
 636       * @since   1.6
 637       */
 638      public function getItems()
 639      {
 640          $items  = parent::getItems();
 641  
 642          $user = Factory::getUser();
 643          $userId = $user->get('id');
 644          $guest = $user->get('guest');
 645          $groups = $user->getAuthorisedViewLevels();
 646          $input = Factory::getApplication()->input;
 647  
 648          // Get the global params
 649          $globalParams = ComponentHelper::getParams('com_content', true);
 650  
 651          $taggedItems = [];
 652  
 653          // Convert the parameter fields into objects.
 654          foreach ($items as $item) {
 655              $articleParams = new Registry($item->attribs);
 656  
 657              // Unpack readmore and layout params
 658              $item->alternative_readmore = $articleParams->get('alternative_readmore');
 659              $item->layout               = $articleParams->get('layout');
 660  
 661              $item->params = clone $this->getState('params');
 662  
 663              /**
 664               * For blogs, article params override menu item params only if menu param = 'use_article'
 665               * Otherwise, menu item params control the layout
 666               * If menu item is 'use_article' and there is no article param, use global
 667               */
 668              if (
 669                  ($input->getString('layout') === 'blog') || ($input->getString('view') === 'featured')
 670                  || ($this->getState('params')->get('layout_type') === 'blog')
 671              ) {
 672                  // Create an array of just the params set to 'use_article'
 673                  $menuParamsArray = $this->getState('params')->toArray();
 674                  $articleArray    = array();
 675  
 676                  foreach ($menuParamsArray as $key => $value) {
 677                      if ($value === 'use_article') {
 678                          // If the article has a value, use it
 679                          if ($articleParams->get($key) != '') {
 680                              // Get the value from the article
 681                              $articleArray[$key] = $articleParams->get($key);
 682                          } else {
 683                              // Otherwise, use the global value
 684                              $articleArray[$key] = $globalParams->get($key);
 685                          }
 686                      }
 687                  }
 688  
 689                  // Merge the selected article params
 690                  if (count($articleArray) > 0) {
 691                      $articleParams = new Registry($articleArray);
 692                      $item->params->merge($articleParams);
 693                  }
 694              } else {
 695                  // For non-blog layouts, merge all of the article params
 696                  $item->params->merge($articleParams);
 697              }
 698  
 699              // Get display date
 700              switch ($item->params->get('list_show_date')) {
 701                  case 'modified':
 702                      $item->displayDate = $item->modified;
 703                      break;
 704  
 705                  case 'published':
 706                      $item->displayDate = ($item->publish_up == 0) ? $item->created : $item->publish_up;
 707                      break;
 708  
 709                  default:
 710                  case 'created':
 711                      $item->displayDate = $item->created;
 712                      break;
 713              }
 714  
 715              /**
 716               * Compute the asset access permissions.
 717               * Technically guest could edit an article, but lets not check that to improve performance a little.
 718               */
 719              if (!$guest) {
 720                  $asset = 'com_content.article.' . $item->id;
 721  
 722                  // Check general edit permission first.
 723                  if ($user->authorise('core.edit', $asset)) {
 724                      $item->params->set('access-edit', true);
 725                  } elseif (!empty($userId) && $user->authorise('core.edit.own', $asset)) {
 726                      // Now check if edit.own is available.
 727                      // Check for a valid user and that they are the owner.
 728                      if ($userId == $item->created_by) {
 729                          $item->params->set('access-edit', true);
 730                      }
 731                  }
 732              }
 733  
 734              $access = $this->getState('filter.access');
 735  
 736              if ($access) {
 737                  // If the access filter has been set, we already have only the articles this user can view.
 738                  $item->params->set('access-view', true);
 739              } else {
 740                  // If no access filter is set, the layout takes some responsibility for display of limited information.
 741                  if ($item->catid == 0 || $item->category_access === null) {
 742                      $item->params->set('access-view', in_array($item->access, $groups));
 743                  } else {
 744                      $item->params->set('access-view', in_array($item->access, $groups) && in_array($item->category_access, $groups));
 745                  }
 746              }
 747  
 748              // Some contexts may not use tags data at all, so we allow callers to disable loading tag data
 749              if ($this->getState('load_tags', $item->params->get('show_tags', '1'))) {
 750                  $item->tags = new TagsHelper();
 751                  $taggedItems[$item->id] = $item;
 752              }
 753  
 754              if (Associations::isEnabled() && $item->params->get('show_associations')) {
 755                  $item->associations = AssociationHelper::displayAssociations($item->id);
 756              }
 757          }
 758  
 759          // Load tags of all items.
 760          if ($taggedItems) {
 761              $tagsHelper = new TagsHelper();
 762              $itemIds = \array_keys($taggedItems);
 763  
 764              foreach ($tagsHelper->getMultipleItemTags('com_content.article', $itemIds) as $id => $tags) {
 765                  $taggedItems[$id]->tags->itemTags = $tags;
 766              }
 767          }
 768  
 769          return $items;
 770      }
 771  
 772      /**
 773       * Method to get the starting number of items for the data set.
 774       *
 775       * @return  integer  The starting number of items available in the data set.
 776       *
 777       * @since   3.0.1
 778       */
 779      public function getStart()
 780      {
 781          return $this->getState('list.start');
 782      }
 783  
 784      /**
 785       * Count Items by Month
 786       *
 787       * @return  mixed  An array of objects on success, false on failure.
 788       *
 789       * @since   3.9.0
 790       */
 791      public function countItemsByMonth()
 792      {
 793          // Create a new query object.
 794          $db    = $this->getDatabase();
 795          $query = $db->getQuery(true);
 796  
 797          // Get the list query.
 798          $listQuery = $this->getListQuery();
 799          $bounded   = $listQuery->getBounded();
 800  
 801          // Bind list query variables to our new query.
 802          $keys      = array_keys($bounded);
 803          $values    = array_column($bounded, 'value');
 804          $dataTypes = array_column($bounded, 'dataType');
 805  
 806          $query->bind($keys, $values, $dataTypes);
 807  
 808          $query
 809              ->select(
 810                  'DATE(' .
 811                  $query->concatenate(
 812                      array(
 813                          $query->year($db->quoteName('publish_up')),
 814                          $db->quote('-'),
 815                          $query->month($db->quoteName('publish_up')),
 816                          $db->quote('-01')
 817                      )
 818                  ) . ') AS ' . $db->quoteName('d')
 819              )
 820              ->select('COUNT(*) AS ' . $db->quoteName('c'))
 821              ->from('(' . $this->getListQuery() . ') AS ' . $db->quoteName('b'))
 822              ->group($db->quoteName('d'))
 823              ->order($db->quoteName('d') . ' DESC');
 824  
 825          return $db->setQuery($query)->loadObjectList();
 826      }
 827  }


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