<form method="{@$form->getMethod()}" action="{@$form->getAction()}" id="{@$form->getId()}"{if !$form->getClasses()|empty} class="{implode from=$form->getClasses() item='class'}{$class}{/implode}"{/if}{foreach from=$form->getAttributes() key='attributeName' item='attributeValue'} {$attributeName}="{$attributeValue}"{/foreach}>
{foreach from=$form item='child'}
- {@$child->getHtml()}
+ {if $child->isAvailable()}
+ {@$child->getHtml()}
+ {/if}
{/foreach}
<div class="formSubmit">
{foreach from=$container item='child'}
- {@$child->getHtml()}
+ {if $child->isAvailable()}
+ {@$child->getHtml()}
+ {/if}
{/foreach}
\ No newline at end of file
<nav class="tabMenu">
<ul>
{foreach from=$container item='child'}
- {assign var='__tabMenuFormContainerChildId' value=$child->getPrefixedId()|concat:'Container'}
- <li{if !$child->checkDependencies()} style="display: none;"{/if}><a href="{@$__wcf->getAnchor($__tabMenuFormContainerChildId)}">{@$child->getLabel()}</a></li>
+ {if $child->isAvailable()}
+ {assign var='__tabMenuFormContainerChildId' value=$child->getPrefixedId()|concat:'Container'}
+ <li{if !$child->checkDependencies()} style="display: none;"{/if}><a href="{@$__wcf->getAnchor($__tabMenuFormContainerChildId)}">{@$child->getLabel()}</a></li>
+ {/if}
{/foreach}
</ul>
</nav>
<nav class="menu">
<ul>
{foreach from=$container item='child'}
- <li><a href="{@$__wcf->getAnchor($child->getPrefixedId())}">{@$container->getLabel()}</a></li>
+ {if $child->isAvailable()}
+ {assign var='__tabMenuFormContainerChildId' value=$child->getPrefixedId()|concat:'Container'}
+ <li{if !$child->checkDependencies()} style="display: none;"{/if}><a href="{@$__wcf->getAnchor($__tabMenuFormContainerChildId)}">{@$child->getLabel()}</a></li>
+ {/if}
{/foreach}
</ul>
</nav>
public function loadValuesFromObject(IStorableObject $object) {
/** @var IFormNode $node */
foreach ($this->getIterator() as $node) {
- if ($node instanceof IFormField) {
+ if ($node instanceof IFormField && $node->isAvailable()) {
$node->loadValueFromObject($object);
}
}
*/
public function attribute($name, $value = null);
+ /**
+ * Sets if this node is available and returns this node.
+ *
+ * By default, every node is available. This methods makes it easier to create forms
+ * that contains node that are only avaiable if certain options have specific values
+ * or the active user has specific permissions, for example. Furthermore, fields
+ * themselves are also able to mark themselves as unavailable, for example, a selection
+ * field without any options. A `IFormContainer` is automatically unavailable if it
+ * contains no available children.
+ *
+ * Unavailable fields produce no output, their value is not read, they are not validated
+ * and they are not checked for save values.
+ *
+ * Note: Form field dependencies manage dynamic availability of form nodes based on
+ * form field values while this method manages static availability that is independent
+ * of form field values and only depends on external factors.
+ *
+ * @param bool $available determines if node is available
+ * @return static this node
+ *
+ * @throws \InvalidArgumentException if the given value is no bool
+ */
+ public function available($available = true);
+
/**
* Returns `true` if the node's dependencies are met and returns `false` otherwise.
*
*/
public function id($id);
+ /**
+ * Returns `true` if this node is available and returns `false` otherwise.
+ *
+ * If the node's availability has not been explicitly set, `true` is returned.
+ *
+ * @return bool
+ *
+ * @see IFormNode::available()
+ */
+ public function isAvailable();
+
/**
* Is called once after all nodes have been added to the document this node belongs to.
*
*/
protected $__attributes = [];
+ /**
+ * `true` if this node is available and `false` otherwise
+ * @var bool
+ */
+ protected $__available = true;
+
/**
* CSS classes of this node
* @var string[]
return $this;
}
+ /**
+ * Sets if this node is available and returns this node.
+ *
+ * By default, every node is available. This methods makes it easier to create forms
+ * that contains node that are only avaiable if certain options have specific values
+ * or the active user has specific permissions, for example. Furthermore, fields
+ * themselves are also able to mark themselves as unavailable, for example, a selection
+ * field without any options. A `IFormContainer` is automatically unavailable if it
+ * contains no available children.
+ *
+ * Unavailable fields produce no output, their value is not read, they are not validated
+ * and they are not checked for save values.
+ *
+ * Note: Form field dependencies manage dynamic availability of form nodes based on
+ * form field values while this method manages static availability that is independent
+ * of form field values and only depends on external factors.
+ *
+ * @param bool $available determines if node is available
+ * @return static this node
+ *
+ * @throws \InvalidArgumentException if the given value is no bool
+ */
+ public function available($available = true) {
+ if (!is_bool($available)) {
+ throw new \InvalidArgumentException("Given value is no bool, " . gettype($available) . " given.");
+ }
+
+ $this->__available = $available;
+
+ return $this;
+ }
+
/**
* Returns `true` if the node's dependencies are met and returns `false` otherwise.
*
return $this;
}
+ /**
+ * Returns `true` if this node is available and returns `false` otherwise.
+ *
+ * If the node's own availability has not been explicitly set, it is assumed to be `true`.
+ *
+ * @return bool
+ *
+ * @see IFormNode::available()
+ */
+ public function isAvailable() {
+ if ($this->__available && $this instanceof IFormParentNode) {
+ /** @var IFormChildNode $child */
+ foreach ($this as $child) {
+ if ($child->isAvailable()) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ return $this->__available;
+ }
+
/**
* Is called once after all nodes have been added to the document this node belongs to.
*
* @return static this node
*/
public function readValues() {
- foreach ($this->children() as $child) {
- if ($child instanceof IFormParentNode) {
- $child->readValues();
- }
- else if ($child instanceof IFormField && !$child->isImmutable()) {
- $child->readValue();
+ if ($this->isAvailable()) {
+ foreach ($this->children() as $child) {
+ if ($child instanceof IFormParentNode) {
+ $child->readValues();
+ }
+ else if ($child instanceof IFormField && $child->isAvailable() && !$child->isImmutable()) {
+ $child->readValue();
+ }
}
}
* nodes are valid. A `IFormField` object is valid if its value is valid.
*/
public function validate() {
- if ($this->checkDependencies()) {
+ if ($this->isAvailable() && $this->checkDependencies()) {
foreach ($this->children() as $child) {
// call `checkDependencies()` on form fields here so that their validate
// method does not have to do it
- if ($child instanceof IFormField && !$child->checkDependencies()) {
+ if ($child instanceof IFormField && $child->isAvailable() && !$child->checkDependencies()) {
continue;
}
return $this->__options;
}
+ /**
+ * Returns `true` if this node is available and returns `false` otherwise.
+ *
+ * If the node's availability has not been explicitly set, `true` is returned.
+ *
+ * @return bool
+ *
+ * @see IFormNode::available()
+ */
+ public function isAvailable() {
+ // selections without any possible values are not available
+ return !empty($this->possibleValues) && parent::isAvailable();
+ }
+
/**
* Sets the possible options of this selection and returns this field.
*
$this->getData($childNode, $data);
}
}
- else if ($node instanceof IFormField && $node->hasSaveValue()) {
+ else if ($node instanceof IFormField && $node->isAvailable() && $node->hasSaveValue()) {
$data[$node->getId()] = $node->getSaveValue();
}
}