[ Index ] |
PHP Cross Reference of Joomla 4.2.2 documentation |
[Summary view] [Print] [Text view]
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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Sep 7 05:41:13 2022 | Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer |