| [ Index ] |
PHP Cross Reference of Joomla 2.5.4 DE |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * @copyright Copyright (C) 2005 - 2012 Open Source Matters, Inc. All rights reserved. 4 * @license GNU General Public License version 2 or later; see LICENSE.txt 5 */ 6 7 // Check to ensure this file is included in Joomla! 8 defined('_JEXEC') or die; 9 10 jimport('joomla.application.component.modellist'); 11 12 /** 13 * This models supports retrieving lists of articles. 14 * 15 * @package Joomla.Site 16 * @subpackage com_content 17 * @since 1.6 18 */ 19 class ContentModelArticles extends JModelList 20 { 21 22 /** 23 * Constructor. 24 * 25 * @param array An optional associative array of configuration settings. 26 * @see JController 27 * @since 1.6 28 */ 29 public function __construct($config = array()) 30 { 31 if (empty($config['filter_fields'])) { 32 $config['filter_fields'] = array( 33 'id', 'a.id', 34 'title', 'a.title', 35 'alias', 'a.alias', 36 'checked_out', 'a.checked_out', 37 'checked_out_time', 'a.checked_out_time', 38 'catid', 'a.catid', 'category_title', 39 'state', 'a.state', 40 'access', 'a.access', 'access_level', 41 'created', 'a.created', 42 'created_by', 'a.created_by', 43 'ordering', 'a.ordering', 44 'featured', 'a.featured', 45 'language', 'a.language', 46 'hits', 'a.hits', 47 'publish_up', 'a.publish_up', 48 'publish_down', 'a.publish_down', 49 'images', 'a.images', 50 'urls', 'a.urls', 51 ); 52 } 53 54 parent::__construct($config); 55 } 56 57 /** 58 * Method to auto-populate the model state. 59 * 60 * Note. Calling getState in this method will result in recursion. 61 * 62 * @return void 63 * @since 1.6 64 */ 65 protected function populateState($ordering = 'ordering', $direction = 'ASC') 66 { 67 $app = JFactory::getApplication(); 68 69 // List state information 70 //$value = $app->getUserStateFromRequest('global.list.limit', 'limit', $app->getCfg('list_limit')); 71 $value = JRequest::getUInt('limit', $app->getCfg('list_limit', 0)); 72 $this->setState('list.limit', $value); 73 74 //$value = $app->getUserStateFromRequest($this->context.'.limitstart', 'limitstart', 0); 75 $value = JRequest::getUInt('limitstart', 0); 76 $this->setState('list.start', $value); 77 78 $orderCol = JRequest::getCmd('filter_order', 'a.ordering'); 79 if (!in_array($orderCol, $this->filter_fields)) { 80 $orderCol = 'a.ordering'; 81 } 82 $this->setState('list.ordering', $orderCol); 83 84 $listOrder = JRequest::getCmd('filter_order_Dir', 'ASC'); 85 if (!in_array(strtoupper($listOrder), array('ASC', 'DESC', ''))) { 86 $listOrder = 'ASC'; 87 } 88 $this->setState('list.direction', $listOrder); 89 90 $params = $app->getParams(); 91 $this->setState('params', $params); 92 $user = JFactory::getUser(); 93 94 if ((!$user->authorise('core.edit.state', 'com_content')) && (!$user->authorise('core.edit', 'com_content'))){ 95 // filter on published for those who do not have edit or edit.state rights. 96 $this->setState('filter.published', 1); 97 } 98 99 $this->setState('filter.language', $app->getLanguageFilter()); 100 101 // process show_noauth parameter 102 if (!$params->get('show_noauth')) { 103 $this->setState('filter.access', true); 104 } 105 else { 106 $this->setState('filter.access', false); 107 } 108 109 $this->setState('layout', JRequest::getCmd('layout')); 110 } 111 112 /** 113 * Method to get a store id based on model configuration state. 114 * 115 * This is necessary because the model is used by the component and 116 * different modules that might need different sets of data or different 117 * ordering requirements. 118 * 119 * @param string $id A prefix for the store id. 120 * 121 * @return string A store id. 122 * @since 1.6 123 */ 124 protected function getStoreId($id = '') 125 { 126 // Compile the store id. 127 $id .= ':'.$this->getState('filter.published'); 128 $id .= ':'.$this->getState('filter.access'); 129 $id .= ':'.$this->getState('filter.featured'); 130 $id .= ':'.$this->getState('filter.article_id'); 131 $id .= ':'.$this->getState('filter.article_id.include'); 132 $id .= ':'.$this->getState('filter.category_id'); 133 $id .= ':'.$this->getState('filter.category_id.include'); 134 $id .= ':'.$this->getState('filter.author_id'); 135 $id .= ':'.$this->getState('filter.author_id.include'); 136 $id .= ':'.$this->getState('filter.author_alias'); 137 $id .= ':'.$this->getState('filter.author_alias.include'); 138 $id .= ':'.$this->getState('filter.date_filtering'); 139 $id .= ':'.$this->getState('filter.date_field'); 140 $id .= ':'.$this->getState('filter.start_date_range'); 141 $id .= ':'.$this->getState('filter.end_date_range'); 142 $id .= ':'.$this->getState('filter.relative_date'); 143 144 return parent::getStoreId($id); 145 } 146 147 /** 148 * Get the master query for retrieving a list of articles subject to the model state. 149 * 150 * @return JDatabaseQuery 151 * @since 1.6 152 */ 153 function getListQuery() 154 { 155 // Create a new query object. 156 $db = $this->getDbo(); 157 $query = $db->getQuery(true); 158 159 // Select the required fields from the table. 160 $query->select( 161 $this->getState( 162 'list.select', 163 'a.id, a.title, a.alias, a.title_alias, a.introtext, ' . 164 'a.checked_out, a.checked_out_time, ' . 165 'a.catid, a.created, a.created_by, a.created_by_alias, ' . 166 // use created if modified is 0 167 'CASE WHEN a.modified = 0 THEN a.created ELSE a.modified END as modified, ' . 168 'a.modified_by, uam.name as modified_by_name,' . 169 // use created if publish_up is 0 170 'CASE WHEN a.publish_up = 0 THEN a.created ELSE a.publish_up END as publish_up,' . 171 'a.publish_down, a.images, a.urls, a.attribs, a.metadata, a.metakey, a.metadesc, a.access, ' . 172 'a.hits, a.xreference, a.featured,'.' '.$query->length('a.fulltext').' AS readmore' 173 ) 174 ); 175 176 // Process an Archived Article layout 177 if ($this->getState('filter.published') == 2) { 178 // If badcats is not null, this means that the article is inside an archived category 179 // In this case, the state is set to 2 to indicate Archived (even if the article state is Published) 180 $query->select($this->getState('list.select', 'CASE WHEN badcats.id is null THEN a.state ELSE 2 END AS state')); 181 } 182 else { 183 // Process non-archived layout 184 // If badcats is not null, this means that the article is inside an unpublished category 185 // In this case, the state is set to 0 to indicate Unpublished (even if the article state is Published) 186 $query->select($this->getState('list.select', 'CASE WHEN badcats.id is not null THEN 0 ELSE a.state END AS state')); 187 } 188 189 $query->from('#__content AS a'); 190 191 // Join over the frontpage articles. 192 if ($this->context != 'com_content.featured') { 193 $query->join('LEFT', '#__content_frontpage AS fp ON fp.content_id = a.id'); 194 } 195 196 // Join over the categories. 197 $query->select('c.title AS category_title, c.path AS category_route, c.access AS category_access, c.alias AS category_alias'); 198 $query->join('LEFT', '#__categories AS c ON c.id = a.catid'); 199 200 // Join over the users for the author and modified_by names. 201 $query->select("CASE WHEN a.created_by_alias > ' ' THEN a.created_by_alias ELSE ua.name END AS author"); 202 $query->select("ua.email AS author_email"); 203 204 $query->join('LEFT', '#__users AS ua ON ua.id = a.created_by'); 205 $query->join('LEFT', '#__users AS uam ON uam.id = a.modified_by'); 206 207 // Join on contact table 208 $subQuery = $db->getQuery(true); 209 $subQuery->select('contact.user_id, MAX(contact.id) AS id, contact.language'); 210 $subQuery->from('#__contact_details AS contact'); 211 $subQuery->where('contact.published = 1'); 212 $subQuery->group('contact.user_id, contact.language'); 213 $query->select('contact.id as contactid' ); 214 $query->join('LEFT', '(' . $subQuery . ') AS contact ON contact.user_id = a.created_by'); 215 216 // Join over the categories to get parent category titles 217 $query->select('parent.title as parent_title, parent.id as parent_id, parent.path as parent_route, parent.alias as parent_alias'); 218 $query->join('LEFT', '#__categories as parent ON parent.id = c.parent_id'); 219 220 // Join on voting table 221 $query->select('ROUND(v.rating_sum / v.rating_count, 0) AS rating, v.rating_count as rating_count'); 222 $query->join('LEFT', '#__content_rating AS v ON a.id = v.content_id'); 223 224 // Join to check for category published state in parent categories up the tree 225 $query->select('c.published, CASE WHEN badcats.id is null THEN c.published ELSE 0 END AS parents_published'); 226 $subquery = 'SELECT cat.id as id FROM #__categories AS cat JOIN #__categories AS parent '; 227 $subquery .= 'ON cat.lft BETWEEN parent.lft AND parent.rgt '; 228 $subquery .= 'WHERE parent.extension = ' . $db->quote('com_content'); 229 230 if ($this->getState('filter.published') == 2) { 231 // Find any up-path categories that are archived 232 // If any up-path categories are archived, include all children in archived layout 233 $subquery .= ' AND parent.published = 2 GROUP BY cat.id '; 234 // Set effective state to archived if up-path category is archived 235 $publishedWhere = 'CASE WHEN badcats.id is null THEN a.state ELSE 2 END'; 236 } 237 else { 238 // Find any up-path categories that are not published 239 // If all categories are published, badcats.id will be null, and we just use the article state 240 $subquery .= ' AND parent.published != 1 GROUP BY cat.id '; 241 // Select state to unpublished if up-path category is unpublished 242 $publishedWhere = 'CASE WHEN badcats.id is null THEN a.state ELSE 0 END'; 243 } 244 $query->join('LEFT OUTER', '(' . $subquery . ') AS badcats ON badcats.id = c.id'); 245 246 // Filter by access level. 247 if ($access = $this->getState('filter.access')) { 248 $user = JFactory::getUser(); 249 $groups = implode(',', $user->getAuthorisedViewLevels()); 250 $query->where('a.access IN ('.$groups.')'); 251 } 252 253 // Filter by published state 254 $published = $this->getState('filter.published'); 255 256 if (is_numeric($published)) { 257 // Use article state if badcats.id is null, otherwise, force 0 for unpublished 258 $query->where($publishedWhere . ' = ' . (int) $published); 259 } 260 elseif (is_array($published)) { 261 JArrayHelper::toInteger($published); 262 $published = implode(',', $published); 263 // Use article state if badcats.id is null, otherwise, force 0 for unpublished 264 $query->where($publishedWhere . ' IN ('.$published.')'); 265 } 266 267 // Filter by featured state 268 $featured = $this->getState('filter.featured'); 269 switch ($featured) 270 { 271 case 'hide': 272 $query->where('a.featured = 0'); 273 break; 274 275 case 'only': 276 $query->where('a.featured = 1'); 277 break; 278 279 case 'show': 280 default: 281 // Normally we do not discriminate 282 // between featured/unfeatured items. 283 break; 284 } 285 286 // Filter by a single or group of articles. 287 $articleId = $this->getState('filter.article_id'); 288 289 if (is_numeric($articleId)) { 290 $type = $this->getState('filter.article_id.include', true) ? '= ' : '<> '; 291 $query->where('a.id '.$type.(int) $articleId); 292 } 293 elseif (is_array($articleId)) { 294 JArrayHelper::toInteger($articleId); 295 $articleId = implode(',', $articleId); 296 $type = $this->getState('filter.article_id.include', true) ? 'IN' : 'NOT IN'; 297 $query->where('a.id '.$type.' ('.$articleId.')'); 298 } 299 300 // Filter by a single or group of categories 301 $categoryId = $this->getState('filter.category_id'); 302 303 if (is_numeric($categoryId)) { 304 $type = $this->getState('filter.category_id.include', true) ? '= ' : '<> '; 305 306 // Add subcategory check 307 $includeSubcategories = $this->getState('filter.subcategories', false); 308 $categoryEquals = 'a.catid '.$type.(int) $categoryId; 309 310 if ($includeSubcategories) { 311 $levels = (int) $this->getState('filter.max_category_levels', '1'); 312 // Create a subquery for the subcategory list 313 $subQuery = $db->getQuery(true); 314 $subQuery->select('sub.id'); 315 $subQuery->from('#__categories as sub'); 316 $subQuery->join('INNER', '#__categories as this ON sub.lft > this.lft AND sub.rgt < this.rgt'); 317 $subQuery->where('this.id = '.(int) $categoryId); 318 if ($levels >= 0) { 319 $subQuery->where('sub.level <= this.level + '.$levels); 320 } 321 322 // Add the subquery to the main query 323 $query->where('('.$categoryEquals.' OR a.catid IN ('.$subQuery->__toString().'))'); 324 } 325 else { 326 $query->where($categoryEquals); 327 } 328 } 329 elseif (is_array($categoryId) && (count($categoryId) > 0)) { 330 JArrayHelper::toInteger($categoryId); 331 $categoryId = implode(',', $categoryId); 332 if (!empty($categoryId)) { 333 $type = $this->getState('filter.category_id.include', true) ? 'IN' : 'NOT IN'; 334 $query->where('a.catid '.$type.' ('.$categoryId.')'); 335 } 336 } 337 338 // Filter by author 339 $authorId = $this->getState('filter.author_id'); 340 $authorWhere = ''; 341 342 if (is_numeric($authorId)) { 343 $type = $this->getState('filter.author_id.include', true) ? '= ' : '<> '; 344 $authorWhere = 'a.created_by '.$type.(int) $authorId; 345 } 346 elseif (is_array($authorId)) { 347 JArrayHelper::toInteger($authorId); 348 $authorId = implode(',', $authorId); 349 350 if ($authorId) { 351 $type = $this->getState('filter.author_id.include', true) ? 'IN' : 'NOT IN'; 352 $authorWhere = 'a.created_by '.$type.' ('.$authorId.')'; 353 } 354 } 355 356 // Filter by author alias 357 $authorAlias = $this->getState('filter.author_alias'); 358 $authorAliasWhere = ''; 359 360 if (is_string($authorAlias)) { 361 $type = $this->getState('filter.author_alias.include', true) ? '= ' : '<> '; 362 $authorAliasWhere = 'a.created_by_alias '.$type.$db->Quote($authorAlias); 363 } 364 elseif (is_array($authorAlias)) { 365 $first = current($authorAlias); 366 367 if (!empty($first)) { 368 JArrayHelper::toString($authorAlias); 369 370 foreach ($authorAlias as $key => $alias) 371 { 372 $authorAlias[$key] = $db->Quote($alias); 373 } 374 375 $authorAlias = implode(',', $authorAlias); 376 377 if ($authorAlias) { 378 $type = $this->getState('filter.author_alias.include', true) ? 'IN' : 'NOT IN'; 379 $authorAliasWhere = 'a.created_by_alias '.$type.' ('.$authorAlias . 380 ')'; 381 } 382 } 383 } 384 385 if (!empty($authorWhere) && !empty($authorAliasWhere)) { 386 $query->where('('.$authorWhere.' OR '.$authorAliasWhere.')'); 387 } 388 elseif (empty($authorWhere) && empty($authorAliasWhere)) { 389 // If both are empty we don't want to add to the query 390 } 391 else { 392 // One of these is empty, the other is not so we just add both 393 $query->where($authorWhere.$authorAliasWhere); 394 } 395 396 // Filter by start and end dates. 397 $nullDate = $db->Quote($db->getNullDate()); 398 $nowDate = $db->Quote(JFactory::getDate()->toSql()); 399 400 $query->where('(a.publish_up = '.$nullDate.' OR a.publish_up <= '.$nowDate.')'); 401 $query->where('(a.publish_down = '.$nullDate.' OR a.publish_down >= '.$nowDate.')'); 402 403 // Filter by Date Range or Relative Date 404 $dateFiltering = $this->getState('filter.date_filtering', 'off'); 405 $dateField = $this->getState('filter.date_field', 'a.created'); 406 407 switch ($dateFiltering) 408 { 409 case 'range': 410 $startDateRange = $db->Quote($this->getState('filter.start_date_range', $nullDate)); 411 $endDateRange = $db->Quote($this->getState('filter.end_date_range', $nullDate)); 412 $query->where('('.$dateField.' >= '.$startDateRange.' AND '.$dateField . 413 ' <= '.$endDateRange.')'); 414 break; 415 416 case 'relative': 417 $relativeDate = (int) $this->getState('filter.relative_date', 0); 418 $query->where($dateField.' >= DATE_SUB('.$nowDate.', INTERVAL ' . 419 $relativeDate.' DAY)'); 420 break; 421 422 case 'off': 423 default: 424 break; 425 } 426 427 // process the filter for list views with user-entered filters 428 $params = $this->getState('params'); 429 430 if ((is_object($params)) && ($params->get('filter_field') != 'hide') && ($filter = $this->getState('list.filter'))) { 431 // clean filter variable 432 $filter = JString::strtolower($filter); 433 $hitsFilter = intval($filter); 434 $filter = $db->Quote('%'.$db->escape($filter, true).'%', false); 435 436 switch ($params->get('filter_field')) 437 { 438 case 'author': 439 $query->where( 440 'LOWER( CASE WHEN a.created_by_alias > '.$db->quote(' '). 441 ' THEN a.created_by_alias ELSE ua.name END ) LIKE '.$filter.' ' 442 ); 443 break; 444 445 case 'hits': 446 $query->where('a.hits >= '.$hitsFilter.' '); 447 break; 448 449 case 'title': 450 default: // default to 'title' if parameter is not valid 451 $query->where('LOWER( a.title ) LIKE '.$filter); 452 break; 453 } 454 } 455 456 // Filter by language 457 if ($this->getState('filter.language')) { 458 $query->where('a.language in ('.$db->quote(JFactory::getLanguage()->getTag()).','.$db->quote('*').')'); 459 $query->where('(contact.language in ('.$db->quote(JFactory::getLanguage()->getTag()).','.$db->quote('*').') OR contact.language IS NULL)'); 460 } 461 462 // Add the list ordering clause. 463 $query->order($this->getState('list.ordering', 'a.ordering').' '.$this->getState('list.direction', 'ASC')); 464 $query->group('a.id, a.title, a.alias, a.title_alias, a.introtext, a.checked_out, a.checked_out_time, a.catid, a.created, a.created_by, a.created_by_alias, a.created, a.modified, a.modified_by, uam.name, a.publish_up, a.attribs, a.metadata, a.metakey, a.metadesc, a.access, a.hits, a.xreference, a.featured, a.fulltext, a.state, a.publish_down, badcats.id, c.title, c.path, c.access, c.alias, uam.id, ua.name, ua.email, contact.id, parent.title, parent.id, parent.path, parent.alias, v.rating_sum, v.rating_count, c.published, c.lft, a.ordering, parent.lft, fp.ordering, c.id, a.images, a.urls'); 465 return $query; 466 } 467 468 /** 469 * Method to get a list of articles. 470 * 471 * Overriden to inject convert the attribs field into a JParameter object. 472 * 473 * @return mixed An array of objects on success, false on failure. 474 * @since 1.6 475 */ 476 public function getItems() 477 { 478 $items = parent::getItems(); 479 $user = JFactory::getUser(); 480 $userId = $user->get('id'); 481 $guest = $user->get('guest'); 482 $groups = $user->getAuthorisedViewLevels(); 483 484 // Get the global params 485 $globalParams = JComponentHelper::getParams('com_content', true); 486 487 // Convert the parameter fields into objects. 488 foreach ($items as &$item) 489 { 490 $articleParams = new JRegistry; 491 $articleParams->loadString($item->attribs); 492 493 // Unpack readmore and layout params 494 $item->alternative_readmore = $articleParams->get('alternative_readmore'); 495 $item->layout = $articleParams->get('layout'); 496 497 $item->params = clone $this->getState('params'); 498 499 // For blogs, article params override menu item params only if menu param = 'use_article' 500 // Otherwise, menu item params control the layout 501 // If menu item is 'use_article' and there is no article param, use global 502 if ((JRequest::getString('layout') == 'blog') || (JRequest::getString('view') == 'featured') 503 || ($this->getState('params')->get('layout_type') == 'blog')) { 504 // create an array of just the params set to 'use_article' 505 $menuParamsArray = $this->getState('params')->toArray(); 506 $articleArray = array(); 507 508 foreach ($menuParamsArray as $key => $value) 509 { 510 if ($value === 'use_article') { 511 // if the article has a value, use it 512 if ($articleParams->get($key) != '') { 513 // get the value from the article 514 $articleArray[$key] = $articleParams->get($key); 515 } 516 else { 517 // otherwise, use the global value 518 $articleArray[$key] = $globalParams->get($key); 519 } 520 } 521 } 522 523 // merge the selected article params 524 if (count($articleArray) > 0) { 525 $articleParams = new JRegistry; 526 $articleParams->loadArray($articleArray); 527 $item->params->merge($articleParams); 528 } 529 } 530 else { 531 // For non-blog layouts, merge all of the article params 532 $item->params->merge($articleParams); 533 } 534 535 // get display date 536 switch ($item->params->get('list_show_date')) 537 { 538 case 'modified': 539 $item->displayDate = $item->modified; 540 break; 541 542 case 'published': 543 $item->displayDate = ($item->publish_up == 0) ? $item->created : $item->publish_up; 544 break; 545 546 default: 547 case 'created': 548 $item->displayDate = $item->created; 549 break; 550 } 551 552 // Compute the asset access permissions. 553 // Technically guest could edit an article, but lets not check that to improve performance a little. 554 if (!$guest) { 555 $asset = 'com_content.article.'.$item->id; 556 557 // Check general edit permission first. 558 if ($user->authorise('core.edit', $asset)) { 559 $item->params->set('access-edit', true); 560 } 561 // Now check if edit.own is available. 562 elseif (!empty($userId) && $user->authorise('core.edit.own', $asset)) { 563 // Check for a valid user and that they are the owner. 564 if ($userId == $item->created_by) { 565 $item->params->set('access-edit', true); 566 } 567 } 568 } 569 570 $access = $this->getState('filter.access'); 571 572 if ($access) { 573 // If the access filter has been set, we already have only the articles this user can view. 574 $item->params->set('access-view', true); 575 } 576 else { 577 // If no access filter is set, the layout takes some responsibility for display of limited information. 578 if ($item->catid == 0 || $item->category_access === null) { 579 $item->params->set('access-view', in_array($item->access, $groups)); 580 } 581 else { 582 $item->params->set('access-view', in_array($item->access, $groups) && in_array($item->category_access, $groups)); 583 } 584 } 585 } 586 587 return $items; 588 } 589 public function getStart() 590 { 591 return $this->getState('list.start'); 592 } 593 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Tue Apr 3 11:40:28 2012 | Cross-referenced by PHPXref 0.7.1 |