* @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Finder\Administrator\Indexer; use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Tree\ImmutableNodeInterface; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Result class for the Finder indexer package. * * This class uses magic __get() and __set() methods to prevent properties * being added that might confuse the system. All properties not explicitly * declared will be pushed into the elements array and can be accessed * explicitly using the getElement() method. * * @since 2.5 */ class Result implements \Serializable { /** * An array of extra result properties. * * @var array * @since 2.5 */ protected $elements = array(); /** * This array tells the indexer which properties should be indexed and what * weights to use for those properties. * * @var array * @since 2.5 */ protected $instructions = array( Indexer::TITLE_CONTEXT => array('title', 'subtitle', 'id'), Indexer::TEXT_CONTEXT => array('summary', 'body'), Indexer::META_CONTEXT => array('meta', 'list_price', 'sale_price'), Indexer::PATH_CONTEXT => array('path', 'alias'), Indexer::MISC_CONTEXT => array('comments'), ); /** * The indexer will use this data to create taxonomy mapping entries for * the item so that it can be filtered by type, label, category, * or whatever. * * @var array * @since 2.5 */ protected $taxonomy = array(); /** * The content URL. * * @var string * @since 2.5 */ public $url; /** * The content route. * * @var string * @since 2.5 */ public $route; /** * The content title. * * @var string * @since 2.5 */ public $title; /** * The content description. * * @var string * @since 2.5 */ public $description; /** * The published state of the result. * * @var integer * @since 2.5 */ public $published; /** * The content published state. * * @var integer * @since 2.5 */ public $state; /** * The content access level. * * @var integer * @since 2.5 */ public $access; /** * The content language. * * @var string * @since 2.5 */ public $language = '*'; /** * The publishing start date. * * @var string * @since 2.5 */ public $publish_start_date; /** * The publishing end date. * * @var string * @since 2.5 */ public $publish_end_date; /** * The generic start date. * * @var string * @since 2.5 */ public $start_date; /** * The generic end date. * * @var string * @since 2.5 */ public $end_date; /** * The item list price. * * @var mixed * @since 2.5 */ public $list_price; /** * The item sale price. * * @var mixed * @since 2.5 */ public $sale_price; /** * The content type id. This is set by the adapter. * * @var integer * @since 2.5 */ public $type_id; /** * The default language for content. * * @var string * @since 3.0.2 */ public $defaultLanguage; /** * Constructor * * @since 3.0.3 */ public function __construct() { $this->defaultLanguage = ComponentHelper::getParams('com_languages')->get('site', 'en-GB'); } /** * The magic set method is used to push additional values into the elements * array in order to preserve the cleanliness of the object. * * @param string $name The name of the element. * @param mixed $value The value of the element. * * @return void * * @since 2.5 */ public function __set($name, $value) { $this->setElement($name, $value); } /** * The magic get method is used to retrieve additional element values from the elements array. * * @param string $name The name of the element. * * @return mixed The value of the element if set, null otherwise. * * @since 2.5 */ public function __get($name) { return $this->getElement($name); } /** * The magic isset method is used to check the state of additional element values in the elements array. * * @param string $name The name of the element. * * @return boolean True if set, false otherwise. * * @since 2.5 */ public function __isset($name) { return isset($this->elements[$name]); } /** * The magic unset method is used to unset additional element values in the elements array. * * @param string $name The name of the element. * * @return void * * @since 2.5 */ public function __unset($name) { unset($this->elements[$name]); } /** * Method to retrieve additional element values from the elements array. * * @param string $name The name of the element. * * @return mixed The value of the element if set, null otherwise. * * @since 2.5 */ public function getElement($name) { // Get the element value if set. if (array_key_exists($name, $this->elements)) { return $this->elements[$name]; } return null; } /** * Method to retrieve all elements. * * @return array The elements * * @since 3.8.3 */ public function getElements() { return $this->elements; } /** * Method to set additional element values in the elements array. * * @param string $name The name of the element. * @param mixed $value The value of the element. * * @return void * * @since 2.5 */ public function setElement($name, $value) { $this->elements[$name] = $value; } /** * Method to get all processing instructions. * * @return array An array of processing instructions. * * @since 2.5 */ public function getInstructions() { return $this->instructions; } /** * Method to add a processing instruction for an item property. * * @param string $group The group to associate the property with. * @param string $property The property to process. * * @return void * * @since 2.5 */ public function addInstruction($group, $property) { // Check if the group exists. We can't add instructions for unknown groups. // Check if the property exists in the group. if (array_key_exists($group, $this->instructions) && !in_array($property, $this->instructions[$group], true)) { // Add the property to the group. $this->instructions[$group][] = $property; } } /** * Method to remove a processing instruction for an item property. * * @param string $group The group to associate the property with. * @param string $property The property to process. * * @return void * * @since 2.5 */ public function removeInstruction($group, $property) { // Check if the group exists. We can't remove instructions for unknown groups. if (array_key_exists($group, $this->instructions)) { // Search for the property in the group. $key = array_search($property, $this->instructions[$group]); // If the property was found, remove it. if ($key !== false) { unset($this->instructions[$group][$key]); } } } /** * Method to get the taxonomy maps for an item. * * @param string $branch The taxonomy branch to get. [optional] * * @return array An array of taxonomy maps. * * @since 2.5 */ public function getTaxonomy($branch = null) { // Get the taxonomy branch if available. if ($branch !== null && isset($this->taxonomy[$branch])) { return $this->taxonomy[$branch]; } return $this->taxonomy; } /** * Method to add a taxonomy map for an item. * * @param string $branch The title of the taxonomy branch to add the node to. * @param string $title The title of the taxonomy node. * @param integer $state The published state of the taxonomy node. [optional] * @param integer $access The access level of the taxonomy node. [optional] * @param string $language The language of the taxonomy. [optional] * * @return void * * @since 2.5 */ public function addTaxonomy($branch, $title, $state = 1, $access = 1, $language = '') { // Filter the input. $branch = preg_replace('#[^\pL\pM\pN\p{Pi}\p{Pf}\'+-.,_]+#mui', ' ', $branch); // Create the taxonomy node. $node = new \stdClass(); $node->title = $title; $node->state = (int) $state; $node->access = (int) $access; $node->language = $language; $node->nested = false; // Add the node to the taxonomy branch. $this->taxonomy[$branch][] = $node; } /** * Method to add a nested taxonomy map for an item. * * @param string $branch The title of the taxonomy branch to add the node to. * @param ImmutableNodeInterface $contentNode The node object. * @param integer $state The published state of the taxonomy node. [optional] * @param integer $access The access level of the taxonomy node. [optional] * @param string $language The language of the taxonomy. [optional] * * @return void * * @since 4.0.0 */ public function addNestedTaxonomy($branch, ImmutableNodeInterface $contentNode, $state = 1, $access = 1, $language = '') { // Filter the input. $branch = preg_replace('#[^\pL\pM\pN\p{Pi}\p{Pf}\'+-.,_]+#mui', ' ', $branch); // Create the taxonomy node. $node = new \stdClass(); $node->title = $contentNode->title; $node->state = (int) $state; $node->access = (int) $access; $node->language = $language; $node->nested = true; $node->node = $contentNode; // Add the node to the taxonomy branch. $this->taxonomy[$branch][] = $node; } /** * Method to set the item language * * @return void * * @since 3.0 */ public function setLanguage() { if ($this->language == '') { $this->language = $this->defaultLanguage; } } /** * Helper function to serialise the data of a Result object * * @return string The serialised data * * @since 4.0.0 */ public function serialize() { return serialize($this->__serialize()); } /** * Helper function to unserialise the data for this object * * @param string $serialized Serialised data to unserialise * * @return void * * @since 4.0.0 */ public function unserialize($serialized): void { $this->__unserialize(unserialize($serialized)); } /** * Magic method used for serializing. * * @since 4.1.3 */ public function __serialize(): array { $taxonomy = []; foreach ($this->taxonomy as $branch => $nodes) { $taxonomy[$branch] = []; foreach ($nodes as $node) { if ($node->nested) { $n = clone $node; unset($n->node); $taxonomy[$branch][] = $n; } else { $taxonomy[$branch][] = $node; } } } // This order must match EXACTLY the order of the $properties in the self::__unserialize method return [ $this->access, $this->defaultLanguage, $this->description, $this->elements, $this->end_date, $this->instructions, $this->language, $this->list_price, $this->publish_end_date, $this->publish_start_date, $this->published, $this->route, $this->sale_price, $this->start_date, $this->state, $taxonomy, $this->title, $this->type_id, $this->url ]; } /** * Magic method used for unserializing. * * @since 4.1.3 */ public function __unserialize(array $serialized): void { // This order must match EXACTLY the order of the array in the self::__serialize method $properties = [ 'access', 'defaultLanguage', 'description', 'elements', 'end_date', 'instructions', 'language', 'list_price', 'publish_end_date', 'publish_start_date', 'published', 'route', 'sale_price', 'start_date', 'state', 'taxonomy', 'title', 'type_id', 'url', ]; foreach ($properties as $k => $v) { $this->$v = $serialized[$k]; } foreach ($this->taxonomy as $nodes) { foreach ($nodes as $node) { $curTaxonomy = Taxonomy::getTaxonomy($node->id); $node->state = $curTaxonomy->state; $node->access = $curTaxonomy->access; } } } }