Register requirements as objects
This neutralizes the need for a unique name per requirement as requirements are now compared based on their type and condition. It also allows to implement a solution to add simple conditional requirements. refs #8508
This commit is contained in:
parent
85e6fce867
commit
24d0999fa4
|
@ -1,7 +1,6 @@
|
|||
<?php
|
||||
|
||||
use Icinga\Web\Wizard;
|
||||
use Icinga\Module\Setup\Requirements;
|
||||
|
||||
$requirements = $form->getRequirements();
|
||||
|
||||
|
@ -10,21 +9,22 @@ $requirements = $form->getRequirements();
|
|||
<tbody>
|
||||
<?php foreach ($requirements as $requirement): ?>
|
||||
<tr>
|
||||
<td><h2><?= $requirement->title; ?></h2></td>
|
||||
<td><h2><?= $requirement->getTitle(); ?></h2></td>
|
||||
<td style="width: 50%">
|
||||
<?php if (is_array($requirement->description)): ?>
|
||||
<?php $descriptions = $requirement->getDescriptions(); ?>
|
||||
<?php if (count($descriptions) > 1): ?>
|
||||
<ul>
|
||||
<?php foreach ($requirement->description as $desc): ?>
|
||||
<?php foreach ($descriptions as $desc): ?>
|
||||
<li><?= $desc; ?></li>
|
||||
<?php endforeach ?>
|
||||
</ul>
|
||||
<?php else: ?>
|
||||
<?= $requirement->description; ?>
|
||||
<?php elseif (! empty($descriptions)): ?>
|
||||
<?= $descriptions[0]; ?>
|
||||
<?php endif ?>
|
||||
</td>
|
||||
<td class="state <?= $requirement->state === Requirements::STATE_OK ? 'fulfilled' : (
|
||||
$requirement->state === Requirements::STATE_OPTIONAL ? 'not-available' : 'missing'
|
||||
); ?>"><?= $requirement->message; ?></td>
|
||||
<td class="state <?= $requirement->getState() ? 'fulfilled' : (
|
||||
$requirement->isOptional() ? 'not-available' : 'missing'
|
||||
); ?>"><?= $requirement->getStateText(); ?></td>
|
||||
</tr>
|
||||
<?php endforeach ?>
|
||||
<tr>
|
||||
|
|
|
@ -0,0 +1,279 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Module\Setup;
|
||||
|
||||
use LogicException;
|
||||
|
||||
abstract class Requirement
|
||||
{
|
||||
/**
|
||||
* The state of this requirement
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $state;
|
||||
|
||||
/**
|
||||
* A descriptive text representing the current state of this requirement
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $stateText;
|
||||
|
||||
/**
|
||||
* The descriptions of this requirement
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $descriptions;
|
||||
|
||||
/**
|
||||
* The title of this requirement
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $title;
|
||||
|
||||
/**
|
||||
* The condition of this requirement
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
protected $condition;
|
||||
|
||||
/**
|
||||
* Whether this requirement is optional
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $optional;
|
||||
|
||||
/**
|
||||
* The alias to display the condition with in a human readable way
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $alias;
|
||||
|
||||
/**
|
||||
* Create a new requirement
|
||||
*
|
||||
* @param array $options
|
||||
*
|
||||
* @throws LogicException In case there exists no setter for an option's key
|
||||
*/
|
||||
public function __construct(array $options = array())
|
||||
{
|
||||
$this->optional = false;
|
||||
$this->descriptions = array();
|
||||
|
||||
foreach ($options as $key => $value) {
|
||||
$setMethod = 'set' . ucfirst($key);
|
||||
$addMethod = 'add' . ucfirst($key);
|
||||
if (method_exists($this, $setMethod)) {
|
||||
$this->$setMethod($value);
|
||||
} elseif (method_exists($this, $addMethod)) {
|
||||
$this->$addMethod($value);
|
||||
} else {
|
||||
throw LogicException('No setter found for option key: ' . $key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the state of this requirement
|
||||
*
|
||||
* @param bool $state
|
||||
*
|
||||
* @return Requirement
|
||||
*/
|
||||
public function setState($state)
|
||||
{
|
||||
$this->state = (bool) $state;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the state of this requirement
|
||||
*
|
||||
* Evaluates the requirement in case there is no state set yet.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getState()
|
||||
{
|
||||
if ($this->state === null) {
|
||||
$this->state = $this->evaluate();
|
||||
}
|
||||
|
||||
return $this->state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a descriptive text for this requirement's current state
|
||||
*
|
||||
* @param string $text
|
||||
*
|
||||
* @return Requirement
|
||||
*/
|
||||
public function setStateText($text)
|
||||
{
|
||||
$this->stateText = $text;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a descriptive text for this requirement's current state
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getStateText()
|
||||
{
|
||||
return $this->stateText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a description for this requirement
|
||||
*
|
||||
* @param string $description
|
||||
*
|
||||
* @return Requirement
|
||||
*/
|
||||
public function addDescription($description)
|
||||
{
|
||||
$this->descriptions[] = $description;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the descriptions of this wizard
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getDescriptions()
|
||||
{
|
||||
return $this->descriptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the title for this requirement
|
||||
*
|
||||
* @param string $title
|
||||
*
|
||||
* @return Requirement
|
||||
*/
|
||||
public function setTitle($title)
|
||||
{
|
||||
$this->title = $title;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the title of this requirement
|
||||
*
|
||||
* In case there is no title set the alias is returned instead.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTitle()
|
||||
{
|
||||
if ($this->title === null) {
|
||||
return $this->getAlias();
|
||||
}
|
||||
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the condition for this requirement
|
||||
*
|
||||
* @param mixed $condition
|
||||
*
|
||||
* @return Requirement
|
||||
*/
|
||||
public function setCondition($condition)
|
||||
{
|
||||
$this->condition = $condition;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the condition of this requirement
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getCondition()
|
||||
{
|
||||
return $this->condition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether this requirement is optional
|
||||
*
|
||||
* @param bool $state
|
||||
*
|
||||
* @return Requirement
|
||||
*/
|
||||
public function setOptional($state = true)
|
||||
{
|
||||
$this->optional = (bool) $state;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether this requirement is optional
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isOptional()
|
||||
{
|
||||
return $this->optional;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the alias to display the condition with in a human readable way
|
||||
*
|
||||
* @param string $alias
|
||||
*
|
||||
* @return Requirement
|
||||
*/
|
||||
public function setAlias($alias)
|
||||
{
|
||||
$this->alias = $alias;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the alias to display the condition with in a human readable way
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAlias()
|
||||
{
|
||||
return $this->alias;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate this requirement and return whether it is fulfilled
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
abstract protected function evaluate();
|
||||
|
||||
/**
|
||||
* Return whether the given requirement equals this one
|
||||
*
|
||||
* @param Requirement $requirement
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function equals(Requirement $requirement)
|
||||
{
|
||||
if ($requirement instanceof static) {
|
||||
return $this->getCondition() === $requirement->getCondition();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -8,27 +8,9 @@ use IteratorAggregate;
|
|||
|
||||
/**
|
||||
* Container to store and handle requirements
|
||||
*
|
||||
* TODO: Requirements should be registered as objects with a specific purpose (PhpModRequirement, PhpIniRequirement, ..)
|
||||
* so that it's not necessary to define unique identifiers which may differ between different modules.
|
||||
*/
|
||||
class Requirements implements IteratorAggregate
|
||||
{
|
||||
/**
|
||||
* Identifier representing the state OK
|
||||
*/
|
||||
const STATE_OK = 2;
|
||||
|
||||
/**
|
||||
* Identifier representing the state OPTIONAL
|
||||
*/
|
||||
const STATE_OPTIONAL = 1;
|
||||
|
||||
/**
|
||||
* Identifier representing the state MANDATORY
|
||||
*/
|
||||
const STATE_MANDATORY = 0;
|
||||
|
||||
/**
|
||||
* The registered requirements
|
||||
*
|
||||
|
@ -39,44 +21,35 @@ class Requirements implements IteratorAggregate
|
|||
/**
|
||||
* Register a requirement
|
||||
*
|
||||
* @param object $requirement The requirement to add
|
||||
* @param Requirement $requirement The requirement to add
|
||||
*
|
||||
* @return self
|
||||
* @return Requirements
|
||||
*/
|
||||
public function add($name, $requirement)
|
||||
public function add(Requirement $requirement)
|
||||
{
|
||||
$this->requirements[$name] = array_key_exists($name, $this->requirements)
|
||||
? $this->combine($this->requirements[$name], $requirement)
|
||||
: $requirement;
|
||||
$merged = false;
|
||||
foreach ($this as $knownRequirement) {
|
||||
if ($requirement->equals($knownRequirement)) {
|
||||
if ($knownRequirement->isOptional() && !$requirement->isOptional()) {
|
||||
$knownRequirement->setOptional(false);
|
||||
}
|
||||
|
||||
foreach ($requirement->getDescriptions() as $description) {
|
||||
$knownRequirement->addDescription($description);
|
||||
}
|
||||
|
||||
$merged = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (! $merged) {
|
||||
$this->requirements[] = $requirement;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Combine the two given requirements
|
||||
*
|
||||
* Returns the most important requirement with the description from the other one being added.
|
||||
*
|
||||
* @param object $oldRequirement
|
||||
* @param object $newRequirement
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
protected function combine($oldRequirement, $newRequirement)
|
||||
{
|
||||
if ($newRequirement->state === static::STATE_MANDATORY && $oldRequirement->state === static::STATE_OPTIONAL) {
|
||||
$tempRequirement = $oldRequirement;
|
||||
$oldRequirement = $newRequirement;
|
||||
$newRequirement = $tempRequirement;
|
||||
}
|
||||
|
||||
if (! is_array($oldRequirement->description)) {
|
||||
$oldRequirement->description = array($oldRequirement->description);
|
||||
}
|
||||
|
||||
$oldRequirement->description[] = $newRequirement->description;
|
||||
return $oldRequirement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all registered requirements
|
||||
*
|
||||
|
@ -97,83 +70,17 @@ class Requirements implements IteratorAggregate
|
|||
return new ArrayIterator($this->getAll());
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an optional requirement
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $title
|
||||
* @param string $description
|
||||
* @param bool $state
|
||||
* @param string $message
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function addOptional($name, $title, $description, $state, $message)
|
||||
{
|
||||
$this->add(
|
||||
$name,
|
||||
(object) array(
|
||||
'title' => $title,
|
||||
'message' => $message,
|
||||
'description' => $description,
|
||||
'state' => (bool) $state ? static::STATE_OK : static::STATE_OPTIONAL
|
||||
)
|
||||
);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a mandatory requirement
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $title
|
||||
* @param string $description
|
||||
* @param bool $state
|
||||
* @param string $message
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function addMandatory($name, $title, $description, $state, $message)
|
||||
{
|
||||
$this->add(
|
||||
$name,
|
||||
(object) array(
|
||||
'title' => $title,
|
||||
'message' => $message,
|
||||
'description' => $description,
|
||||
'state' => (bool) $state ? static::STATE_OK : static::STATE_MANDATORY
|
||||
)
|
||||
);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the given requirements
|
||||
*
|
||||
* @param Requirements $requirements The requirements to register
|
||||
*
|
||||
* @return self
|
||||
* @return Requirements
|
||||
*/
|
||||
public function merge(Requirements $requirements)
|
||||
{
|
||||
foreach ($requirements->getAll() as $name => $requirement) {
|
||||
$this->add($name, $requirement);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make all registered requirements being optional
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function allOptional()
|
||||
{
|
||||
foreach ($this->getAll() as $requirement) {
|
||||
if ($requirement->state === static::STATE_MANDATORY) {
|
||||
$requirement->state = static::STATE_OPTIONAL;
|
||||
}
|
||||
foreach ($requirements as $requirement) {
|
||||
$this->add($requirement);
|
||||
}
|
||||
|
||||
return $this;
|
||||
|
@ -186,8 +93,8 @@ class Requirements implements IteratorAggregate
|
|||
*/
|
||||
public function fulfilled()
|
||||
{
|
||||
foreach ($this->getAll() as $requirement) {
|
||||
if ($requirement->state === static::STATE_MANDATORY) {
|
||||
foreach ($this as $requirement) {
|
||||
if (! $requirement->getState() && !$requirement->isOptional()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue