PageRenderTime 52ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 1ms

/libraries/cms/helper/tags.php

https://bitbucket.org/pastor399/newcastleunifc
PHP | 905 lines | 536 code | 111 blank | 258 comment | 76 complexity | cb8f6918376464ea28de8df59b713930 MD5 | raw file
  1. <?php
  2. /**
  3. * @package Joomla.Libraries
  4. * @subpackage Helper
  5. *
  6. * @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
  7. * @license GNU General Public License version 2 or later; see LICENSE
  8. */
  9. defined('JPATH_PLATFORM') or die;
  10. /**
  11. * Tags helper class, provides methods to perform various tasks relevant
  12. * tagging of content.
  13. *
  14. * @package Joomla.Libraries
  15. * @subpackage Helper
  16. * @since 3.1
  17. */
  18. class JHelperTags
  19. {
  20. /**
  21. * Helper object for storing and deleting tag information.
  22. *
  23. * @var boolean
  24. * @since 3.1
  25. */
  26. protected $tagsChanged = false;
  27. /**
  28. * Whether up replace all tags or just add tags
  29. *
  30. * @var boolean
  31. * @since 3.1
  32. */
  33. protected $replaceTags = false;
  34. /**
  35. * Alias for quering mapping and content type table.
  36. *
  37. * @var string
  38. * @since 3.1
  39. */
  40. public $typeAlias = null;
  41. /**
  42. * Method to add tag rows to mapping table.
  43. *
  44. * @param integer $ucmId Id of the #__ucm_content item being tagged
  45. * @param JTable $table JTable object being tagged
  46. * @param array $tags Array of tags to be applied.
  47. *
  48. * @return boolean true on success, otherwise false.
  49. *
  50. * @since 3.1
  51. */
  52. public function addTagMapping($ucmId, $table, $tags = array())
  53. {
  54. $typeId = $this->typeAlias;
  55. $db = $table->getDbo();
  56. $key = $table->getKeyName();
  57. $item = $table->$key;
  58. $typeId = $this->getTypeId($this->typeAlias);
  59. // Insert the new tag maps
  60. $query = $db->getQuery(true);
  61. $query->insert('#__contentitem_tag_map');
  62. $query->columns(array($db->quoteName('type_alias'), $db->quoteName('core_content_id'), $db->quoteName('content_item_id'), $db->quoteName('tag_id'), $db->quoteName('tag_date'), $db->quoteName('type_id')));
  63. foreach ($tags as $tag)
  64. {
  65. $query->values($db->quote($this->typeAlias) . ', ' . (int) $ucmId . ', ' . (int) $item . ', ' . $db->quote($tag) . ', ' . $query->currentTimestamp() . ', ' . (int) $typeId);
  66. }
  67. $db->setQuery($query);
  68. return (boolean) $db->execute();
  69. }
  70. /**
  71. * Function that converts tags paths into paths of names
  72. *
  73. * @param array $tags Array of tags
  74. *
  75. * @return array
  76. *
  77. * @since 3.1
  78. */
  79. public static function convertPathsToNames($tags)
  80. {
  81. // We will replace path aliases with tag names
  82. if ($tags)
  83. {
  84. // Create an array with all the aliases of the results
  85. $aliases = array();
  86. foreach ($tags as $tag)
  87. {
  88. if (!empty($tag->path))
  89. {
  90. if ($pathParts = explode('/', $tag->path))
  91. {
  92. $aliases = array_merge($aliases, $pathParts);
  93. }
  94. }
  95. }
  96. // Get the aliases titles in one single query and map the results
  97. if ($aliases)
  98. {
  99. // Remove duplicates
  100. $aliases = array_unique($aliases);
  101. $db = JFactory::getDbo();
  102. $query = $db->getQuery(true)
  103. ->select('alias, title')
  104. ->from('#__tags')
  105. ->where('alias IN (' . implode(',', array_map(array($db, 'quote'), $aliases)) . ')');
  106. $db->setQuery($query);
  107. try
  108. {
  109. $aliasesMapper = $db->loadAssocList('alias');
  110. }
  111. catch (RuntimeException $e)
  112. {
  113. return false;
  114. }
  115. // Rebuild the items path
  116. if ($aliasesMapper)
  117. {
  118. foreach ($tags as $tag)
  119. {
  120. $namesPath = array();
  121. if (!empty($tag->path))
  122. {
  123. if ($pathParts = explode('/', $tag->path))
  124. {
  125. foreach ($pathParts as $alias)
  126. {
  127. if (isset($aliasesMapper[$alias]))
  128. {
  129. $namesPath[] = $aliasesMapper[$alias]['title'];
  130. }
  131. else
  132. {
  133. $namesPath[] = $alias;
  134. }
  135. }
  136. $tag->text = implode('/', $namesPath);
  137. }
  138. }
  139. }
  140. }
  141. }
  142. }
  143. return $tags;
  144. }
  145. /**
  146. * Create any new tags by looking for #new# in the metadata
  147. *
  148. * @param string $metadata Metadata JSON string
  149. *
  150. * @return mixed If successful, metadata with new tag titles replaced by tag ids. Otherwise false.
  151. *
  152. * @since 3.1
  153. */
  154. public function createTagsFromMetadata($metadata)
  155. {
  156. $metaObject = json_decode($metadata);
  157. $tags = $metaObject->tags;
  158. if (empty($tags) || !is_array($tags))
  159. {
  160. $result = $metadata;
  161. }
  162. else
  163. {
  164. // We will use the tags table to store them
  165. JTable::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_tags/tables');
  166. $tagTable = JTable::getInstance('Tag', 'TagsTable');
  167. $newTags = array();
  168. foreach ($tags as $key => $tag)
  169. {
  170. // Remove the #new# prefix that identifies new tags
  171. $tagText = str_replace('#new#', '', $tag);
  172. if ($tagText == $tag)
  173. {
  174. $newTags[] = (int) $tag;
  175. }
  176. else
  177. {
  178. // Clear old data if exist
  179. $tagTable->reset();
  180. // Try to load the selected tag
  181. if ($tagTable->load(array('title' => $tagText)))
  182. {
  183. $newTags[] = (int) $tagTable->id;
  184. }
  185. else
  186. {
  187. // Prepare tag data
  188. $tagTable->id = 0;
  189. $tagTable->title = $tagText;
  190. $tagTable->published = 1;
  191. // $tagTable->language = property_exists ($item, 'language') ? $item->language : '*';
  192. $tagTable->language = '*';
  193. $tagTable->access = 1;
  194. // Make this item a child of the root tag
  195. $tagTable->setLocation($tagTable->getRootId(), 'last-child');
  196. // Try to store tag
  197. if ($tagTable->check())
  198. {
  199. // Assign the alias as path (autogenerated tags have always level 1)
  200. $tagTable->path = $tagTable->alias;
  201. if ($tagTable->store())
  202. {
  203. $newTags[] = (int) $tagTable->id;
  204. }
  205. }
  206. }
  207. }
  208. }
  209. // At this point $tags is an array of all tag ids
  210. $metaObject->tags = $newTags;
  211. $result = json_encode($metaObject);
  212. }
  213. return $result;
  214. }
  215. /**
  216. * Method to delete the tag mappings and #__ucm_content record for for an item
  217. *
  218. * @param JTable $table JTable object of content table where delete occurred
  219. * @param integer $contentItemId Id of the content item.
  220. *
  221. * @return boolean true on success, false on failure
  222. *
  223. * @since 3.1
  224. */
  225. public function deleteTagData(JTable $table, $contentItemId)
  226. {
  227. $result = $this->unTagItem($contentItemId, $table);
  228. $ucmContentTable = JTable::getInstance('Corecontent');
  229. return $result && $ucmContentTable->deleteByContentId($contentItemId);
  230. }
  231. /**
  232. * Method to get a list of tags for an item, optionally with the tag data.
  233. *
  234. * @param integer $contentType Content type alias. Dot separated.
  235. * @param integer $id Id of the item to retrieve tags for.
  236. * @param boolean $getTagData If true, data from the tags table will be included, defaults to true.
  237. *
  238. * @return array Array of of tag objects
  239. *
  240. * @since 3.1
  241. */
  242. public function getItemTags($contentType, $id, $getTagData = true)
  243. {
  244. if (is_array($id))
  245. {
  246. $id = implode($id);
  247. }
  248. // Initialize some variables.
  249. $db = JFactory::getDbo();
  250. $query = $db->getQuery(true)
  251. ->select($db->quoteName('m.tag_id'))
  252. ->from($db->quoteName('#__contentitem_tag_map') . ' AS m ')
  253. ->where(
  254. array(
  255. $db->quoteName('m.type_alias') . ' = ' . $db->quote($contentType),
  256. $db->quoteName('m.content_item_id') . ' = ' . $id,
  257. $db->quoteName('t.published') . ' = 1'
  258. )
  259. );
  260. $user = JFactory::getUser();
  261. $groups = implode(',', $user->getAuthorisedViewLevels());
  262. $query->where('t.access IN (' . $groups . ')');
  263. // Optionally filter on language
  264. if (empty($language))
  265. {
  266. $language = JComponentHelper::getParams('com_tags')->get('tag_list_language_filter', 'all');
  267. }
  268. if ($language != 'all')
  269. {
  270. if ($language == 'current_language')
  271. {
  272. $language = JHelperContent::getCurrentLanguage();
  273. }
  274. $query->where($db->quoteName('language') . ' IN (' . $db->quote($language) . ', ' . $db->quote('*') . ')');
  275. }
  276. if ($getTagData)
  277. {
  278. $query->select($db->quoteName('t') . '.*');
  279. }
  280. $query->join('INNER', $db->quoteName('#__tags') . ' AS t ' . ' ON ' . $db->quoteName('m.tag_id') . ' = ' . $db->quoteName('t.id'));
  281. $db->setQuery($query);
  282. $this->itemTags = $db->loadObjectList();
  283. return $this->itemTags;
  284. }
  285. /**
  286. * Method to get a list of tags for a given item.
  287. * Normally used for displaying a list of tags within a layout
  288. *
  289. * @param integer $id The id (primary key) of the item to be tagged.
  290. * @param string $prefix Dot separated string with the option and view to be used for a url.
  291. *
  292. * @return string Comma separated list of tag Ids.
  293. *
  294. * @since 3.1
  295. */
  296. public function getTagIds($id, $prefix)
  297. {
  298. if (!empty($id))
  299. {
  300. if (is_array($id))
  301. {
  302. $id = implode(',', $id);
  303. }
  304. $db = JFactory::getDbo();
  305. $query = $db->getQuery(true);
  306. // Load the tags.
  307. $query->clear()
  308. ->select($db->quoteName('t.id'))
  309. ->from($db->quoteName('#__tags') . ' AS t ')
  310. ->join(
  311. 'INNER', $db->quoteName('#__contentitem_tag_map') . ' AS m'
  312. . ' ON ' . $db->quoteName('m.tag_id') . ' = ' . $db->quoteName('t.id')
  313. . ' AND ' . $db->quoteName('m.type_alias') . ' = ' . $db->quote($prefix)
  314. . ' AND ' . $db->quoteName('m.content_item_id') . ' IN ( ' . $id . ')'
  315. );
  316. $db->setQuery($query);
  317. // Add the tags to the content data.
  318. $tagsList = $db->loadColumn();
  319. $this->tags = implode(',', $tagsList);
  320. }
  321. else
  322. {
  323. $this->tags = null;
  324. }
  325. return $this->tags;
  326. }
  327. /**
  328. * Method to get a query to retrieve a detailed list of items for a tag.
  329. *
  330. * @param mixed $tagId Tag or array of tags to be matched
  331. * @param mixed $typesr Null, type or array of type aliases for content types to be included in the results
  332. * @param boolean $includeChildren True to include the results from child tags
  333. * @param string $orderByOption Column to order the results by
  334. * @param string $orderDir Direction to sort the results in
  335. * @param boolean $anyOrAll True to include items matching at least one tag, false to include
  336. * items all tags in the array.
  337. * @param string $languageFilter Optional filter on language. Options are 'all', 'current' or any string.
  338. * @param string $stateFilter Optional filtering on publication state, defaults to published or unpublished.
  339. *
  340. * @return JDatabaseQuery Query to retrieve a list of tags
  341. *
  342. * @since 3.1
  343. */
  344. public function getTagItemsQuery($tagId, $typesr = null, $includeChildren = false, $orderByOption = 'c.core_title', $orderDir = 'ASC',
  345. $anyOrAll = true, $languageFilter = 'all', $stateFilter = '0,1')
  346. {
  347. // Create a new query object.
  348. $db = JFactory::getDbo();
  349. $query = $db->getQuery(true);
  350. $user = JFactory::getUser();
  351. $nullDate = $db->quote($db->getNullDate());
  352. $ntagsr = substr_count($tagId, ',') + 1;
  353. // If we want to include children we have to adjust the list of tags.
  354. // We do not search child tags when the match all option is selected.
  355. if ($includeChildren)
  356. {
  357. if (!is_array($tagId))
  358. {
  359. $tagIdArray = explode(',', $tagId);
  360. }
  361. else
  362. {
  363. $tagIdArray = $tagId;
  364. }
  365. $tagTreeList = '';
  366. foreach ($tagIdArray as $tag)
  367. {
  368. if ($this->getTagTreeArray($tag, $tagTreeArray))
  369. {
  370. $tagTreeList .= implode(',', $this->getTagTreeArray($tag, $tagTreeArray)) . ',';
  371. }
  372. }
  373. if ($tagTreeList)
  374. {
  375. $tagId = trim($tagTreeList, ',');
  376. }
  377. }
  378. if (is_array($tagId))
  379. {
  380. $tagId = implode(',', $tagId);
  381. }
  382. // M is the mapping table. C is the core_content table. Ct is the content_types table.
  383. $query->select('m.type_alias, m.content_item_id, m.core_content_id, count(m.tag_id) AS match_count, MAX(m.tag_date) as tag_date, MAX(c.core_title) AS core_title')
  384. ->select('MAX(c.core_alias) AS core_alias, MAX(c.core_body) AS core_body, MAX(c.core_state) AS core_state, MAX(c.core_access) AS core_access')
  385. ->select('MAX(c.core_metadata) AS core_metadata, MAX(c.core_created_user_id) AS core_created_user_id, MAX(c.core_created_by_alias) AS core_created_by_alias')
  386. ->select('MAX(c.core_created_time) as core_created_time, MAX(c.core_images) as core_images')
  387. ->select('CASE WHEN c.core_modified_time = ' . $nullDate . ' THEN c.core_created_time ELSE c.core_modified_time END as core_modified_time')
  388. ->select('MAX(c.core_language) AS core_language, MAX(c.core_catid) AS core_catid')
  389. ->select('MAX(c.core_publish_up) AS core_publish_up, MAX(c.core_publish_down) as core_publish_down')
  390. ->select('MAX(ct.type_title) AS content_type_title, MAX(ct.router) AS router')
  391. ->from('#__contentitem_tag_map AS m')
  392. ->join('INNER', '#__ucm_content AS c ON m.type_alias = c.core_type_alias AND m.core_content_id = c.core_content_id')
  393. ->join('INNER', '#__content_types AS ct ON ct.type_alias = m.type_alias')
  394. // Join over the users for the author and email
  395. ->select("CASE WHEN c.core_created_by_alias > ' ' THEN c.core_created_by_alias ELSE ua.name END AS author")
  396. ->select("ua.email AS author_email")
  397. ->join('LEFT', '#__users AS ua ON ua.id = c.core_created_user_id')
  398. ->where('m.tag_id IN (' . $tagId . ')')
  399. ->where('c.core_state IN (' . $stateFilter . ')');
  400. // Optionally filter on language
  401. if (empty($language))
  402. {
  403. $language = $languageFilter;
  404. }
  405. if ($language != 'all')
  406. {
  407. if ($language == 'current_language')
  408. {
  409. $language = JHelperContent::getCurrentLanguage();
  410. }
  411. $query->where($db->quoteName('c.core_language') . ' IN (' . $db->quote($language) . ', ' . $db->quote('*') . ')');
  412. }
  413. // Get the type data, limited to types in the request if there are any specified.
  414. $typesarray = self::getTypes('assocList', $typesr, false);
  415. $typeAliases = '';
  416. foreach ($typesarray as $type)
  417. {
  418. $typeAliases .= "'" . $type['type_alias'] . "'" . ',';
  419. }
  420. $typeAliases = rtrim($typeAliases, ',');
  421. $query->where('m.type_alias IN (' . $typeAliases . ')');
  422. $groups = '0,' . implode(',', array_unique($user->getAuthorisedViewLevels()));
  423. $query->where('c.core_access IN (' . $groups . ')')
  424. ->group('m.type_alias, m.content_item_id, m.core_content_id');
  425. // Use HAVING if matching all tags and we are matching more than one tag.
  426. if ($ntagsr > 1 && $anyOrAll != 1 && $includeChildren != 1)
  427. {
  428. // The number of results should equal the number of tags requested.
  429. $query->having("COUNT('m.tag_id') = " . $ntagsr);
  430. }
  431. // Set up the order by using the option chosen
  432. if ($orderByOption == 'match_count')
  433. {
  434. $orderBy = 'COUNT(m.tag_id)';
  435. }
  436. else
  437. {
  438. $orderBy = 'MAX(' . $orderByOption . ')';
  439. }
  440. $query->order($orderBy . ' ' . $orderDir);
  441. return $query;
  442. }
  443. /**
  444. * Function that converts tag ids to their tag names
  445. *
  446. * @param array $tagIds array of integer tag ids.
  447. *
  448. * @return array An array of tag names.
  449. *
  450. * @since 3.1
  451. */
  452. public function getTagNames($tagIds)
  453. {
  454. $tagNames = array();
  455. if (is_array($tagIds) && count($tagIds) > 0)
  456. {
  457. JArrayHelper::toInteger($tagIds);
  458. $tagIds = implode(',', $tagIds);
  459. $db = JFactory::getDbo();
  460. $query = $db->getQuery(true);
  461. $query->select($db->quoteName('title'))
  462. ->from($db->quoteName('#__tags'))
  463. ->where($db->quoteName('id') . ' IN (' . $tagIds . ')');
  464. $query->order($db->quoteName('title'));
  465. $db->setQuery($query);
  466. $tagNames = $db->loadColumn();
  467. }
  468. return $tagNames;
  469. }
  470. /**
  471. * Method to get an array of tag ids for the current tag and its children
  472. *
  473. * @param integer $id An optional ID
  474. * @param array &$tagTreeArray Array containing the tag tree
  475. *
  476. * @return mixed
  477. *
  478. * @since 3.1
  479. */
  480. public function getTagTreeArray($id, &$tagTreeArray = array())
  481. {
  482. // Get a level row instance.
  483. $table = JTable::getInstance('Tag', 'TagsTable');
  484. if ($table->isLeaf($id))
  485. {
  486. $tagTreeArray[] .= $id;
  487. return $tagTreeArray;
  488. }
  489. $tagTree = $table->getTree($id);
  490. // Attempt to load the tree
  491. if ($tagTree)
  492. {
  493. foreach ($tagTree as $tag)
  494. {
  495. $tagTreeArray[] = $tag->id;
  496. }
  497. return $tagTreeArray;
  498. }
  499. }
  500. /**
  501. * Method to get the type id for a type alias.
  502. *
  503. * @param string $typeAlias A type alias.
  504. *
  505. * @return string Name of the table for a type
  506. *
  507. * @since 3.1
  508. */
  509. public function getTypeId($typeAlias)
  510. {
  511. // Initialize some variables.
  512. $db = JFactory::getDbo();
  513. $query = $db->getQuery(true)
  514. ->select($db->quoteName('type_id'))
  515. ->from($db->quoteName('#__content_types'))
  516. ->where($db->quoteName('type_alias') . ' = ' . $db->quote($typeAlias));
  517. $db->setQuery($query);
  518. $this->type_id = $db->loadResult();
  519. return $this->type_id;
  520. }
  521. /**
  522. * Method to get a list of types with associated data.
  523. *
  524. * @param string $arrayType Optionally specify that the returned list consist of objects, associative arrays, or arrays.
  525. * Options are: rowList, assocList, and objectList
  526. * @param array $selectTypes Optional array of type ids to limit the results to. Often from a request.
  527. * @param boolean $useAlias If true, the alias is used to match, if false the type_id is used.
  528. *
  529. * @return array Array of of types
  530. *
  531. * @since 3.1
  532. */
  533. public static function getTypes($arrayType = 'objectList', $selectTypes = null, $useAlias = true)
  534. {
  535. // Initialize some variables.
  536. $db = JFactory::getDbo();
  537. $query = $db->getQuery(true);
  538. $query->select('*');
  539. if (!empty($selectTypes))
  540. {
  541. if (is_array($selectTypes))
  542. {
  543. $selectTypes = implode(',', $selectTypes);
  544. }
  545. if ($useAlias)
  546. {
  547. $query->where($db->quoteName('type_alias') . ' IN (' . $db->quote($selectTypes) . ')');
  548. }
  549. else
  550. {
  551. $query->where($db->quoteName('type_id') . ' IN (' . $selectTypes . ')');
  552. }
  553. }
  554. $query->from($db->quoteName('#__content_types'));
  555. $db->setQuery($query);
  556. switch ($arrayType)
  557. {
  558. case 'assocList':
  559. $types = $db->loadAssocList();
  560. break;
  561. case 'rowList':
  562. $types = $db->loadRowList();
  563. break;
  564. case 'objectList':
  565. default:
  566. $types = $db->loadObjectList();
  567. break;
  568. }
  569. return $types;
  570. }
  571. /**
  572. * Function that handles saving tags used in a table class after a store()
  573. *
  574. * @param JTable $table JTable being processed
  575. *
  576. * @return null
  577. *
  578. * @since 3.1
  579. */
  580. public function postStoreProcess($table)
  581. {
  582. $metaObject = json_decode($table->get('metadata'));
  583. $tags = (isset($metaObject->tags)) ? $metaObject->tags : null;
  584. $result = true;
  585. // Process ucm_content and ucm_base if either tags have changed or we have some tags.
  586. if ($this->tagsChanged || $tags)
  587. {
  588. if (!$tags)
  589. {
  590. // Delete all tags data
  591. $key = $table->getKeyName();
  592. $result = $this->deleteTagData($table, $table->$key);
  593. }
  594. else
  595. {
  596. // Process the tags
  597. $rowdata = new JHelperContent;
  598. $data = $rowdata->getRowData($table);
  599. $ucmContentTable = JTable::getInstance('Corecontent');
  600. $ucm = new JUcmContent($table, $this->typeAlias);
  601. $ucmData = $data ? $ucm->mapData($data) : $ucm->ucmData;
  602. $primaryId = $ucm->getPrimaryKey($ucmData['common']['core_type_id'], $ucmData['common']['core_content_item_id']);
  603. $result = $ucmContentTable->load($primaryId);
  604. $result = $result && $ucmContentTable->bind($ucmData['common']);
  605. $result = $result && $ucmContentTable->check();
  606. $result = $result && $ucmContentTable->store();
  607. $ucmId = $ucmContentTable->core_content_id;
  608. // Store the tag data if the article data was saved and run related methods.
  609. $result = $result && $this->tagItem($ucmId, $table, json_decode($table->metadata)->tags, true);
  610. }
  611. }
  612. return $result;
  613. }
  614. /**
  615. * Function that preProcesses data from a table prior to a store() to ensure proper tag handling
  616. *
  617. * @param JTable $table JTable being processed
  618. *
  619. * @return null
  620. *
  621. * @since 3.1
  622. */
  623. public function preStoreProcess($table)
  624. {
  625. if ($newMetadata = $this->createTagsFromMetadata($table->metadata))
  626. {
  627. $table->metadata = $newMetadata;
  628. }
  629. // If existing row, check to see if tags have changed.
  630. $oldTable = clone $table;
  631. $oldTable->reset();
  632. $key = $oldTable->getKeyName();
  633. if ($oldTable->$key && $oldTable->load())
  634. {
  635. $oldMetaObject = json_decode($oldTable->get('metadata'));
  636. $oldTags = (isset($oldMetaObject->tags)) ? $oldMetaObject->tags : null;
  637. $newMetaObject = json_decode($table->get('metadata'));
  638. $newTags = (isset($newMetaObject->tags)) ? $newMetaObject->tags : null;
  639. }
  640. // New items with no tags bypass this step.
  641. if (!empty($newTags) && !empty($oldTags))
  642. {
  643. // We need to process tags if the tags have changed or if we have a new row
  644. $this->tagsChanged = ($oldTags != $newTags) || !$table->$key;
  645. }
  646. }
  647. /**
  648. * Function to search tags
  649. *
  650. * @param array $filters Filter to apply to the search
  651. *
  652. * @return array
  653. *
  654. * @since 3.1
  655. */
  656. public static function searchTags($filters = array())
  657. {
  658. $db = JFactory::getDbo();
  659. $query = $db->getQuery(true)
  660. ->select('a.id AS value')
  661. ->select('a.path AS text')
  662. ->select('a.path')
  663. ->from('#__tags AS a')
  664. ->join('LEFT', $db->quoteName('#__tags', 'b') . ' ON a.lft > b.lft AND a.rgt < b.rgt');
  665. // Filter language
  666. if (!empty($filters['flanguage']))
  667. {
  668. $query->where('a.language IN (' . $db->quote($filters['flanguage']) . ',' . $db->quote('*') . ') ');
  669. }
  670. // Do not return root
  671. $query->where($db->quoteName('a.alias') . ' <> ' . $db->quote('root'));
  672. // Search in title or path
  673. if (!empty($filters['like']))
  674. {
  675. $query->where(
  676. '(' . $db->quoteName('a.title') . ' LIKE ' . $db->quote('%' . $filters['like'] . '%')
  677. . ' OR ' . $db->quoteName('a.path') . ' LIKE ' . $db->quote('%' . $filters['like'] . '%') . ')'
  678. );
  679. }
  680. // Filter title
  681. if (!empty($filters['title']))
  682. {
  683. $query->where($db->quoteName('a.title') . ' = ' . $db->quote($filters['title']));
  684. }
  685. // Filter on the published state
  686. if (is_numeric($filters['published']))
  687. {
  688. $query->where('a.published = ' . (int) $filters['published']);
  689. }
  690. // Filter by parent_id
  691. if (!empty($filters['parent_id']))
  692. {
  693. JTable::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_tags/tables');
  694. $tagTable = JTable::getInstance('Tag', 'TagsTable');
  695. if ($children = $tagTable->getTree($filters['parent_id']))
  696. {
  697. foreach ($children as $child)
  698. {
  699. $childrenIds[] = $child->id;
  700. }
  701. $query->where('a.id IN (' . implode(',', $childrenIds) . ')');
  702. }
  703. }
  704. $query->group('a.id, a.title, a.level, a.lft, a.rgt, a.parent_id, a.published, a.path')
  705. ->order('a.lft ASC');
  706. // Get the options.
  707. $db->setQuery($query);
  708. try
  709. {
  710. $results = $db->loadObjectList();
  711. }
  712. catch (RuntimeException $e)
  713. {
  714. return false;
  715. }
  716. // We will replace path aliases with tag names
  717. $results = self::convertPathsToNames($results);
  718. return $results;
  719. }
  720. /**
  721. * Method to delete all instances of a tag from the mapping table. Generally used when a tag is deleted.
  722. *
  723. * @param integer $tag_id The tag_id (primary key) for the deleted tag.
  724. *
  725. * @return void
  726. *
  727. * @since 3.1
  728. */
  729. public function tagDeleteInstances($tag_id)
  730. {
  731. // Delete the old tag maps.
  732. $db = JFactory::getDbo();
  733. $query = $db->getQuery(true)
  734. ->delete($db->quoteName('#__contentitem_tag_map'))
  735. ->where($db->quoteName('tag_id') . ' = ' . (int) $tag_id);
  736. $db->setQuery($query);
  737. $db->execute();
  738. }
  739. /**
  740. * Method to add or update tags associated with an item.
  741. *
  742. * @param integer $ucmId Id of the #__ucm_content item being tagged
  743. * @param JTable $table JTable object being tagged
  744. * @param array $tags Array of tags to be applied.
  745. * @param boolean $replace Flag indicating if all exising tags should be replaced
  746. *
  747. * @return boolean true on success, otherwise false.
  748. *
  749. * @since 3.1
  750. */
  751. public function tagItem($ucmId, $table, $tags = array(), $replace = true)
  752. {
  753. $result = $this->unTagItem($ucmId, $table);
  754. if ($replace)
  755. {
  756. $newTags = $tags;
  757. }
  758. else
  759. {
  760. $oldTags = json_decode($table->metadata)->tags;
  761. $newTags = array_unique(array_merge($tags, $oldTags));
  762. }
  763. if (is_array($newTags) && count($newTags) > 0)
  764. {
  765. $result = $result && $this->addTagMapping($ucmId, $table, $newTags);
  766. }
  767. return $result;
  768. }
  769. /**
  770. * @param integer $contentId Id of the content item being untagged
  771. * @param JTable $table JTable object being untagged
  772. * @param array $tags Array of tags to be untagged. Use an empty array to untag all existing tags.
  773. *
  774. * @return boolean true on success, otherwise false.
  775. *
  776. * @since 3.1
  777. */
  778. public function unTagItem($contentId, $table, $tags = array())
  779. {
  780. $key = $table->getKeyName();
  781. $id = $table->$key;
  782. $db = JFactory::getDbo();
  783. $query = $db->getQuery(true)
  784. ->delete('#__contentitem_tag_map')
  785. ->where($db->quoteName('type_alias') . ' = ' . $db->quote($this->typeAlias))
  786. ->where($db->quoteName('content_item_id') . ' = ' . (int) $id);
  787. if (is_array($tags) && count($tags) > 0)
  788. {
  789. $query->where($db->quoteName('tag_id') . ' IN ' . implode(',', $tags));
  790. }
  791. $db->setQuery($query);
  792. return (boolean) $db->execute();
  793. }
  794. }