From bb27332aa143247edc197557f1f5a6751f2628ca Mon Sep 17 00:00:00 2001 From: Christian Leucht Date: Tue, 19 Sep 2023 08:14:34 +0200 Subject: [PATCH] Element::parent // introduce new methods Element::withParent() and Element::parent() to keep track of the parent CollectionElement/Form and track "submission"-state on all Elements. Element::attributesForView // introduced new method which prepares the "id" and "name" for rendering to take the Element parents into account. Form, CollectionElement, Element // reduced amount of methods which are overwritten and ensure that with*() methods are not callable after submission. --- src/Element/ChoiceElement.php | 7 +- src/Element/CollectionElement.php | 53 +++---- src/Element/Element.php | 149 ++++++++++++------ src/Element/ElementInterface.php | 33 +++- src/Element/Form.php | 62 ++------ src/Element/FormInterface.php | 13 +- src/ElementFactory.php | 5 +- src/View/Button.php | 2 +- src/View/Checkbox.php | 8 +- src/View/Collection.php | 6 +- src/View/Form.php | 2 +- src/View/Input.php | 2 +- src/View/Label.php | 11 +- src/View/Progress.php | 2 +- src/View/Radio.php | 2 +- src/View/Select.php | 2 +- src/View/Textarea.php | 2 +- .../Unit/Element/CollectionElementTest.php | 24 +++ tests/phpunit/Unit/Element/ElementTest.php | 50 +++++- tests/phpunit/Unit/Element/FormTest.php | 10 ++ tests/phpunit/Unit/View/CollectionTest.php | 18 ++- tests/phpunit/Unit/View/FormTest.php | 4 +- 22 files changed, 297 insertions(+), 170 deletions(-) diff --git a/src/Element/ChoiceElement.php b/src/Element/ChoiceElement.php index 4e9af0e..d046c15 100644 --- a/src/Element/ChoiceElement.php +++ b/src/Element/ChoiceElement.php @@ -15,19 +15,18 @@ class ChoiceElement extends Element implements ChoiceElementInterface protected ?ChoiceListInterface $list = null; /** - * @param ChoiceListInterface $list - * - * @return static + * {@inheritDoc} */ public function withChoices(ChoiceListInterface $list): static { + $this->assertNotSubmitted(__METHOD__); $this->list = $list; return $this; } /** - * @return ChoiceListInterface + * {@inheritDoc} */ public function choices(): ChoiceListInterface { diff --git a/src/Element/CollectionElement.php b/src/Element/CollectionElement.php index 2418618..47b73ec 100644 --- a/src/Element/CollectionElement.php +++ b/src/Element/CollectionElement.php @@ -31,16 +31,17 @@ class CollectionElement extends Element implements CollectionElementInterface private array $allErrors = []; /** - * @param ElementInterface[] $elements - * - * @return static + * {@inheritDoc} */ public function withElement(ElementInterface ...$elements): static { + $this->assertNotSubmitted(__METHOD__); + array_walk( $elements, function (ElementInterface $element): void { $this->elements[$element->name()] = $element; + $element->withParent($this); } ); @@ -48,11 +49,7 @@ function (ElementInterface $element): void { } /** - * @param string $name - * - * @return ElementInterface - * @throws ElementNotFoundException - * + * {@inheritDoc} */ public function element(string $name): ElementInterface { @@ -66,9 +63,7 @@ public function element(string $name): ElementInterface } /** - * @param string $name - * - * @return bool + * {@inheritDoc} */ public function elementExists(string $name): bool { @@ -78,18 +73,24 @@ public function elementExists(string $name): bool /** * If the key is "value" and the $value an array, we assign all values to the children. * - * @param string $key - * @param bool|int|string $value - * - * @return static + * {@inheritDoc} */ public function withAttribute(string $key, $value): static { + $this->assertNotSubmitted(__METHOD__); + if ($key === 'value' && is_array($value)) { - foreach ($this->elements as $name => $element) { - $this->elements[$name]->withValue($value[$name] ?? ''); + $assignedValues = []; + foreach ($value as $elementName => $elementValue) { + if (!$this->elementExists($elementName)) { + continue; + } + $this->element($elementName)->withValue($elementValue); + $assignedValues[$elementName] = $elementValue; } + $this->attributes['value'] = $assignedValues; + return $this; } @@ -101,9 +102,7 @@ public function withAttribute(string $key, $value): static /** * Returns a list of values for each element inside the collection. * - * @param string $key - * - * @return array + * {@inheritDoc} */ public function attribute(string $key) { @@ -118,7 +117,7 @@ public function attribute(string $key) } /** - * @return array + * {@inheritDoc} */ public function elements(): array { @@ -128,16 +127,13 @@ public function elements(): array /** * Delegate errors down to the children. * - * @param array $errors - * - * @return static + * {@inheritDoc} */ public function withErrors(array $errors = []): static { $this->allErrors = $errors; - foreach ($this->elements as $element) { - $name = $element->name(); + foreach ($this->elements as $name => $element) { if (isset($errors[$name]) && $element instanceof ErrorAwareInterface) { $element->withErrors((array) $errors[$name]); unset($errors[$name]); @@ -151,7 +147,7 @@ public function withErrors(array $errors = []): static } /** - * @return bool + * {@inheritDoc} */ public function hasErrors(): bool { @@ -167,6 +163,9 @@ public function hasErrors(): bool return false; } + /** + * {@inheritDoc} + */ public function validate(): bool { $isValid = parent::validate(); diff --git a/src/Element/Element.php b/src/Element/Element.php index af039ce..94cb885 100644 --- a/src/Element/Element.php +++ b/src/Element/Element.php @@ -2,6 +2,8 @@ namespace ChriCo\Fields\Element; +use ChriCo\Fields\Exception\LogicException; + /** * Class Element * @@ -31,6 +33,8 @@ class Element implements */ protected $filter = null; + protected ?CollectionElement $parent = null; + /** * @param string $name */ @@ -41,52 +45,57 @@ public function __construct(string $name) } /** - * @param string $key - * @param bool|int|string $value - * - * @return static + * {@inheritDoc} */ public function withAttribute(string $key, $value): static { + $this->assertNotSubmitted(__METHOD__); $this->attributes[$key] = $value; return $this; } /** - * @return string + * {@inheritDoc} */ - public function id(): string + public function attribute(string $key) { - return (string) $this->attribute('id'); + return $this->attributes()[$key] ?? ''; } /** - * @param string $key + * An Element itself can be disabled but also can be disabled through the parent. * - * @return bool|int|mixed|string + * {@inheritDoc} */ - public function attribute(string $key) + public function isDisabled(): bool { - if (!isset($this->attributes[$key])) { - return ''; - } + $disabled = $this->parent()?->isDisabled() ?? $this->attribute('disabled'); - return $this->attributes[$key]; + return is_bool($disabled) && $disabled; } /** - * @return bool + * The Element itself cannot be submitted. It is always submitted through + * the parent which is Form::isSubmitted(). + * + * {@inheritDoc} */ - public function isDisabled(): bool + public function isSubmitted(): bool { - $disabled = $this->attribute('disabled'); + return $this->parent()?->isSubmitted() ?? false; + } - return is_bool($disabled) && $disabled; + /** + * {@inheritDoc} + */ + public function id(): string + { + return (string) $this->attribute('id'); } /** - * @return string + * {@inheritDoc} */ public function name(): string { @@ -94,7 +103,7 @@ public function name(): string } /** - * @return string + * {@inheritDoc} */ public function type(): string { @@ -102,7 +111,7 @@ public function type(): string } /** - * @return bool|int|mixed|string + * {@inheritDoc} */ public function value() { @@ -112,19 +121,18 @@ public function value() } /** - * @param string $value - * - * @return static + * {@inheritDoc} */ public function withValue($value): static { + $this->assertNotSubmitted(__METHOD__); $this->withAttribute('value', $value); return $this; } /** - * @return array + * {@inheritDoc} */ public function attributes(): array { @@ -132,12 +140,29 @@ public function attributes(): array } /** - * @param array $attributes - * - * @return static + * {@inheritDoc} + */ + public function attributesForView(): array + { + $attributes = $this->attributes; + if ($this->parent() !== null) { + $parentAttributes = $this->parent()->attributesForView(); + $id = $parentAttributes['id']; + $name = $parentAttributes['name']; + + $attributes['id'] = $id . '_' . $attributes['id']; + $attributes['name'] = $name . '[' . $attributes['name'] . ']'; + } + + return $attributes; + } + + /** + * {@inheritDoc} */ public function withAttributes(array $attributes = []): static { + $this->assertNotSubmitted(__METHOD__); foreach ($attributes as $key => $value) { $this->withAttribute($key, $value); } @@ -146,7 +171,7 @@ public function withAttributes(array $attributes = []): static } /** - * @return array + * {@inheritDoc} */ public function options(): array { @@ -154,13 +179,12 @@ public function options(): array } /** - * @param array $options - * - * @return static + * {@inheritDoc} */ public function withOptions(array $options = []): static { - foreach($options as $key => $value){ + $this->assertNotSubmitted(__METHOD__); + foreach ($options as $key => $value) { $this->withOption($key, $value); } @@ -168,22 +192,18 @@ public function withOptions(array $options = []): static } /** - * @param string $key - * @param int|string $value - * - * @return static + * {@inheritDoc} */ public function withOption(string $key, $value): static { + $this->assertNotSubmitted(__METHOD__); $this->options[$key] = $value; return $this; } /** - * @param string $key - * - * @return int|mixed|string + * {@inheritDoc} */ public function option(string $key) { @@ -195,17 +215,19 @@ public function option(string $key) } /** - * @param callable $callable - * - * @return static + * {@inheritDoc} */ public function withFilter(callable $callable): static { + $this->assertNotSubmitted(__METHOD__); $this->filter = $callable; return $this; } + /** + * {@inheritDoc} + */ public function filter($value) { if ($this->filter) { @@ -216,17 +238,19 @@ public function filter($value) } /** - * @param callable $callable - * - * @return static + * {@inheritDoc} */ public function withValidator(callable $callable): static { + $this->assertNotSubmitted(__METHOD__); $this->validator = $callable; return $this; } + /** + * {@inheritDoc} + */ public function validate(): bool { $value = $this->value(); @@ -242,4 +266,37 @@ public function validate(): bool return $valid; } + + /** + * {@inheritDoc} + */ + public function withParent(CollectionElement $element): static + { + $this->parent = $element; + + return $this; + } + + /** + * {@inheritDoc} + */ + public function parent(): ?CollectionElement + { + return $this->parent; + } + + /** + * Internal helper function for with*()-methods to ensure + * that data is only set when the Element (and parent) is not yet submitted. + * + * @param string $caller + * + * @return void + */ + protected function assertNotSubmitted(string $caller): void + { + if ($this->isSubmitted()) { + throw new LogicException(sprintf('You cannot call %s after submission.', $caller)); + } + } } diff --git a/src/Element/ElementInterface.php b/src/Element/ElementInterface.php index 88d43d4..505e339 100644 --- a/src/Element/ElementInterface.php +++ b/src/Element/ElementInterface.php @@ -16,6 +16,13 @@ interface ElementInterface */ public function isDisabled(): bool; + /** + * In case the element itself (or parent) is submitted. + * + * @return bool + */ + public function isSubmitted(): bool; + /** * Proxy to get the "id" in field attributes. * @@ -40,7 +47,7 @@ public function name(): string; /** * Proxy to get the value in field attributes. * - * @return mixed + * @return bool|int|mixed|string|array */ public function value(); @@ -51,6 +58,15 @@ public function value(); */ public function withValue($value); + /** + * Returns attributes prepared for the View with taking + * the parent into consideration for building correct + * "id" and "name" attributes. + * + * @return array + */ + public function attributesForView(): array; + /** * Get all field attributes for this element. * @@ -72,7 +88,7 @@ public function withAttribute(string $key, $value); /** * @param string $key * - * @return int|string|bool $value + * @return bool|int|mixed|string|array $value */ public function attribute(string $key); @@ -124,4 +140,17 @@ public function validate(): bool; * @param callable $callable */ public function withValidator(callable $callable); + + /** + * Setting a parent which can be either a Collection or Form itself + * to reuse internally to detect if the Element is disabled or submitted. + * + * @param CollectionElement $element + */ + public function withParent(CollectionElement $element); + + /** + * @return CollectionElement|null + */ + public function parent(): ?CollectionElement; } diff --git a/src/Element/Form.php b/src/Element/Form.php index 6e3004e..6b60b02 100644 --- a/src/Element/Form.php +++ b/src/Element/Form.php @@ -21,63 +21,23 @@ class Form extends CollectionElement implements FormInterface protected bool $isSubmitted = false; /** - * Contains the raw data assigned by Form::bind_data + * Contains the raw data assigned by Form::submit() */ protected array $rawData = []; /** - * Contains the filtered data. - */ - protected array $data = []; - - /** - * @param string $key - * @param string|array $value - * - * @return static - * @throws LogicException - * - */ - public function withAttribute(string $key, $value): static - { - if ($key === 'value' && is_array($value)) { - $this->withData($value); - } - - parent::withAttribute($key, $value); - - return $this; - } - - /** - * @param array $data - * - * @return static - * @throws LogicException - * + * {@inheritDoc} */ public function withData(array $data = []): static { - if ($this->isSubmitted) { - throw new LogicException('You cannot change data of a submitted form.'); - } - - foreach ($data as $name => $value) { - if (!$this->elementExists($name)) { - continue; - } - $element = $this->element($name); - $element->withValue($value); - $this->data[$name] = $element->value(); - } + $this->assertNotSubmitted(__METHOD__); + $this->withAttribute('value', $data); return $this; } /** - * @param array $inputData - * - * @throws ElementNotFoundException + * {@inheritDoc} */ public function submit(array $inputData = []) { @@ -94,8 +54,6 @@ public function submit(array $inputData = []) $this->rawData[$name] = $value; $element->withValue($value); - $this->data[$name] = $element->value(); - if (!$element->validate()) { $this->isValid = false; } @@ -103,17 +61,15 @@ public function submit(array $inputData = []) } /** - * @return array + * {@inheritDoc} */ public function data(): array { - return $this->data; + return $this->value(); } /** - * @return bool - * @throws LogicException - * + * {@inheritDoc} */ public function isValid(): bool { @@ -133,7 +89,7 @@ public function isValid(): bool } /** - * @return bool + * {@inheritDoc} */ public function isSubmitted(): bool { diff --git a/src/Element/FormInterface.php b/src/Element/FormInterface.php index b5cb55c..415c2a5 100644 --- a/src/Element/FormInterface.php +++ b/src/Element/FormInterface.php @@ -9,7 +9,6 @@ */ interface FormInterface { - /** * Submits data to the form, filter and validates it. * @@ -18,14 +17,12 @@ interface FormInterface public function submit(array $inputData = []); /** - * @return bool - */ - public function isSubmitted(): bool; - - /** - * Set data without re-validating and filtering it. + * Pre-assign data (values) to all Elements when the Form is not submitted. + * This method is a shorthand to Form::withValue($data) or Form::withAttribute('value', $data); * * @param array $data + * + * @deprecated ElementInterface::setValue() */ public function withData(array $data = []); @@ -33,6 +30,8 @@ public function withData(array $data = []); * Returns the assigned data. * * @return array + * + * @deprecated ElementInterface::value() */ public function data(): array; diff --git a/src/ElementFactory.php b/src/ElementFactory.php index 3974b9b..6820478 100644 --- a/src/ElementFactory.php +++ b/src/ElementFactory.php @@ -231,7 +231,10 @@ protected static function configureDescription( */ protected static function configureElement(Element\ElementInterface $element, array $specs = []) { - $element->withAttributes($specs['attributes']); + $attributes = $specs['attributes']; + // Don't set name again. + unset($attributes['name']); + $element->withAttributes($attributes); if (!empty($specs['options'])) { $element->withOptions($specs['options']); diff --git a/src/View/Button.php b/src/View/Button.php index bc682ef..c85e2dd 100644 --- a/src/View/Button.php +++ b/src/View/Button.php @@ -25,7 +25,7 @@ public function render(ElementInterface $element): string // Every button should have a label (text). $this->assertElementIsInstanceOf($element, LabelAwareInterface::class); - $attributes = $element->attributes(); + $attributes = $element->attributesForView(); $attributes = $this->buildCssClasses($attributes, 'element', $element); return sprintf( diff --git a/src/View/Checkbox.php b/src/View/Checkbox.php index dd0c620..276af6b 100644 --- a/src/View/Checkbox.php +++ b/src/View/Checkbox.php @@ -28,7 +28,7 @@ public function render(ElementInterface $element): string $this->assertElementIsInstanceOf($element, ChoiceElementInterface::class); $list = $element->choices(); - $attributes = $element->attributes(); + $attributes = $element->attributesForView(); $choices = $list->choices(); $selected = $list->choicesForValue((array) $element->value()); @@ -40,7 +40,7 @@ public function render(ElementInterface $element): string $isMultiChoice = false; if (count($choices) > 1) { - $attributes['name'] = $element->name() . '[]'; + $attributes['name'] = $attributes['name'] . '[]'; $isMultiChoice = true; } @@ -50,8 +50,8 @@ public function render(ElementInterface $element): string $elementAttr['checked'] = isset($selected[$key]); $elementAttr['disabled'] = $choice['disabled']; $elementAttr['id'] = $isMultiChoice - ? $element->id() . '_' . $key - : $element->id(); + ? $attributes['id'] . '_' . $key + : $attributes['id']; $elementAttr = $this->buildCssClasses($elementAttr, 'element', $element); $label = sprintf( diff --git a/src/View/Collection.php b/src/View/Collection.php index 8524506..18ca973 100644 --- a/src/View/Collection.php +++ b/src/View/Collection.php @@ -48,10 +48,6 @@ public function render(ElementInterface $element): string $html = array_reduce( $element->elements(), function ($html, ElementInterface $next) use ($element, $row): string { - // Adding the CollectionElement name to the Element name and ID as prefix. - $next->withAttribute('id', $element->id() . '_' . $next->id()); - $next->withAttribute('name', $element->name() . '[' . $next->name() . ']'); - // In case we have nested CollectionElement, then // we don't want to nest those when rendering. if ($next instanceof Element\CollectionElement) { @@ -65,7 +61,7 @@ function ($html, ElementInterface $next) use ($element, $row): string { '' ); - $attributes = $element->attributes(); + $attributes = $element->attributesForView(); $attributes = $this->buildCssClasses($attributes, 'collection', $element); // we do not want to get the "name" and "type" rendered as attribute on wrapper. unset($attributes['name'], $attributes['type']); diff --git a/src/View/Form.php b/src/View/Form.php index ca4755f..17fd259 100644 --- a/src/View/Form.php +++ b/src/View/Form.php @@ -56,7 +56,7 @@ static function ($html, ElementInterface $next) use ($element, $row): string { '' ); - $attributes = $element->attributes(); + $attributes = $element->attributesForView(); // Don't re-use the "type" as attribute on
-tag. unset($attributes['type']); $classes = (string) ($attributes['class'] ?? ''); diff --git a/src/View/Input.php b/src/View/Input.php index 5c3b7fd..d336e7e 100644 --- a/src/View/Input.php +++ b/src/View/Input.php @@ -21,7 +21,7 @@ class Input implements RenderableElementInterface */ public function render(ElementInterface $element): string { - $attributes = $element->attributes(); + $attributes = $element->attributesForView(); $attributes = $this->buildCssClasses($attributes, 'element', $element); return sprintf( diff --git a/src/View/Label.php b/src/View/Label.php index f848730..55d09c9 100644 --- a/src/View/Label.php +++ b/src/View/Label.php @@ -30,15 +30,16 @@ public function render(ElementInterface $element): string return ''; } - $attributes = $element->labelAttributes(); - if (!isset($attributes['for'])) { - $attributes['for'] = $element->id(); + $labelAttributes = $element->labelAttributes(); + $attributes = $element->attributesForView(); + if (!isset($labelAttributes['for'])) { + $labelAttributes['for'] = $attributes['id']; } - $attributes = $this->buildCssClasses($attributes, 'label', $element); + $labelAttributes = $this->buildCssClasses($labelAttributes, 'label', $element); return sprintf( '', - $this->attributesToString($attributes), + $this->attributesToString($labelAttributes), $element->label() ); } diff --git a/src/View/Progress.php b/src/View/Progress.php index dcd3e90..655b348 100644 --- a/src/View/Progress.php +++ b/src/View/Progress.php @@ -19,7 +19,7 @@ class Progress implements RenderableElementInterface */ public function render(ElementInterface $element): string { - $attributes = $element->attributes(); + $attributes = $element->attributesForView(); $attributes = $this->buildCssClasses($attributes, 'element', $element); diff --git a/src/View/Radio.php b/src/View/Radio.php index fc22aeb..f9141f0 100644 --- a/src/View/Radio.php +++ b/src/View/Radio.php @@ -28,7 +28,7 @@ public function render(ElementInterface $element): string $this->assertElementIsInstanceOf($element, ChoiceElementInterface::class); $list = $element->choices(); - $attributes = $element->attributes(); + $attributes = $element->attributesForView(); $choices = $list->choices(); $selected = $list->choicesForValue((array) $element->value()); diff --git a/src/View/Select.php b/src/View/Select.php index cfb7f5e..0af5348 100644 --- a/src/View/Select.php +++ b/src/View/Select.php @@ -26,7 +26,7 @@ public function render(ElementInterface $element): string { $this->assertElementIsInstanceOf($element, ChoiceElementInterface::class); - $attributes = $element->attributes(); + $attributes = $element->attributesForView(); $attributes = $this->buildCssClasses($attributes, 'element', $element); unset($attributes['type'], $attributes['value']); diff --git a/src/View/Textarea.php b/src/View/Textarea.php index edbe648..30fad5c 100644 --- a/src/View/Textarea.php +++ b/src/View/Textarea.php @@ -19,7 +19,7 @@ class Textarea implements RenderableElementInterface */ public function render(ElementInterface $element): string { - $attributes = $element->attributes(); + $attributes = $element->attributesForView(); $attributes = $this->buildCssClasses($attributes, 'element', $element); unset($attributes['value']); diff --git a/tests/phpunit/Unit/Element/CollectionElementTest.php b/tests/phpunit/Unit/Element/CollectionElementTest.php index a1269a7..27c559f 100644 --- a/tests/phpunit/Unit/Element/CollectionElementTest.php +++ b/tests/phpunit/Unit/Element/CollectionElementTest.php @@ -6,8 +6,10 @@ use ChriCo\Fields\Element\Element; use ChriCo\Fields\Element\ElementInterface; use ChriCo\Fields\Element\ErrorAwareInterface; +use ChriCo\Fields\Element\Form; use ChriCo\Fields\Exception\ElementNotFoundException; use ChriCo\Fields\Tests\Unit\AbstractTestCase; +use Inpsyde\PresentationElements\Contracts\FormElement; class CollectionElementTest extends AbstractTestCase { @@ -166,4 +168,26 @@ public function testGetAttributeValue(): void static::assertSame($expected, $testee->value()); } + + + /** + * @return void + */ + public function testSetGetMultipleParents(): void + { + $rootElement = new Form('my-form-element'); + $parentElement = new CollectionElement('my-collection-element'); + $element = new Element('my-element'); + + static::assertNull($rootElement->parent()); + static::assertNull($parentElement->parent()); + static::assertNull($element->parent()); + + $parentElement->withElement($element); + $rootElement->withElement($parentElement); + + static::assertSame($rootElement, $parentElement->parent()); + static::assertSame($parentElement, $element->parent()); + } + } diff --git a/tests/phpunit/Unit/Element/ElementTest.php b/tests/phpunit/Unit/Element/ElementTest.php index 700d113..6dd0161 100644 --- a/tests/phpunit/Unit/Element/ElementTest.php +++ b/tests/phpunit/Unit/Element/ElementTest.php @@ -2,14 +2,15 @@ namespace ChriCo\Fields\Tests\Unit\Element; +use ChriCo\Fields\Element\CollectionElement; use ChriCo\Fields\Element\Element; use ChriCo\Fields\Element\ElementInterface; use ChriCo\Fields\Element\LabelAwareInterface; use ChriCo\Fields\Tests\Unit\AbstractTestCase; +use Inpsyde\PresentationElements\Contracts\FormElement; class ElementTest extends AbstractTestCase { - /** * Basic test to check the default behavior of the class. * @@ -40,6 +41,10 @@ public function testBasic(): void static::assertFalse($testee->hasErrors()); static::assertFalse($testee->isDisabled()); + static::assertNull($testee->parent()); + + static::assertFalse($testee->isSubmitted()); + static::assertFalse($testee->isDisabled()); } /** @@ -221,4 +226,47 @@ public function testFilter(): void static::assertSame($expectedValue, $testee->value()); } + + /** + * @test + */ + public function testSetGetParent(): void + { + $parentElement = \Mockery::mock(CollectionElement::class); + + $testee = new Element('my-element'); + $testee->withParent($parentElement); + + static::assertSame($parentElement, $testee->parent()); + } + + /** + * @test + */ + public function testIsDisabledWithParent(): void + { + $parentElement = \Mockery::mock(CollectionElement::class); + $parentElement->expects('isDisabled')->andReturn(true); + + $testee = new Element('my-element'); + static::assertFalse($testee->isDisabled()); + + $testee->withParent($parentElement); + static::assertTrue($testee->isDisabled()); + } + + /** + * @test + */ + public function testIsSubmittedWithParent(): void + { + $parentElement = \Mockery::mock(CollectionElement::class); + $parentElement->expects('isSubmitted')->andReturn(true); + + $testee = new Element('my-element'); + static::assertFalse($testee->isSubmitted()); + + $testee->withParent($parentElement); + static::assertTrue($testee->isSubmitted()); + } } diff --git a/tests/phpunit/Unit/Element/FormTest.php b/tests/phpunit/Unit/Element/FormTest.php index 7da9145..0c058e7 100644 --- a/tests/phpunit/Unit/Element/FormTest.php +++ b/tests/phpunit/Unit/Element/FormTest.php @@ -65,6 +65,8 @@ public function testIsValid(): void ->andReturnTrue(); $element->allows('validate') ->andReturnFalse(); + $element->allows('withParent') + ->andReturn($element); // element which has no validator assigned. $not_validated_element2 = $this->getElementStub($expected_key2); @@ -72,10 +74,14 @@ public function testIsValid(): void ->andReturns($expected_value2); $not_validated_element2->allows('validate') ->andReturnTrue(); + $not_validated_element2->allows('withParent') + ->andReturn($not_validated_element2); // element which is disabled shouldn't't be validated $disabled_element = $this->getElementStub($expected_key3, true); $disabled_element->allows('validate')->never(); + $disabled_element->allows('withParent') + ->andReturn($disabled_element); $testee = (new Form('')) ->withElement($element, $not_validated_element2, $disabled_element); @@ -134,6 +140,8 @@ public function testSetData(): void ->andReturn($expected_value); $element->allows('isDisabled') ->andReturn(false); + $element->allows('withParent') + ->andReturn($element); $testee = new Form(''); $testee->withElement($element) @@ -176,6 +184,8 @@ public function testSubmit(): void ->andReturn($expected_value); $element->allows('validate') ->andReturnTrue(); + $element->allows('withParent') + ->andReturn($element); $testee = new Form(''); $testee->withElement($element); diff --git a/tests/phpunit/Unit/View/CollectionTest.php b/tests/phpunit/Unit/View/CollectionTest.php index 725e85a..7e6caf7 100644 --- a/tests/phpunit/Unit/View/CollectionTest.php +++ b/tests/phpunit/Unit/View/CollectionTest.php @@ -43,17 +43,23 @@ public function testRenderInvalidElement(): void */ public function testRenderNestedCollectionElements(): void { - $expectedName1 = 'name1'; - $expectedName2 = 'name2'; - $expectedTextElementName = 'text'; + $rootCollectionName = 'rootCollection'; + $childCollectionName = 'childCollection'; + $textElementName = 'text'; + $textElementWithLabelName = 'text-with-label'; - $textElement = new Element($expectedTextElementName); + $textElement = new Element($textElementName); $textElement->withAttribute('type', 'text'); - $childCollection = new CollectionElement($expectedName2); + $textElementWithLabel = new Element($textElementWithLabelName); + $textElementWithLabel->withAttribute('type', 'text'); + $textElementWithLabel->withLabel('Some Label'); + + $childCollection = new CollectionElement($childCollectionName); $childCollection->withElement($textElement); + $childCollection->withElement($textElementWithLabel); - $rootCollection = new CollectionElement($expectedName1); + $rootCollection = new CollectionElement($rootCollectionName); $rootCollection->withElement($childCollection); $result = (new Collection())->render($rootCollection); diff --git a/tests/phpunit/Unit/View/FormTest.php b/tests/phpunit/Unit/View/FormTest.php index 369d75f..1b1228f 100644 --- a/tests/phpunit/Unit/View/FormTest.php +++ b/tests/phpunit/Unit/View/FormTest.php @@ -54,13 +54,13 @@ public function testRender(): void ->andReturn($expected_name); $element_stub->allows('type') ->andReturn('text'); - $element_stub->allows('attributes') + $element_stub->allows('attributesForView') ->andReturn([]); $form_stub = Mockery::mock(FormInterface::class, ElementInterface::class, CollectionElementInterface::class); $form_stub->allows('name') ->andReturn('form'); - $form_stub->allows('attributes') + $form_stub->allows('attributesForView') ->andReturn([]); $form_stub->allows('elements') ->andReturn([$element_stub]);