mirror of
				https://github.com/Icinga/icingaweb2.git
				synced 2025-10-31 03:14:31 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			334 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			334 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| /* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
 | |
| 
 | |
| namespace Icinga\Module\Setup;
 | |
| 
 | |
| use LogicException;
 | |
| use RecursiveIterator;
 | |
| 
 | |
| /**
 | |
|  * Container to store and handle requirements
 | |
|  */
 | |
| class RequirementSet implements RecursiveIterator
 | |
| {
 | |
|     /**
 | |
|      * Mode AND (all requirements must be met)
 | |
|      */
 | |
|     const MODE_AND = 0;
 | |
| 
 | |
|     /**
 | |
|      * Mode OR (at least one requirement must be met)
 | |
|      */
 | |
|     const MODE_OR = 1;
 | |
| 
 | |
|     /**
 | |
|      * Whether all requirements meet their condition
 | |
|      *
 | |
|      * @var bool
 | |
|      */
 | |
|     protected $state;
 | |
| 
 | |
|     /**
 | |
|      * Whether this set is optional
 | |
|      *
 | |
|      * @var bool
 | |
|      */
 | |
|     protected $optional;
 | |
| 
 | |
|     /**
 | |
|      * The mode by which the requirements are evaluated
 | |
|      *
 | |
|      * @var string
 | |
|      */
 | |
|     protected $mode;
 | |
| 
 | |
|     /**
 | |
|      * The registered requirements
 | |
|      *
 | |
|      * @var array
 | |
|      */
 | |
|     protected $requirements;
 | |
| 
 | |
|     /**
 | |
|      * The raw state of this set's requirements
 | |
|      *
 | |
|      * @var bool
 | |
|      */
 | |
|     private $forcedState;
 | |
| 
 | |
|     /**
 | |
|      * Initialize a new set of requirements
 | |
|      *
 | |
|      * @param   bool    $optional   Whether this set is optional
 | |
|      * @param   int     $mode       The mode by which to evaluate this set
 | |
|      */
 | |
|     public function __construct($optional = false, $mode = null)
 | |
|     {
 | |
|         $this->optional = $optional;
 | |
|         $this->requirements = array();
 | |
|         $this->setMode($mode ?: static::MODE_AND);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Set the state of this set
 | |
|      *
 | |
|      * @param   bool    $state
 | |
|      *
 | |
|      * @return  RequirementSet
 | |
|      */
 | |
|     public function setState($state)
 | |
|     {
 | |
|         $this->state = (bool) $state;
 | |
|         return $this;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Return the state of this set
 | |
|      *
 | |
|      * Alias for RequirementSet::fulfilled(true).
 | |
|      *
 | |
|      * @return  bool
 | |
|      */
 | |
|     public function getState()
 | |
|     {
 | |
|         return $this->fulfilled(true);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Set whether this set of requirements should be optional
 | |
|      *
 | |
|      * @param   bool    $state
 | |
|      *
 | |
|      * @return  RequirementSet
 | |
|      */
 | |
|     public function setOptional($state = true)
 | |
|     {
 | |
|         $this->optional = (bool) $state;
 | |
|         return $this;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Return whether this set of requirements is optional
 | |
|      *
 | |
|      * @return  bool
 | |
|      */
 | |
|     public function isOptional()
 | |
|     {
 | |
|         return $this->optional;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Set the mode by which to evaluate the requirements
 | |
|      *
 | |
|      * @param   int     $mode
 | |
|      *
 | |
|      * @return  RequirementSet
 | |
|      *
 | |
|      * @throws  LogicException      In case the given mode is invalid
 | |
|      */
 | |
|     public function setMode($mode)
 | |
|     {
 | |
|         if ($mode !== static::MODE_AND && $mode !== static::MODE_OR) {
 | |
|             throw new LogicException(sprintf('Invalid mode %u given.'), $mode);
 | |
|         }
 | |
| 
 | |
|         $this->mode = $mode;
 | |
|         return $this;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Return the mode by which the requirements are evaluated
 | |
|      *
 | |
|      * @return  int
 | |
|      */
 | |
|     public function getMode()
 | |
|     {
 | |
|         return $this->mode;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Register a requirement
 | |
|      *
 | |
|      * @param   Requirement     $requirement    The requirement to add
 | |
|      *
 | |
|      * @return  RequirementSet
 | |
|      */
 | |
|     public function add(Requirement $requirement)
 | |
|     {
 | |
|         $merged = false;
 | |
|         foreach ($this->requirements as $knownRequirement) {
 | |
|             if ($knownRequirement instanceof Requirement && $requirement->equals($knownRequirement)) {
 | |
|                 $knownRequirement->setOptional($requirement->isOptional());
 | |
|                 foreach ($requirement->getDescriptions() as $description) {
 | |
|                     $knownRequirement->addDescription($description);
 | |
|                 }
 | |
| 
 | |
|                 $merged = true;
 | |
|                 break;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         if (! $merged) {
 | |
|             $this->requirements[] = $requirement;
 | |
|         }
 | |
| 
 | |
|         return $this;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Return all registered requirements
 | |
|      *
 | |
|      * @return  array
 | |
|      */
 | |
|     public function getAll()
 | |
|     {
 | |
|         return $this->requirements;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Register the given set of requirements
 | |
|      *
 | |
|      * @param   RequirementSet  $set    The set to register
 | |
|      *
 | |
|      * @return  RequirementSet
 | |
|      */
 | |
|     public function merge(RequirementSet $set)
 | |
|     {
 | |
|         if ($this->getMode() === $set->getMode() && $this->isOptional() === $set->isOptional()) {
 | |
|             foreach ($set->getAll() as $requirement) {
 | |
|                 if ($requirement instanceof static) {
 | |
|                     $this->merge($requirement);
 | |
|                 } else {
 | |
|                     $this->add($requirement);
 | |
|                 }
 | |
|             }
 | |
|         } else {
 | |
|             $this->requirements[] = $set;
 | |
|         }
 | |
| 
 | |
|         return $this;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Return whether all requirements can successfully be evaluated based on the current mode
 | |
|      *
 | |
|      * In case this is a optional set of requirements (and $force is false), true is returned immediately.
 | |
|      *
 | |
|      * @param   bool    $force      Whether to ignore the optionality of a set or single requirement
 | |
|      *
 | |
|      * @return  bool
 | |
|      */
 | |
|     public function fulfilled($force = false)
 | |
|     {
 | |
|         $state = $this->isOptional();
 | |
|         if (! $force && $state) {
 | |
|             return true;
 | |
|         }
 | |
| 
 | |
|         if (! $force && $this->state !== null) {
 | |
|             return $this->state;
 | |
|         } elseif ($force && $this->forcedState !== null) {
 | |
|             return $this->forcedState;
 | |
|         }
 | |
| 
 | |
|         $self = $this->requirements;
 | |
|         foreach ($self as $requirement) {
 | |
|             if ($requirement->getState()) {
 | |
|                 $state = true;
 | |
|                 if ($this->getMode() === static::MODE_OR) {
 | |
|                     break;
 | |
|                 }
 | |
|             } elseif ($force || !$requirement->isOptional()) {
 | |
|                 $state = false;
 | |
|                 if ($this->getMode() === static::MODE_AND) {
 | |
|                     break;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         if ($force) {
 | |
|             return $this->forcedState = $state;
 | |
|         }
 | |
| 
 | |
|         return $this->state = $state;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Return whether the current element represents a nested set of requirements
 | |
|      *
 | |
|      * @return  bool
 | |
|      */
 | |
|     public function hasChildren()
 | |
|     {
 | |
|         $current = $this->current();
 | |
|         return $current instanceof static;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Return a iterator for the current nested set of requirements
 | |
|      *
 | |
|      * @return  RecursiveIterator
 | |
|      */
 | |
|     public function getChildren()
 | |
|     {
 | |
|         return $this->current();
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Rewind the iterator to its first element
 | |
|      */
 | |
|     public function rewind()
 | |
|     {
 | |
|         reset($this->requirements);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Return whether the current iterator position is valid
 | |
|      *
 | |
|      * @return  bool
 | |
|      */
 | |
|     public function valid()
 | |
|     {
 | |
|         return $this->key() !== null;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Return the current element in the iteration
 | |
|      *
 | |
|      * @return  Requirement|RequirementSet
 | |
|      */
 | |
|     public function current()
 | |
|     {
 | |
|         return current($this->requirements);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Return the position of the current element in the iteration
 | |
|      *
 | |
|      * @return  int
 | |
|      */
 | |
|     public function key()
 | |
|     {
 | |
|         return key($this->requirements);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Advance the iterator to the next element
 | |
|      */
 | |
|     public function next()
 | |
|     {
 | |
|         next($this->requirements);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Return this set of requirements rendered as HTML
 | |
|      *
 | |
|      * @return  string
 | |
|      */
 | |
|     public function __toString()
 | |
|     {
 | |
|         $renderer = new RequirementsRenderer($this);
 | |
|         return (string) $renderer;
 | |
|     }
 | |
| }
 |