455 lines
		
	
	
		
			9.5 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			455 lines
		
	
	
		
			9.5 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| 
 | |
| /**
 | |
|  * @author          Tassos Marinos <info@tassos.gr>
 | |
|  * @link            https://www.tassos.gr
 | |
|  * @copyright       Copyright © 2024 Tassos All Rights Reserved
 | |
|  * @license         GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
 | |
|  */
 | |
| 
 | |
| namespace NRFramework\Conditions;
 | |
| 
 | |
| defined('_JEXEC') or die;
 | |
| 
 | |
| use Joomla\Registry\Registry;
 | |
| use Joomla\String\StringHelper;
 | |
| use Joomla\CMS\Language\Text;
 | |
| 
 | |
| /**
 | |
|  *  Assignment Class
 | |
|  */
 | |
| class Condition
 | |
| {
 | |
| 	/**
 | |
| 	 *  Application Object
 | |
| 	 *
 | |
| 	 *  @var  object
 | |
| 	 */
 | |
| 	protected $app;
 | |
| 
 | |
| 	/**
 | |
| 	 *  Document Object
 | |
| 	 *
 | |
| 	 *  @var  object
 | |
| 	 */
 | |
| 	protected $doc;
 | |
| 
 | |
| 	/**
 | |
| 	 *  Date Object
 | |
| 	 *
 | |
| 	 *  @var  object
 | |
| 	 */
 | |
| 	protected $date;
 | |
| 
 | |
| 	/**
 | |
| 	 *  Database Object
 | |
| 	 *
 | |
| 	 *  @var  object
 | |
| 	 */
 | |
| 	protected $db;
 | |
| 
 | |
| 	/**
 | |
| 	 *  User Object
 | |
| 	 *
 | |
| 	 *  @var  object
 | |
| 	 */
 | |
| 	protected $user;
 | |
| 
 | |
| 	/**
 | |
| 	 *  Assignment Selection
 | |
| 	 *
 | |
| 	 *  @var  mixed
 | |
| 	 */
 | |
| 	protected $selection;
 | |
| 
 | |
| 	/**
 | |
| 	 *  Assignment Parameters
 | |
| 	 *
 | |
| 	 *  @var  mixed
 | |
| 	 */
 | |
| 	protected $params;
 | |
| 
 | |
| 	/**
 | |
| 	 *  Assignment State (Include|Exclude)
 | |
| 	 *
 | |
| 	 *  @var  string
 | |
| 	 */
 | |
|     public $assignment;
 | |
|     
 | |
|     /**
 | |
|      *  Options
 | |
| 	 * 
 | |
| 	 *  @var  object
 | |
|      */
 | |
|     public $options;
 | |
|     
 | |
|     /**
 | |
|      *  Framework factory object
 | |
| 	 * 
 | |
| 	 *  @var  object
 | |
|      */
 | |
|     public $factory;
 | |
| 
 | |
| 	/**
 | |
| 	 * The default operator that will be used to compare haystack with needle.
 | |
| 	 *
 | |
| 	 * @var string
 | |
| 	 */
 | |
| 	protected $operator;
 | |
| 
 | |
| 	/**
 | |
| 	 * Class constructor
 | |
| 	 *
 | |
| 	 * @param	array  $options		The rule options. Expected properties: selection, value, params
 | |
| 	 * @param   object $factory		The framework's factory class.
 | |
| 	 */
 | |
| 	public function __construct($options = null, $factory = null)
 | |
| 	{
 | |
|         $this->factory = is_null($factory) ? new \NRFramework\Factory() : $factory;
 | |
| 
 | |
| 		// Set General Joomla Objects
 | |
| 		$this->db   = $this->factory->getDbo();
 | |
| 		$this->app  = $this->factory->getApplication();
 | |
| 		$this->doc  = $this->factory->getDocument();
 | |
| 		$this->user = $this->factory->getUser();
 | |
| 
 | |
| 		$this->options = new Registry($options);
 | |
| 
 | |
| 		$this->setParams($this->options->get('params'));
 | |
| 		$this->setOperator($this->options->get('operator', 'includesSome'));
 | |
| 
 | |
| 		// For performance reasons we might move this inside the pass() method
 | |
| 		$this->setSelection($this->options->get('selection', ''));
 | |
|     }
 | |
| 
 | |
| 	/**
 | |
| 	 * Set the rule's user selected value
 | |
| 	 *
 | |
| 	 * @param	mixed	$selection
 | |
| 	 * @return 	object
 | |
| 	 */
 | |
| 	public function setSelection($selection)
 | |
| 	{
 | |
| 		$this->selection = $selection;
 | |
| 
 | |
| 		if (method_exists($this, 'prepareSelection'))
 | |
| 		{
 | |
| 			$this->selection = $this->prepareSelection();
 | |
| 		}
 | |
| 
 | |
| 		return $this;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Undocumented function
 | |
| 	 *
 | |
| 	 * @return void
 | |
| 	 */
 | |
| 	public function getSelection()
 | |
| 	{
 | |
| 		return $this->selection;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Set the operator that will be used for the comparison
 | |
| 	 *
 | |
| 	 * @param	string $operator
 | |
| 	 * @return	object
 | |
| 	 */
 | |
| 	public function setOperator($operator)
 | |
| 	{
 | |
| 		$this->operator = $operator;
 | |
| 		return $this;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Set the rule's parameters
 | |
| 	 *
 | |
| 	 * @param  array $params
 | |
| 	 */
 | |
| 	public function setParams($params)
 | |
| 	{
 | |
| 		$this->params = new Registry($params);
 | |
| 	}
 | |
| 
 | |
| 	public function getParams()
 | |
| 	{
 | |
| 		return $this->params;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Checks the validitity of two values based on the given operator.
 | |
| 	 * 
 | |
| 	 * Consider converting this method as a Trait.
 | |
| 	 * 
 | |
| 	 * @param   mixed   $value
 | |
| 	 * @param   mixed   $selection
 | |
| 	 * @param   string  $operator
 | |
| 	 * @param   array   $options 	ignoreCase: true,false
 | |
| 	 * 
 | |
| 	 * @return  bool
 | |
| 	 */
 | |
| 	public function passByOperator($value = null, $selection = null, $operator = null, $options = null)
 | |
| 	{
 | |
| 		$value = is_null($value) ? $this->value() : $value;
 | |
| 
 | |
| 		if (!is_null($selection))
 | |
| 		{
 | |
| 			$this->setSelection($selection);
 | |
| 		}
 | |
| 
 | |
| 		$selection = $this->getSelection();
 | |
| 
 | |
| 		$options = new Registry($options);
 | |
| 		$ignoreCase = $options->get('ignoreCase', true);
 | |
| 
 | |
| 		if (is_object($value))
 | |
| 		{
 | |
| 			$value = (array) $value;
 | |
| 		}
 | |
| 
 | |
| 		if (is_object($selection))
 | |
| 		{
 | |
| 			$selection = (array) $selection;
 | |
| 		}
 | |
| 
 | |
| 		if ($ignoreCase)
 | |
| 		{
 | |
| 			if (is_string($value))
 | |
| 			{
 | |
| 				$value = strtolower($value);
 | |
| 			}
 | |
| 
 | |
| 			if (is_string($selection))
 | |
| 			{
 | |
| 				$selection = strtolower($selection);
 | |
| 			}
 | |
| 
 | |
| 			if (is_array($value))
 | |
| 			{
 | |
| 				$value = array_map('strtolower', $value);
 | |
| 			}
 | |
| 
 | |
| 			if (is_array($selection))
 | |
| 			{
 | |
| 				$selection = array_map(function($str)
 | |
| 				{
 | |
| 					return is_null($str) ? '' : strtolower($str);
 | |
| 				}, $selection);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		$operator = (is_null($operator) OR empty($operator)) ? $this->operator : $operator;
 | |
| 		$pass = false;
 | |
| 
 | |
|         switch ($operator)
 | |
|         {
 | |
| 			case 'exists':
 | |
| 				$pass = !is_null($value);
 | |
| 				break;
 | |
| 
 | |
| 			// Determines whether haystack is empty. Accepts: array, string
 | |
|             case 'empty':
 | |
| 				if (is_array($value))
 | |
| 				{
 | |
| 					$pass = empty($value);
 | |
| 				}
 | |
| 
 | |
| 				if (is_string($value))
 | |
| 				{
 | |
| 					$pass = $value == '' || trim($value) == '';
 | |
| 				}
 | |
| 
 | |
| 				if (is_bool($value))
 | |
| 				{
 | |
| 					$pass = !$value;
 | |
| 				}
 | |
| 				break;
 | |
| 
 | |
| 			case 'equals':
 | |
| 				if (is_array($selection) || is_array($value))
 | |
| 				{
 | |
| 					$pass = $this->passByOperator($value, $selection, 'includesSome', $options);
 | |
| 				}
 | |
| 				else
 | |
| 				{
 | |
| 					$pass = $value == $selection;
 | |
| 				}
 | |
| 				break;
 | |
| 
 | |
| 			case 'contains':
 | |
| 				if (is_string($value) && is_string($selection))
 | |
| 				{
 | |
| 					$pass = strlen($selection) > 0 && strpos($value, $selection) !== false;
 | |
| 				}
 | |
| 
 | |
| 				break;
 | |
| 			// Determine whether haystack is less than needle.
 | |
| 			case 'less_than':
 | |
| 			case 'lowerthan':
 | |
| 			case 'lt':
 | |
| 				$pass = $value < $selection;
 | |
| 				break;
 | |
| 
 | |
| 			// Determine whether haystack is less than or equal to needle.
 | |
| 			case 'less_than_or_equal_to':
 | |
| 			case 'lowerthanequal':
 | |
| 			case 'lte':
 | |
| 				$pass = $value <= $selection;
 | |
| 				break;
 | |
| 
 | |
| 			// Determine whether haystack is greater than needle.
 | |
| 			case 'greater_than':
 | |
| 			case 'greaterthan':
 | |
| 			case 'gt':
 | |
| 				$pass = $value > $selection;
 | |
| 				break;
 | |
| 
 | |
| 			// Determine whether haystack is greater than or equal to needle.
 | |
| 			case 'greater_than_or_equal_to':
 | |
| 			case 'greterthanequal':
 | |
| 			case 'gte':
 | |
| 				$pass = $value >= $selection;
 | |
| 				break;
 | |
| 
 | |
| 			// Determine whether haystack contains all elements in needle.
 | |
| 			case 'includesAll':
 | |
| 			case 'containsall':
 | |
| 				$pass = count(array_intersect((array) $selection, (array) $value)) == count((array) $selection);
 | |
| 				break;
 | |
| 
 | |
| 			// Determine whether haystack contains at least one element from needle.
 | |
| 			case 'includesSome':
 | |
| 			case 'containsany':
 | |
| 				$pass = !empty(array_intersect((array) $value, (array) $selection));
 | |
| 				break;
 | |
| 
 | |
| 			// Determine whether haystack contains at least one element from needle. Accepts; string, array.
 | |
| 			case 'includes':
 | |
| 				if (is_string($value) && $value != '' && is_string($selection) && $selection != '')
 | |
| 				{
 | |
| 					if (StringHelper::strpos($value, $selection) !== false)
 | |
| 					{
 | |
| 						$pass = true;
 | |
| 					}
 | |
| 				}
 | |
| 
 | |
| 				if (is_array($value) || is_array($selection))
 | |
| 				{
 | |
| 					$pass = $this->passByOperator($value, $selection, 'includesSome', $options);
 | |
| 				}
 | |
| 
 | |
| 				break;
 | |
| 
 | |
| 			// Determine whether haystack starts with needle. Accepts: string
 | |
|             case 'starts_with':
 | |
|                 $pass = StringHelper::substr($value, 0, StringHelper::strlen($selection)) === $selection;
 | |
| 				break;
 | |
| 			
 | |
| 			// Determine whether haystack ends with needle. Accepts: string
 | |
|             case 'ends_with':
 | |
|                 $pass = StringHelper::substr($value, -StringHelper::strlen($selection)) === $selection;
 | |
| 				break;
 | |
| 
 | |
| 			// Determine whether value is in given range
 | |
|             case 'range':
 | |
| 				$value1 = isset($selection['value1']) ? (float) $selection['value1'] : false;
 | |
| 				$value2 = isset($selection['value2']) ? (float) $selection['value2'] : false;
 | |
| 
 | |
|                 $pass = $value1 && $value2 ? (($value >= $value1) && ($value <= $value2)) : false;
 | |
| 				break;
 | |
| 			
 | |
| 			// Determine whether haystack equals to needle. Accepts any object.
 | |
| 			default:
 | |
| 				$pass = $value == $selection;
 | |
|         }
 | |
| 
 | |
| 		return $pass;
 | |
| 	}
 | |
| 
 | |
|     /**
 | |
|      *  Base assignment check
 | |
|      * 
 | |
|      *  @return bool
 | |
|      */
 | |
| 	public function pass()
 | |
| 	{	
 | |
| 		return $this->passByOperator();
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 *  Returns all parent rows
 | |
| 	 * 
 | |
| 	 *  This method doesn't belong here. Move it to Functions.php.
 | |
| 	 *
 | |
| 	 *  @param   integer  $id      Row primary key
 | |
| 	 *  @param   string   $table   Table name
 | |
| 	 *  @param   string   $parent  Parent column name
 | |
| 	 *  @param   string   $child   Child column name
 | |
| 	 *
 | |
| 	 *  @return  array             Array with IDs
 | |
| 	 */
 | |
| 	public function getParentIds($id = 0, $table = 'menu', $parent = 'parent_id', $child = 'id')
 | |
| 	{
 | |
| 		if (!$id)
 | |
| 		{
 | |
| 			return [];
 | |
| 		}
 | |
| 
 | |
| 		$cache = $this->factory->getCache(); 
 | |
| 		$hash  = md5('getParentIds_' . $id . '_' . $table . '_' . $parent . '_' . $child);
 | |
| 
 | |
| 		if ($cache->has($hash))
 | |
| 		{
 | |
| 			return $cache->get($hash);
 | |
| 		}
 | |
| 
 | |
| 		$parent_ids = array();
 | |
| 
 | |
| 		while ($id)
 | |
| 		{
 | |
| 			$query = $this->db->getQuery(true)
 | |
| 				->select('t.' . $parent)
 | |
| 				->from('#__' . $table . ' as t')
 | |
| 				->where('t.' . $child . ' = ' . (int) $id);
 | |
| 			$this->db->setQuery($query);
 | |
| 			$id = $this->db->loadResult();
 | |
| 
 | |
| 			// Break if no parent is found or parent already found before for some reason
 | |
| 			if (!$id || in_array($id, $parent_ids))
 | |
| 			{
 | |
| 				break;
 | |
| 			}
 | |
| 
 | |
| 			$parent_ids[] = $id;
 | |
| 		}
 | |
| 
 | |
| 		return $cache->set($hash, $parent_ids);
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * A one-line text that describes the current value detected by the rule. Eg: The current time is %s.
 | |
| 	 *
 | |
| 	 * @return string
 | |
| 	 */
 | |
| 	public function getValueHint()
 | |
| 	{
 | |
| 		$value = $this->value();
 | |
| 
 | |
| 		// If the rule returns an array, use the 1st one.
 | |
| 		$value = is_array($value) ? $value[0] : $value;
 | |
| 
 | |
| 		return Text::sprintf('NR_DISPLAY_CONDITIONS_HINT_' . strtoupper($this->getName()), ucfirst(strtolower($value)));
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Return the rule name
 | |
| 	 *
 | |
| 	 * @return string
 | |
| 	 */
 | |
| 	protected function getName()
 | |
| 	{
 | |
| 		$classParts = explode('\\', get_called_class());
 | |
| 		return array_pop($classParts);
 | |
| 	}
 | |
| } |