1<?php 2/** 3 * @package Joomla.Plugin 4 * @subpackage Finder.Content 5 * 6 * @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All rights reserved. 7 * @license GNU General Public License version 2 or later; see LICENSE.txt 8 */ 9 10defined('_JEXEC') or die; 11 12use Joomla\Registry\Registry; 13 14JLoader::register('FinderIndexerAdapter', JPATH_ADMINISTRATOR . '/components/com_finder/helpers/indexer/adapter.php'); 15 16/** 17 * Smart Search adapter for com_content. 18 * 19 * @since 2.5 20 */ 21class PlgFinderContent extends FinderIndexerAdapter 22{ 23 /** 24 * The plugin identifier. 25 * 26 * @var string 27 * @since 2.5 28 */ 29 protected $context = 'Content'; 30 31 /** 32 * The extension name. 33 * 34 * @var string 35 * @since 2.5 36 */ 37 protected $extension = 'com_content'; 38 39 /** 40 * The sublayout to use when rendering the results. 41 * 42 * @var string 43 * @since 2.5 44 */ 45 protected $layout = 'article'; 46 47 /** 48 * The type of content that the adapter indexes. 49 * 50 * @var string 51 * @since 2.5 52 */ 53 protected $type_title = 'Article'; 54 55 /** 56 * The table name. 57 * 58 * @var string 59 * @since 2.5 60 */ 61 protected $table = '#__content'; 62 63 /** 64 * Load the language file on instantiation. 65 * 66 * @var boolean 67 * @since 3.1 68 */ 69 protected $autoloadLanguage = true; 70 71 /** 72 * Method to update the item link information when the item category is 73 * changed. This is fired when the item category is published or unpublished 74 * from the list view. 75 * 76 * @param string $extension The extension whose category has been updated. 77 * @param array $pks A list of primary key ids of the content that has changed state. 78 * @param integer $value The value of the state that the content has been changed to. 79 * 80 * @return void 81 * 82 * @since 2.5 83 */ 84 public function onFinderCategoryChangeState($extension, $pks, $value) 85 { 86 // Make sure we're handling com_content categories. 87 if ($extension === 'com_content') 88 { 89 $this->categoryStateChange($pks, $value); 90 } 91 } 92 93 /** 94 * Method to remove the link information for items that have been deleted. 95 * 96 * @param string $context The context of the action being performed. 97 * @param JTable $table A JTable object containing the record to be deleted 98 * 99 * @return boolean True on success. 100 * 101 * @since 2.5 102 * @throws Exception on database error. 103 */ 104 public function onFinderAfterDelete($context, $table) 105 { 106 if ($context === 'com_content.article') 107 { 108 $id = $table->id; 109 } 110 elseif ($context === 'com_finder.index') 111 { 112 $id = $table->link_id; 113 } 114 else 115 { 116 return true; 117 } 118 119 // Remove item from the index. 120 return $this->remove($id); 121 } 122 123 /** 124 * Smart Search after save content method. 125 * Reindexes the link information for an article that has been saved. 126 * It also makes adjustments if the access level of an item or the 127 * category to which it belongs has changed. 128 * 129 * @param string $context The context of the content passed to the plugin. 130 * @param JTable $row A JTable object. 131 * @param boolean $isNew True if the content has just been created. 132 * 133 * @return boolean True on success. 134 * 135 * @since 2.5 136 * @throws Exception on database error. 137 */ 138 public function onFinderAfterSave($context, $row, $isNew) 139 { 140 // We only want to handle articles here. 141 if ($context === 'com_content.article' || $context === 'com_content.form') 142 { 143 // Check if the access levels are different. 144 if (!$isNew && $this->old_access != $row->access) 145 { 146 // Process the change. 147 $this->itemAccessChange($row); 148 } 149 150 // Reindex the item. 151 $this->reindex($row->id); 152 } 153 154 // Check for access changes in the category. 155 if ($context === 'com_categories.category') 156 { 157 // Check if the access levels are different. 158 if (!$isNew && $this->old_cataccess != $row->access) 159 { 160 $this->categoryAccessChange($row); 161 } 162 } 163 164 return true; 165 } 166 167 /** 168 * Smart Search before content save method. 169 * This event is fired before the data is actually saved. 170 * 171 * @param string $context The context of the content passed to the plugin. 172 * @param JTable $row A JTable object. 173 * @param boolean $isNew If the content is just about to be created. 174 * 175 * @return boolean True on success. 176 * 177 * @since 2.5 178 * @throws Exception on database error. 179 */ 180 public function onFinderBeforeSave($context, $row, $isNew) 181 { 182 // We only want to handle articles here. 183 if ($context === 'com_content.article' || $context === 'com_content.form') 184 { 185 // Query the database for the old access level if the item isn't new. 186 if (!$isNew) 187 { 188 $this->checkItemAccess($row); 189 } 190 } 191 192 // Check for access levels from the category. 193 if ($context === 'com_categories.category') 194 { 195 // Query the database for the old access level if the item isn't new. 196 if (!$isNew) 197 { 198 $this->checkCategoryAccess($row); 199 } 200 } 201 202 return true; 203 } 204 205 /** 206 * Method to update the link information for items that have been changed 207 * from outside the edit screen. This is fired when the item is published, 208 * unpublished, archived, or unarchived from the list view. 209 * 210 * @param string $context The context for the content passed to the plugin. 211 * @param array $pks An array of primary key ids of the content that has changed state. 212 * @param integer $value The value of the state that the content has been changed to. 213 * 214 * @return void 215 * 216 * @since 2.5 217 */ 218 public function onFinderChangeState($context, $pks, $value) 219 { 220 // We only want to handle articles here. 221 if ($context === 'com_content.article' || $context === 'com_content.form') 222 { 223 $this->itemStateChange($pks, $value); 224 } 225 226 // Handle when the plugin is disabled. 227 if ($context === 'com_plugins.plugin' && $value === 0) 228 { 229 $this->pluginDisable($pks); 230 } 231 } 232 233 /** 234 * Method to index an item. The item must be a FinderIndexerResult object. 235 * 236 * @param FinderIndexerResult $item The item to index as a FinderIndexerResult object. 237 * @param string $format The item format. Not used. 238 * 239 * @return void 240 * 241 * @since 2.5 242 * @throws Exception on database error. 243 */ 244 protected function index(FinderIndexerResult $item, $format = 'html') 245 { 246 $item->setLanguage(); 247 248 // Check if the extension is enabled. 249 if (JComponentHelper::isEnabled($this->extension) === false) 250 { 251 return; 252 } 253 254 $item->context = 'com_content.article'; 255 256 // Initialise the item parameters. 257 $registry = new Registry($item->params); 258 $item->params = JComponentHelper::getParams('com_content', true); 259 $item->params->merge($registry); 260 261 $item->metadata = new Registry($item->metadata); 262 263 // Trigger the onContentPrepare event. 264 $item->summary = FinderIndexerHelper::prepareContent($item->summary, $item->params, $item); 265 $item->body = FinderIndexerHelper::prepareContent($item->body, $item->params, $item); 266 267 // Build the necessary route and path information. 268 $item->url = $this->getUrl($item->id, $this->extension, $this->layout); 269 $item->route = ContentHelperRoute::getArticleRoute($item->slug, $item->catid, $item->language); 270 $item->path = FinderIndexerHelper::getContentPath($item->route); 271 272 // Get the menu title if it exists. 273 $title = $this->getItemMenuTitle($item->url); 274 275 // Adjust the title if necessary. 276 if (!empty($title) && $this->params->get('use_menu_title', true)) 277 { 278 $item->title = $title; 279 } 280 281 // Add the meta author. 282 $item->metaauthor = $item->metadata->get('author'); 283 284 // Add the metadata processing instructions. 285 $item->addInstruction(FinderIndexer::META_CONTEXT, 'metakey'); 286 $item->addInstruction(FinderIndexer::META_CONTEXT, 'metadesc'); 287 $item->addInstruction(FinderIndexer::META_CONTEXT, 'metaauthor'); 288 $item->addInstruction(FinderIndexer::META_CONTEXT, 'author'); 289 $item->addInstruction(FinderIndexer::META_CONTEXT, 'created_by_alias'); 290 291 // Translate the state. Articles should only be published if the category is published. 292 $item->state = $this->translateState($item->state, $item->cat_state); 293 294 // Add the type taxonomy data. 295 $item->addTaxonomy('Type', 'Article'); 296 297 // Add the author taxonomy data. 298 if (!empty($item->author) || !empty($item->created_by_alias)) 299 { 300 $item->addTaxonomy('Author', !empty($item->created_by_alias) ? $item->created_by_alias : $item->author); 301 } 302 303 // Add the category taxonomy data. 304 $item->addTaxonomy('Category', $item->category, $item->cat_state, $item->cat_access); 305 306 // Add the language taxonomy data. 307 $item->addTaxonomy('Language', $item->language); 308 309 // Get content extras. 310 FinderIndexerHelper::getContentExtras($item); 311 312 // Index the item. 313 $this->indexer->index($item); 314 } 315 316 /** 317 * Method to setup the indexer to be run. 318 * 319 * @return boolean True on success. 320 * 321 * @since 2.5 322 */ 323 protected function setup() 324 { 325 // Load dependent classes. 326 JLoader::register('ContentHelperRoute', JPATH_SITE . '/components/com_content/helpers/route.php'); 327 328 return true; 329 } 330 331 /** 332 * Method to get the SQL query used to retrieve the list of content items. 333 * 334 * @param mixed $query A JDatabaseQuery object or null. 335 * 336 * @return JDatabaseQuery A database object. 337 * 338 * @since 2.5 339 */ 340 protected function getListQuery($query = null) 341 { 342 $db = JFactory::getDbo(); 343 344 // Check if we can use the supplied SQL query. 345 $query = $query instanceof JDatabaseQuery ? $query : $db->getQuery(true) 346 ->select('a.id, a.title, a.alias, a.introtext AS summary, a.fulltext AS body') 347 ->select('a.images') 348 ->select('a.state, a.catid, a.created AS start_date, a.created_by') 349 ->select('a.created_by_alias, a.modified, a.modified_by, a.attribs AS params') 350 ->select('a.metakey, a.metadesc, a.metadata, a.language, a.access, a.version, a.ordering') 351 ->select('a.publish_up AS publish_start_date, a.publish_down AS publish_end_date') 352 ->select('c.title AS category, c.published AS cat_state, c.access AS cat_access'); 353 354 // Handle the alias CASE WHEN portion of the query 355 $case_when_item_alias = ' CASE WHEN '; 356 $case_when_item_alias .= $query->charLength('a.alias', '!=', '0'); 357 $case_when_item_alias .= ' THEN '; 358 $a_id = $query->castAsChar('a.id'); 359 $case_when_item_alias .= $query->concatenate(array($a_id, 'a.alias'), ':'); 360 $case_when_item_alias .= ' ELSE '; 361 $case_when_item_alias .= $a_id . ' END as slug'; 362 $query->select($case_when_item_alias); 363 364 $case_when_category_alias = ' CASE WHEN '; 365 $case_when_category_alias .= $query->charLength('c.alias', '!=', '0'); 366 $case_when_category_alias .= ' THEN '; 367 $c_id = $query->castAsChar('c.id'); 368 $case_when_category_alias .= $query->concatenate(array($c_id, 'c.alias'), ':'); 369 $case_when_category_alias .= ' ELSE '; 370 $case_when_category_alias .= $c_id . ' END as catslug'; 371 $query->select($case_when_category_alias) 372 373 ->select('u.name AS author') 374 ->from('#__content AS a') 375 ->join('LEFT', '#__categories AS c ON c.id = a.catid') 376 ->join('LEFT', '#__users AS u ON u.id = a.created_by'); 377 378 return $query; 379 } 380} 381