1<?php 2/** 3 * @package Joomla.Administrator 4 * @subpackage com_finder 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 12/** 13 * Stemmer base class for the Finder indexer package. 14 * 15 * @since 2.5 16 */ 17class FinderIndexerTaxonomy 18{ 19 /** 20 * An internal cache of taxonomy branch data. 21 * 22 * @var array 23 * @since 2.5 24 */ 25 public static $branches = array(); 26 27 /** 28 * An internal cache of taxonomy node data. 29 * 30 * @var array 31 * @since 2.5 32 */ 33 public static $nodes = array(); 34 35 /** 36 * Method to add a branch to the taxonomy tree. 37 * 38 * @param string $title The title of the branch. 39 * @param integer $state The published state of the branch. [optional] 40 * @param integer $access The access state of the branch. [optional] 41 * 42 * @return integer The id of the branch. 43 * 44 * @since 2.5 45 * @throws Exception on database error. 46 */ 47 public static function addBranch($title, $state = 1, $access = 1) 48 { 49 // Check to see if the branch is in the cache. 50 if (isset(static::$branches[$title])) 51 { 52 return static::$branches[$title]->id; 53 } 54 55 // Check to see if the branch is in the table. 56 $db = JFactory::getDbo(); 57 $query = $db->getQuery(true) 58 ->select('*') 59 ->from($db->quoteName('#__finder_taxonomy')) 60 ->where($db->quoteName('parent_id') . ' = 1') 61 ->where($db->quoteName('title') . ' = ' . $db->quote($title)); 62 $db->setQuery($query); 63 64 // Get the result. 65 $result = $db->loadObject(); 66 67 // Check if the database matches the input data. 68 if ((bool) $result && $result->state == $state && $result->access == $access) 69 { 70 // The data matches, add the item to the cache. 71 static::$branches[$title] = $result; 72 73 return static::$branches[$title]->id; 74 } 75 76 /* 77 * The database did not match the input. This could be because the 78 * state has changed or because the branch does not exist. Let's figure 79 * out which case is true and deal with it. 80 */ 81 $branch = new JObject; 82 83 if (empty($result)) 84 { 85 // Prepare the branch object. 86 $branch->parent_id = 1; 87 $branch->title = $title; 88 $branch->state = (int) $state; 89 $branch->access = (int) $access; 90 } 91 else 92 { 93 // Prepare the branch object. 94 $branch->id = (int) $result->id; 95 $branch->parent_id = (int) $result->parent_id; 96 $branch->title = $result->title; 97 $branch->state = (int) $result->title; 98 $branch->access = (int) $result->access; 99 $branch->ordering = (int) $result->ordering; 100 } 101 102 // Store the branch. 103 static::storeNode($branch); 104 105 // Add the branch to the cache. 106 static::$branches[$title] = $branch; 107 108 return static::$branches[$title]->id; 109 } 110 111 /** 112 * Method to add a node to the taxonomy tree. 113 * 114 * @param string $branch The title of the branch to store the node in. 115 * @param string $title The title of the node. 116 * @param integer $state The published state of the node. [optional] 117 * @param integer $access The access state of the node. [optional] 118 * 119 * @return integer The id of the node. 120 * 121 * @since 2.5 122 * @throws Exception on database error. 123 */ 124 public static function addNode($branch, $title, $state = 1, $access = 1) 125 { 126 // Check to see if the node is in the cache. 127 if (isset(static::$nodes[$branch][$title])) 128 { 129 return static::$nodes[$branch][$title]->id; 130 } 131 132 // Get the branch id, insert it if it does not exist. 133 $branchId = static::addBranch($branch); 134 135 // Check to see if the node is in the table. 136 $db = JFactory::getDbo(); 137 $query = $db->getQuery(true) 138 ->select('*') 139 ->from($db->quoteName('#__finder_taxonomy')) 140 ->where($db->quoteName('parent_id') . ' = ' . $db->quote($branchId)) 141 ->where($db->quoteName('title') . ' = ' . $db->quote($title)); 142 $db->setQuery($query); 143 144 // Get the result. 145 $result = $db->loadObject(); 146 147 // Check if the database matches the input data. 148 if ((bool) $result && $result->state == $state && $result->access == $access) 149 { 150 // The data matches, add the item to the cache. 151 static::$nodes[$branch][$title] = $result; 152 153 return static::$nodes[$branch][$title]->id; 154 } 155 156 /* 157 * The database did not match the input. This could be because the 158 * state has changed or because the node does not exist. Let's figure 159 * out which case is true and deal with it. 160 */ 161 $node = new JObject; 162 163 if (empty($result)) 164 { 165 // Prepare the node object. 166 $node->parent_id = (int) $branchId; 167 $node->title = $title; 168 $node->state = (int) $state; 169 $node->access = (int) $access; 170 } 171 else 172 { 173 // Prepare the node object. 174 $node->id = (int) $result->id; 175 $node->parent_id = (int) $result->parent_id; 176 $node->title = $result->title; 177 $node->state = (int) $result->title; 178 $node->access = (int) $result->access; 179 $node->ordering = (int) $result->ordering; 180 } 181 182 // Store the node. 183 static::storeNode($node); 184 185 // Add the node to the cache. 186 static::$nodes[$branch][$title] = $node; 187 188 return static::$nodes[$branch][$title]->id; 189 } 190 191 /** 192 * Method to add a map entry between a link and a taxonomy node. 193 * 194 * @param integer $linkId The link to map to. 195 * @param integer $nodeId The node to map to. 196 * 197 * @return boolean True on success. 198 * 199 * @since 2.5 200 * @throws Exception on database error. 201 */ 202 public static function addMap($linkId, $nodeId) 203 { 204 // Insert the map. 205 $db = JFactory::getDbo(); 206 207 $query = $db->getQuery(true) 208 ->select($db->quoteName('link_id')) 209 ->from($db->quoteName('#__finder_taxonomy_map')) 210 ->where($db->quoteName('link_id') . ' = ' . (int) $linkId) 211 ->where($db->quoteName('node_id') . ' = ' . (int) $nodeId); 212 $db->setQuery($query); 213 $db->execute(); 214 $id = (int) $db->loadResult(); 215 216 $map = new JObject; 217 $map->link_id = (int) $linkId; 218 $map->node_id = (int) $nodeId; 219 220 if ($id) 221 { 222 $db->updateObject('#__finder_taxonomy_map', $map, array('link_id', 'node_id')); 223 } 224 else 225 { 226 $db->insertObject('#__finder_taxonomy_map', $map); 227 } 228 229 return true; 230 } 231 232 /** 233 * Method to get the title of all taxonomy branches. 234 * 235 * @return array An array of branch titles. 236 * 237 * @since 2.5 238 * @throws Exception on database error. 239 */ 240 public static function getBranchTitles() 241 { 242 $db = JFactory::getDbo(); 243 244 // Set user variables 245 $groups = implode(',', JFactory::getUser()->getAuthorisedViewLevels()); 246 247 // Create a query to get the taxonomy branch titles. 248 $query = $db->getQuery(true) 249 ->select($db->quoteName('title')) 250 ->from($db->quoteName('#__finder_taxonomy')) 251 ->where($db->quoteName('parent_id') . ' = 1') 252 ->where($db->quoteName('state') . ' = 1') 253 ->where($db->quoteName('access') . ' IN (' . $groups . ')'); 254 255 // Get the branch titles. 256 $db->setQuery($query); 257 258 return $db->loadColumn(); 259 } 260 261 /** 262 * Method to find a taxonomy node in a branch. 263 * 264 * @param string $branch The branch to search. 265 * @param string $title The title of the node. 266 * 267 * @return mixed Integer id on success, null on no match. 268 * 269 * @since 2.5 270 * @throws Exception on database error. 271 */ 272 public static function getNodeByTitle($branch, $title) 273 { 274 $db = JFactory::getDbo(); 275 276 // Set user variables 277 $groups = implode(',', JFactory::getUser()->getAuthorisedViewLevels()); 278 279 // Create a query to get the node. 280 $query = $db->getQuery(true) 281 ->select('t1.*') 282 ->from($db->quoteName('#__finder_taxonomy') . ' AS t1') 283 ->join('INNER', $db->quoteName('#__finder_taxonomy') . ' AS t2 ON t2.id = t1.parent_id') 284 ->where('t1.access IN (' . $groups . ')') 285 ->where('t1.state = 1') 286 ->where('t1.title LIKE ' . $db->quote($db->escape($title) . '%')) 287 ->where('t2.access IN (' . $groups . ')') 288 ->where('t2.state = 1') 289 ->where('t2.title = ' . $db->quote($branch)); 290 291 // Get the node. 292 $db->setQuery($query, 0, 1); 293 294 return $db->loadObject(); 295 } 296 297 /** 298 * Method to remove map entries for a link. 299 * 300 * @param integer $linkId The link to remove. 301 * 302 * @return boolean True on success. 303 * 304 * @since 2.5 305 * @throws Exception on database error. 306 */ 307 public static function removeMaps($linkId) 308 { 309 // Delete the maps. 310 $db = JFactory::getDbo(); 311 $query = $db->getQuery(true) 312 ->delete($db->quoteName('#__finder_taxonomy_map')) 313 ->where($db->quoteName('link_id') . ' = ' . (int) $linkId); 314 $db->setQuery($query); 315 $db->execute(); 316 317 return true; 318 } 319 320 /** 321 * Method to remove orphaned taxonomy nodes and branches. 322 * 323 * @return integer The number of deleted rows. 324 * 325 * @since 2.5 326 * @throws Exception on database error. 327 */ 328 public static function removeOrphanNodes() 329 { 330 // Delete all orphaned nodes. 331 $db = JFactory::getDbo(); 332 $query = $db->getQuery(true); 333 $subquery = $db->getQuery(true); 334 $subquery1 = $db->getQuery(true); 335 336 $subquery1->select($db->quoteName('t.id')) 337 ->from($db->quoteName('#__finder_taxonomy', 't')) 338 ->join('LEFT', $db->quoteName('#__finder_taxonomy_map', 'm') . ' ON ' . $db->quoteName('m.node_id') . '=' . $db->quoteName('t.id')) 339 ->where($db->quoteName('t.parent_id') . ' > 1 ') 340 ->where($db->quoteName('m.link_id') . ' IS NULL'); 341 342 $subquery->select($db->quoteName('id')) 343 ->from('(' . $subquery1 . ') temp'); 344 345 $query->delete($db->quoteName('#__finder_taxonomy')) 346 ->where($db->quoteName('id') . ' IN (' . $subquery . ')'); 347 348 $db->setQuery($query); 349 $db->execute(); 350 351 return $db->getAffectedRows(); 352 } 353 354 /** 355 * Method to store a node to the database. This method will accept either a branch or a node. 356 * 357 * @param object $item The item to store. 358 * 359 * @return boolean True on success. 360 * 361 * @since 2.5 362 * @throws Exception on database error. 363 */ 364 protected static function storeNode($item) 365 { 366 $db = JFactory::getDbo(); 367 368 // Check if we are updating or inserting the item. 369 if (empty($item->id)) 370 { 371 // Insert the item. 372 $db->insertObject('#__finder_taxonomy', $item, 'id'); 373 } 374 else 375 { 376 // Update the item. 377 $db->updateObject('#__finder_taxonomy', $item, 'id'); 378 } 379 380 return true; 381 } 382} 383