From 588fb5dfec441126ea46f2a6519bb84da5bf035b Mon Sep 17 00:00:00 2001 From: Joey Smith Date: Sun, 21 Apr 2024 10:47:29 -0500 Subject: [PATCH 1/8] Initial commit to this branch for moving to delegators and events Signed-off-by: Joey Smith Signed-off-by: Joey Smith --- src/ConfigProvider.php | 111 ++--- src/Events.php | 23 + src/Form/Element.php | 17 - src/Form/Element/Button.php | 19 - src/Form/Element/Checkbox.php | 244 ---------- .../Delegator/Factory/CheckboxFactory.php | 25 - .../Factory/ElementDelegatorFactory.php | 22 - .../Delegator/Factory/SubmitFactory.php | 25 - .../Element/Delegator/Factory/TextFactory.php | 25 - src/Form/Element/Listener/ElementListener.php | 50 ++ .../Listener/ElementListenerFactory.php | 18 + src/Form/Element/MultiCheckbox.php | 186 -------- src/Form/Element/Password.php | 22 - src/Form/Element/Radio.php | 34 -- src/Form/Element/Select.php | 339 -------------- src/Form/Element/Submit.php | 19 - src/Form/Element/Text.php | 15 - src/Form/Element/Textarea.php | 19 - src/Form/ElementInterface.php | 24 - src/Form/Fieldset.php | 42 -- src/Form/Form.php | 78 ---- src/Form/Gridset.php | 11 - src/Form/HelpAwareInterface.php | 26 -- src/Form/ModeAwareInterface.php | 25 - src/Form/NestedElementInterface.php | 20 - ...erface.php => RenderListenerInterface.php} | 2 +- .../Delegator/Factory/FormCheckboxFactory.php | 22 - .../Factory/FormCollectionFactory.php | 22 - .../Delegator/Factory/FormElementFactory.php | 22 - .../View/Delegator/Factory/FormFactory.php | 22 - .../Delegator/Factory/FormInputFactory.php | 22 - .../View/Delegator/Factory/FormRowFactory.php | 22 - .../Delegator/Factory/FormTextFactory.php | 22 - src/Form/View/Helper/AbstractHelper.php | 84 ---- src/Form/View/Helper/Event/RenderEvent.php | 104 +++++ .../View/Helper/Factory/FormInputFactory.php | 23 - src/Form/View/Helper/Form.php | 130 ------ src/Form/View/Helper/FormBootstrapElement.php | 92 ---- src/Form/View/Helper/FormCheckbox.php | 83 ---- src/Form/View/Helper/FormCollection.php | 394 ---------------- src/Form/View/Helper/FormDelegator.php | 48 ++ src/Form/View/Helper/FormDelegatorFactory.php | 25 + src/Form/View/Helper/FormElement.php | 196 -------- src/Form/View/Helper/FormElementDelegator.php | 69 +++ .../Helper/FormElementDelegatorFactory.php | 28 ++ src/Form/View/Helper/FormGridCollection.php | 394 ---------------- .../View/Helper/FormHorizontalElement.php | 21 - src/Form/View/Helper/FormInput.php | 186 -------- .../View/Helper/FormInputDelegatorFactory.php | 23 + src/Form/View/Helper/FormInputDelegatorphp | 72 +++ src/Form/View/Helper/FormLabel.php | 11 - src/Form/View/Helper/FormMultiCheckbox.php | 434 ------------------ src/Form/View/Helper/FormRadio.php | 26 -- src/Form/View/Helper/FormRow.php | 431 ----------------- src/Form/View/Helper/FormRowDelegator.php | 168 +++++++ .../View/Helper/FormRowDelegatorFactory.php | 26 ++ src/Form/View/Helper/FormSelectDelegator.php | 92 ++++ .../Helper/FormSelectDelegatorFactory.php | 23 + src/Form/View/Helper/FormText.php | 39 -- src/Form/View/Helper/HelperDelegatorTrait.php | 22 + src/Provider/Bootstrap/ElementClass.php | 37 ++ src/Provider/Bootstrap/LayoutMode.php | 13 + .../Bootstrap/Listener/RenderListener.php | 62 +++ .../Listener/RenderListenerFactory.php | 22 + src/Provider/CssClassProviderInterface.php | 10 + src/Provider/CssClassProviderTrait.php | 37 ++ 66 files changed, 1020 insertions(+), 4000 deletions(-) create mode 100644 src/Events.php delete mode 100644 src/Form/Element.php delete mode 100644 src/Form/Element/Button.php delete mode 100644 src/Form/Element/Checkbox.php delete mode 100644 src/Form/Element/Delegator/Factory/CheckboxFactory.php delete mode 100644 src/Form/Element/Delegator/Factory/ElementDelegatorFactory.php delete mode 100644 src/Form/Element/Delegator/Factory/SubmitFactory.php delete mode 100644 src/Form/Element/Delegator/Factory/TextFactory.php create mode 100644 src/Form/Element/Listener/ElementListener.php create mode 100644 src/Form/Element/Listener/ElementListenerFactory.php delete mode 100644 src/Form/Element/MultiCheckbox.php delete mode 100644 src/Form/Element/Password.php delete mode 100644 src/Form/Element/Radio.php delete mode 100644 src/Form/Element/Select.php delete mode 100644 src/Form/Element/Submit.php delete mode 100644 src/Form/Element/Text.php delete mode 100644 src/Form/Element/Textarea.php delete mode 100644 src/Form/ElementInterface.php delete mode 100644 src/Form/Fieldset.php delete mode 100644 src/Form/Form.php delete mode 100644 src/Form/Gridset.php delete mode 100644 src/Form/HelpAwareInterface.php delete mode 100644 src/Form/ModeAwareInterface.php delete mode 100644 src/Form/NestedElementInterface.php rename src/Form/{GridsetInterface.php => RenderListenerInterface.php} (64%) delete mode 100644 src/Form/View/Delegator/Factory/FormCheckboxFactory.php delete mode 100644 src/Form/View/Delegator/Factory/FormCollectionFactory.php delete mode 100644 src/Form/View/Delegator/Factory/FormElementFactory.php delete mode 100644 src/Form/View/Delegator/Factory/FormFactory.php delete mode 100644 src/Form/View/Delegator/Factory/FormInputFactory.php delete mode 100644 src/Form/View/Delegator/Factory/FormRowFactory.php delete mode 100644 src/Form/View/Delegator/Factory/FormTextFactory.php delete mode 100644 src/Form/View/Helper/AbstractHelper.php create mode 100644 src/Form/View/Helper/Event/RenderEvent.php delete mode 100644 src/Form/View/Helper/Factory/FormInputFactory.php delete mode 100644 src/Form/View/Helper/Form.php delete mode 100644 src/Form/View/Helper/FormBootstrapElement.php delete mode 100644 src/Form/View/Helper/FormCheckbox.php delete mode 100644 src/Form/View/Helper/FormCollection.php create mode 100644 src/Form/View/Helper/FormDelegator.php create mode 100644 src/Form/View/Helper/FormDelegatorFactory.php delete mode 100644 src/Form/View/Helper/FormElement.php create mode 100644 src/Form/View/Helper/FormElementDelegator.php create mode 100644 src/Form/View/Helper/FormElementDelegatorFactory.php delete mode 100644 src/Form/View/Helper/FormGridCollection.php delete mode 100644 src/Form/View/Helper/FormHorizontalElement.php delete mode 100644 src/Form/View/Helper/FormInput.php create mode 100644 src/Form/View/Helper/FormInputDelegatorFactory.php create mode 100644 src/Form/View/Helper/FormInputDelegatorphp delete mode 100644 src/Form/View/Helper/FormLabel.php delete mode 100644 src/Form/View/Helper/FormMultiCheckbox.php delete mode 100644 src/Form/View/Helper/FormRadio.php delete mode 100644 src/Form/View/Helper/FormRow.php create mode 100644 src/Form/View/Helper/FormRowDelegator.php create mode 100644 src/Form/View/Helper/FormRowDelegatorFactory.php create mode 100644 src/Form/View/Helper/FormSelectDelegator.php create mode 100644 src/Form/View/Helper/FormSelectDelegatorFactory.php delete mode 100644 src/Form/View/Helper/FormText.php create mode 100644 src/Form/View/Helper/HelperDelegatorTrait.php create mode 100644 src/Provider/Bootstrap/ElementClass.php create mode 100644 src/Provider/Bootstrap/LayoutMode.php create mode 100644 src/Provider/Bootstrap/Listener/RenderListener.php create mode 100644 src/Provider/Bootstrap/Listener/RenderListenerFactory.php create mode 100644 src/Provider/CssClassProviderInterface.php create mode 100644 src/Provider/CssClassProviderTrait.php diff --git a/src/ConfigProvider.php b/src/ConfigProvider.php index e9555a3..ad94c4c 100644 --- a/src/ConfigProvider.php +++ b/src/ConfigProvider.php @@ -4,24 +4,20 @@ namespace Limatus; -use Laminas\Form\Element\Checkbox; -use Laminas\Form\Element\Text; -use Laminas\Form\ElementFactory; use Laminas\Form\View\Helper\Factory\FormElementErrorsFactory; use Laminas\Form\View\Helper\Form; -use Laminas\Form\View\Helper\FormCheckbox as FormCheckboxHelper; use Laminas\Form\View\Helper\FormCollection; use Laminas\Form\View\Helper\FormElement; use Laminas\Form\View\Helper\FormElementErrors; use Laminas\Form\View\Helper\FormInput; +use Laminas\Form\View\Helper\FormPassword; use Laminas\Form\View\Helper\FormRow; -use Laminas\Form\View\Helper\FormText; -use Laminas\ServiceManager\Factory; -use Laminas\ServiceManager\Factory\InvokableFactory; use Laminas\View\Helper\Navigation\Menu; +use Limatus\Form\RenderListenerInterface; use Limatus\Form\Element; use Limatus\Form\View; -use Limatus\View\Helper; +use Limatus\Form\View\Helper; +use Limatus\Provider\Bootstrap\LayoutMode; class ConfigProvider { @@ -37,57 +33,36 @@ public function __invoke(): array public function getDependencyConfig(): array { - return []; + return [ + 'aliases' => [ + RenderListenerInterface::class + => Provider\Bootstrap\Listener\RenderListener::class, + ], + 'factories' => [ + Element\Listener\ElementListener::class + => Element\Listener\ElementListenerFactory::class, + Provider\Bootstrap\Listener\RenderListener::class + => Provider\Bootstrap\Listener\RenderListenerFactory::class, + ], + ]; } /** only new components get aliases */ public function getViewHelperConfig(): array { return [ - 'aliases' => [ - 'formBootstrapElement' => View\Helper\FormBootstrapElement::class, - 'formGridCollection' => View\Helper\FormGridCollection::class, - 'formHelp' => View\Helper\FormHelp::class, - 'formHorizontalElement' => View\Helper\FormHorizontalElement::class, - 'formCheckBox' => View\Helper\FormCheckbox::class, - 'modal' => Helper\Modal::class, - ], - 'factories' => [ - FormElementErrors::class => FormElementErrorsFactory::class, - View\Helper\Form::class => Factory\InvokableFactory::class, - View\Helper\FormCheckbox::class => Factory\InvokableFactory::class, - View\Helper\FormCollection::class => Factory\InvokableFactory::class, - View\Helper\FormElement::class => Factory\InvokableFactory::class, - View\Helper\FormInput::class => Factory\InvokableFactory::class, - View\Helper\FormRow::class => Factory\InvokableFactory::class, - View\Helper\FormText::class => Factory\InvokableFactory::class, - View\Helper\FormBootstrapElement::class => Factory\InvokableFactory::class, - View\Helper\FormGridCollection::class => Factory\InvokableFactory::class, - View\Helper\FormHelp::class => Factory\InvokableFactory::class, - View\Helper\FormHorizontalElement::class => Factory\InvokableFactory::class, - Helper\Modal::class => Factory\InvokableFactory::class, - ], 'delegators' => [ Form::class => [ - View\Delegator\Factory\FormFactory::class, - ], - FormCheckboxHelper::class => [ - View\Delegator\Factory\FormCheckboxFactory::class, - ], - FormCollection::class => [ - View\Delegator\Factory\FormCollectionFactory::class, + Helper\FormDelegatorFactory::class, ], + // FormCollection::class => [ + // View\Delegator\Factory\FormCollectionFactory::class, + // ], FormElement::class => [ - View\Delegator\Factory\FormElementFactory::class, - ], - FormInput::class => [ - View\Delegator\Factory\FormInputFactory::class, + Helper\FormElementDelegatorFactory::class, ], FormRow::class => [ - View\Delegator\Factory\FormRowFactory::class, - ], - FormText::class => [ - View\Delegator\Factory\FormTextFactory::class, + Helper\FormRowDelegatorFactory::class, ], ], ]; @@ -96,6 +71,14 @@ public function getViewHelperConfig(): array public function getHelperConfig(): array { return [ + static::class => [ + 'form_layout_mode' => LayoutMode::Grid, // Override the default form layout + // set defaults. Values passed via $formHelper mutators will override these values. + 'g' => '', + 'row' => '', + 'mb' => '', + 'col' => '', + ], 'form_element_errors' => [ 'message_open_format' => '
  • ', 'message_separator_string' => '
  • ', @@ -112,16 +95,16 @@ public function getFormElementConfig(): array return [ 'aliases' => [], 'factories' => [ - Element\Checkbox::class => ElementFactory::class, - Element\Text::class => ElementFactory::class, + // Element\Checkbox::class => ElementFactory::class, + // Element\Text::class => ElementFactory::class, ], 'delegators' => [ - Checkbox::class => [ - Element\Delegator\Factory\CheckboxFactory::class, - ], - Text::class => [ - Element\Delegator\Factory\TextFactory::class, - ], + // Checkbox::class => [ + // Element\Delegator\Factory\CheckboxFactory::class, + // ], + // Text::class => [ + // Element\Delegator\Factory\TextFactory::class, + // ], ], ]; } @@ -129,15 +112,15 @@ public function getFormElementConfig(): array public function getNavigationHelperConfig(): array { return [ - 'aliases' => [], - 'factories' => [ - Helper\Navigation\Menu::class => InvokableFactory::class, - ], - 'delegators' => [ - Menu::class => [ - Helper\Navigation\Delegator\Factory\MenuFactory::class, - ], - ], + // 'aliases' => [], + // 'factories' => [ + // Helper\Navigation\Menu::class => InvokableFactory::class, + // ], + // 'delegators' => [ + // Menu::class => [ + // Helper\Navigation\Delegator\Factory\MenuFactory::class, + // ], + // ], ]; } } diff --git a/src/Events.php b/src/Events.php new file mode 100644 index 0000000..6f381b1 --- /dev/null +++ b/src/Events.php @@ -0,0 +1,23 @@ + 'button', - ]; -} diff --git a/src/Form/Element/Checkbox.php b/src/Form/Element/Checkbox.php deleted file mode 100644 index 193ad38..0000000 --- a/src/Form/Element/Checkbox.php +++ /dev/null @@ -1,244 +0,0 @@ - 'checkbox', - ]; - - protected array $nestedElementAttributes = []; - - /** @var null|ValidatorInterface */ - protected $validator; - - /** @var bool */ - protected $useHiddenElement = true; - - /** @var string */ - protected $uncheckedValue = '0'; - - /** @var string */ - protected $checkedValue = '1'; - - /** - * Accepted options for MultiCheckbox: - * - use_hidden_element: do we render hidden element? - * - unchecked_value: value for checkbox when unchecked - * - checked_value: value for checkbox when checked - * - * @return $this - */ - public function setOptions(iterable $options) - { - parent::setOptions($options); - - if (isset($this->options['use_hidden_element'])) { - $this->setUseHiddenElement($this->options['use_hidden_element']); - } - - if (isset($this->options['unchecked_value'])) { - $this->setUncheckedValue($this->options['unchecked_value']); - } - - if (isset($this->options['checked_value'])) { - $this->setCheckedValue($this->options['checked_value']); - } - - if (isset($this->options['nested_element_attributes'])) { - $this->setNestedElementAttributes($this->options['nested_element_attributes']); - unset($this->options['nested_element_attributes']); - } - - return $this; - } - - /** - * Do we render hidden element? - * - * @return $this - */ - public function setUseHiddenElement(bool $useHiddenElement) - { - $this->useHiddenElement = $useHiddenElement; - return $this; - } - - /** - * Do we render hidden element? - */ - public function useHiddenElement(): bool - { - return $this->useHiddenElement; - } - - /** - * Set the value to use when checkbox is unchecked - * - * @return $this - */ - public function setUncheckedValue(string $uncheckedValue) - { - $this->uncheckedValue = $uncheckedValue; - return $this; - } - - /** - * Get the value to use when checkbox is unchecked - */ - public function getUncheckedValue(): string - { - return $this->uncheckedValue; - } - - /** - * Set the value to use when checkbox is checked - * - * @return $this - */ - public function setCheckedValue(string $checkedValue) - { - $this->checkedValue = $checkedValue; - return $this; - } - - /** - * Get the value to use when checkbox is checked - */ - public function getCheckedValue(): string - { - return $this->checkedValue; - } - - /** - * Get validator - */ - protected function getValidator(): ?ValidatorInterface - { - if (null === $this->validator) { - $this->validator = new InArrayValidator([ - 'haystack' => [$this->checkedValue, $this->uncheckedValue], - 'strict' => false, - ]); - } - return $this->validator; - } - - /** - * Provide default input rules for this element - * - * Attaches the captcha as a validator. - * - * @inheritDoc - */ - public function getInputSpecification(): array - { - $spec = [ - 'required' => true, - ]; - - $name = $this->getName(); - if ($name !== null) { - $spec['name'] = $name; - } - - if ($validator = $this->getValidator()) { - $spec['validators'] = [ - $validator, - ]; - } - - return $spec; - } - - /** - * Checks if this checkbox is checked. - */ - public function isChecked(): bool - { - return $this->value === $this->getCheckedValue(); - } - - /** - * Checks or unchecks the checkbox. - * - * @param bool $value The flag to set. - * @return $this - */ - public function setChecked(bool $value) - { - $this->value = $value ? $this->getCheckedValue() : $this->getUncheckedValue(); - return $this; - } - - /** - * Checks or unchecks the checkbox. - * - * @param mixed $value A boolean flag or string that is checked against the "checked value". - * @return $this - */ - public function setValue($value) - { - // Cast to strings because POST data comes in string form - $checked = (string) $value === $this->getCheckedValue(); - $this->value = $checked ? $this->getCheckedValue() : $this->getUncheckedValue(); - return $this; - } - - public function setNestedElementAttribute(string $key, string|array $value): NestedElementInterface - { - $this->nestedElementAttributes[$key] = $value; - return $this; - } - - public function setNestedElementAttributes(array $nestedAttributes): NestedElementInterface - { - foreach ($nestedAttributes as $key => $value) { - $this->setNestedElementAttribute($key, $value); - } - return $this; - } - - public function getNestedElementAttribute(string $key): string|array|null - { - if (array_key_exists($key, $this->nestedElementAttributes)) { - return $this->nestedElementAttributes[$key]; - } - return null; - } - - public function getNestedElementAttributes(): array - { - return $this->nestedElementAttributes; - } - - public function removeNestedElementAttribute(string $key): NestedElementInterface - { - if (array_key_exists($key, $this->nestedElementAttributes)) { - unset($this->nestedElementAttributes[$key]); - } - return $this; - } - - public function clearNestedElementAttributes(): NestedElementInterface - { - $this->nestedElementAttributes = []; - return $this; - } -} diff --git a/src/Form/Element/Delegator/Factory/CheckboxFactory.php b/src/Form/Element/Delegator/Factory/CheckboxFactory.php deleted file mode 100644 index 7035c04..0000000 --- a/src/Form/Element/Delegator/Factory/CheckboxFactory.php +++ /dev/null @@ -1,25 +0,0 @@ -listeners[] = $events->attach(Events::SetOptions->value, [$this, 'onSetOptions'], 100); + } + + public function onSetOptions(EventInterface $event) + { + /** @var Element */ + $element = $event->getTarget(); + $options = $element->getOptions(); + $attributes = $element->getAttributes(); + $this->helper->set($attributes); + foreach ($options as $key => $value) { + switch (true) { + case $key === 'column': + case $key === 'row': + case $key === 'bootstrap_attributes': + $this->helper->add('class', $value); + break; + + default: + # code... + break; + } + } + // todo: fix the array to string this causes when AbstractHelper::prepareAttributes is called + // maybe override prepareAttributes and trigger listener to handle it? + $element->setAttributes($this->helper->getArrayCopy()); + } +} diff --git a/src/Form/Element/Listener/ElementListenerFactory.php b/src/Form/Element/Listener/ElementListenerFactory.php new file mode 100644 index 0000000..7f4faf5 --- /dev/null +++ b/src/Form/Element/Listener/ElementListenerFactory.php @@ -0,0 +1,18 @@ +get(HelperPluginManager::class); + return new ElementListener(($manager->get(HtmlAttributes::class))()); + } +} diff --git a/src/Form/Element/MultiCheckbox.php b/src/Form/Element/MultiCheckbox.php deleted file mode 100644 index 1b351d9..0000000 --- a/src/Form/Element/MultiCheckbox.php +++ /dev/null @@ -1,186 +0,0 @@ - 'multi_checkbox', - ]; - - /** @var bool */ - protected $disableInArrayValidator = false; - - /** @var bool */ - protected $useHiddenElement = false; - - /** @var string */ - protected $uncheckedValue = ''; - - /** @var array */ - protected $valueOptions = []; - - /** - * @return array - */ - public function getValueOptions(): array - { - return $this->valueOptions; - } - - /** - * @return $this - */ - public function setValueOptions(array $options) - { - $this->valueOptions = $options; - - // Update Explode validator haystack - if ($this->validator instanceof ExplodeValidator) { - $validator = $this->validator->getValidator(); - assert($validator instanceof InArrayValidator); - $validator->setHaystack($this->getValueOptionsValues()); - } - - return $this; - } - - /** - * @return $this - */ - public function unsetValueOption(string $key) - { - if (isset($this->valueOptions[$key])) { - unset($this->valueOptions[$key]); - } - - return $this; - } - - /** - * Set options for an element. Accepted options are: - * - label: label to associate with the element - * - label_attributes: attributes to use when the label is rendered - * - value_options: list of values and labels for the select options - * - * @return $this - * @throws InvalidArgumentException - */ - public function setOptions(iterable $options) - { - parent::setOptions($options); - - if (isset($this->options['value_options'])) { - $this->setValueOptions($this->options['value_options']); - } - // Alias for 'value_options' - if (isset($this->options['options'])) { - $this->setValueOptions($this->options['options']); - } - if (isset($this->options['disable_inarray_validator'])) { - $this->setDisableInArrayValidator($this->options['disable_inarray_validator']); - } - - return $this; - } - - /** - * Set a single element attribute - * - * @param mixed $value - * @return $this - */ - public function setAttribute(string $key, $value) - { - // Do not include the options in the list of attributes - // TODO: Deprecate this - if ($key === 'options') { - $this->setValueOptions($value); - return $this; - } - return parent::setAttribute($key, $value); - } - - /** - * Set the flag to allow for disabling the automatic addition of an InArray validator. - * - * @return $this - */ - public function setDisableInArrayValidator(bool $disableOption) - { - $this->disableInArrayValidator = $disableOption; - return $this; - } - - /** - * Get the disable in array validator flag. - */ - public function disableInArrayValidator(): bool - { - return $this->disableInArrayValidator; - } - - /** - * Get validator - */ - protected function getValidator(): ?ValidatorInterface - { - if (null === $this->validator && ! $this->disableInArrayValidator()) { - $inArrayValidator = new InArrayValidator([ - 'haystack' => $this->getValueOptionsValues(), - 'strict' => false, - ]); - $this->validator = new ExplodeValidator([ - 'validator' => $inArrayValidator, - 'valueDelimiter' => null, // skip explode if only one value - ]); - } - return $this->validator; - } - - /** - * Get only the values from the options attribute - * - * @return array - */ - protected function getValueOptionsValues(): array - { - $values = []; - $options = $this->getValueOptions(); - foreach ($options as $key => $optionSpec) { - $value = is_array($optionSpec) ? $optionSpec['value'] : $key; - $values[] = $value; - } - if ($this->useHiddenElement()) { - $values[] = $this->getUncheckedValue(); - } - return $values; - } - - /** - * Sets the value that should be selected. - * - * @param mixed $value The value to set. - * @return $this - */ - public function setValue($value) - { - $this->value = $value; - return $this; - } -} diff --git a/src/Form/Element/Password.php b/src/Form/Element/Password.php deleted file mode 100644 index 7eb3629..0000000 --- a/src/Form/Element/Password.php +++ /dev/null @@ -1,22 +0,0 @@ - 'password', - ]; - - public function prepareElement(FormInterface $form): void - { - $this->setValue(''); - } -} diff --git a/src/Form/Element/Radio.php b/src/Form/Element/Radio.php deleted file mode 100644 index 56aabbf..0000000 --- a/src/Form/Element/Radio.php +++ /dev/null @@ -1,34 +0,0 @@ - 'radio', - ]; - - /** - * Get validator - */ - protected function getValidator(): ?ValidatorInterface - { - if (null === $this->validator && ! $this->disableInArrayValidator()) { - $this->validator = new InArrayValidator([ - 'haystack' => $this->getValueOptionsValues(), - 'strict' => false, - ]); - } - return $this->validator; - } -} diff --git a/src/Form/Element/Select.php b/src/Form/Element/Select.php deleted file mode 100644 index b5694fd..0000000 --- a/src/Form/Element/Select.php +++ /dev/null @@ -1,339 +0,0 @@ - 'select', - ]; - - /** @var null|ValidatorInterface */ - protected $validator; - - /** @var bool */ - protected $disableInArrayValidator = false; - - /** - * Create an empty option (option with label but no value). If set to null, no option is created - * - * @var null|string|array - */ - protected $emptyOption; - - /** @var array */ - protected $valueOptions = []; - - /** @var bool */ - protected $useHiddenElement = false; - - /** @var string */ - protected $unselectedValue = ''; - - /** - * @return array - */ - public function getValueOptions(): array - { - return $this->valueOptions; - } - - /** - * @return $this - */ - public function setValueOptions(array $options) - { - $this->valueOptions = $options; - - // Update InArrayValidator validator haystack - if (null !== $this->validator) { - if ($this->validator instanceof InArrayValidator) { - $validator = $this->validator; - } - if ( - $this->validator instanceof ExplodeValidator - && $this->validator->getValidator() instanceof InArrayValidator - ) { - $validator = $this->validator->getValidator(); - } - if (! empty($validator)) { - $validator->setHaystack($this->getValueOptionsValues()); - } - } - - return $this; - } - - /** - * @return $this - */ - public function unsetValueOption(string $key) - { - if (isset($this->valueOptions[$key])) { - unset($this->valueOptions[$key]); - } - - return $this; - } - - /** - * Set options for an element. Accepted options are: - * - label: label to associate with the element - * - label_attributes: attributes to use when the label is rendered - * - value_options: list of values and labels for the select options - * - empty_option: should an empty option be prepended to the options ? - * - * @return $this - * @throws InvalidArgumentException - */ - public function setOptions(iterable $options) - { - parent::setOptions($options); - - if (isset($this->options['value_options'])) { - $this->setValueOptions($this->options['value_options']); - } - // Alias for 'value_options' - if (isset($this->options['options'])) { - $this->setValueOptions($this->options['options']); - } - - if (isset($this->options['empty_option'])) { - $this->setEmptyOption($this->options['empty_option']); - } - - if (isset($this->options['disable_inarray_validator'])) { - $this->setDisableInArrayValidator($this->options['disable_inarray_validator']); - } - - if (isset($this->options['use_hidden_element'])) { - $this->setUseHiddenElement($this->options['use_hidden_element']); - } - - if (isset($this->options['unselected_value'])) { - $this->setUnselectedValue($this->options['unselected_value']); - } - - return $this; - } - - /** - * Set a single element attribute - * - * @param mixed $value - * @return $this - */ - public function setAttribute(string $key, $value) - { - // Do not include the options in the list of attributes - // TODO: Deprecate this - if ($key === 'options') { - $this->setValueOptions($value); - return $this; - } - return parent::setAttribute($key, $value); - } - - /** - * Set the flag to allow for disabling the automatic addition of an InArray validator. - * - * @return $this - */ - public function setDisableInArrayValidator(bool $disableOption) - { - $this->disableInArrayValidator = $disableOption; - return $this; - } - - /** - * Get the disable in array validator flag. - */ - public function disableInArrayValidator(): bool - { - return $this->disableInArrayValidator; - } - - /** - * Set the string for an empty option (can be empty string). If set to null, no option will be added - * - * @param null|string|array $emptyOption - * @return $this - */ - public function setEmptyOption($emptyOption) - { - $this->emptyOption = $emptyOption; - return $this; - } - - /** - * Return the string for the empty option (null if none) - * - * @return null|string|array - */ - public function getEmptyOption() - { - return $this->emptyOption; - } - - /** - * Get validator - */ - protected function getValidator(): ?ValidatorInterface - { - if (null === $this->validator && ! $this->disableInArrayValidator()) { - $validator = new InArrayValidator([ - 'haystack' => $this->getValueOptionsValues(), - 'strict' => false, - ]); - - if ($this->isMultiple()) { - $validator = new ExplodeValidator([ - 'validator' => $validator, - 'valueDelimiter' => null, // skip explode if only one value - ]); - } - - $this->validator = $validator; - } - return $this->validator; - } - - /** - * Do we render hidden element? - * - * @return $this - */ - public function setUseHiddenElement(bool $useHiddenElement) - { - $this->useHiddenElement = $useHiddenElement; - return $this; - } - - /** - * Do we render hidden element? - */ - public function useHiddenElement(): bool - { - return $this->useHiddenElement; - } - - /** - * Set the value if the select is not selected - * - * @return $this - */ - public function setUnselectedValue(string $unselectedValue) - { - $this->unselectedValue = $unselectedValue; - return $this; - } - - /** - * Get the value when the select is not selected - */ - public function getUnselectedValue(): string - { - return $this->unselectedValue; - } - - /** - * Provide default input rules for this element - * - * @inheritDoc - */ - public function getInputSpecification(): array - { - $spec = [ - 'required' => true, - ]; - - $name = $this->getName(); - if ($name !== null) { - $spec['name'] = $name; - } - - if ($this->useHiddenElement() && $this->isMultiple()) { - $unselectedValue = $this->getUnselectedValue(); - - $spec['allow_empty'] = true; - $spec['continue_if_empty'] = true; - $spec['filters'] = [ - [ - 'name' => 'Callback', - 'options' => [ - 'callback' => static function ($value) use ($unselectedValue) { - if ($value === $unselectedValue) { - $value = []; - } - return $value; - }, - ], - ], - ]; - } - - if ($validator = $this->getValidator()) { - $spec['validators'] = [ - $validator, - ]; - } - - return $spec; - } - - /** - * Get only the values from the options attribute - * - * @return array - */ - protected function getValueOptionsValues(): array - { - $values = []; - $options = $this->getValueOptions(); - foreach ($options as $key => $optionSpec) { - if (is_array($optionSpec) && array_key_exists('options', $optionSpec)) { - foreach ($optionSpec['options'] as $nestedKey => $nestedOptionSpec) { - $values[] = $this->getOptionValue($nestedKey, $nestedOptionSpec); - } - continue; - } - - $values[] = $this->getOptionValue($key, $optionSpec); - } - return $values; - } - - /** - * @return mixed - */ - protected function getOptionValue(mixed $key, mixed $optionSpec) - { - return is_array($optionSpec) ? $optionSpec['value'] : $key; - } - - /** - * Element has the multiple attribute - */ - public function isMultiple(): bool - { - return isset($this->attributes['multiple']) - && ($this->attributes['multiple'] === true || $this->attributes['multiple'] === 'multiple'); - } -} diff --git a/src/Form/Element/Submit.php b/src/Form/Element/Submit.php deleted file mode 100644 index 2c18b81..0000000 --- a/src/Form/Element/Submit.php +++ /dev/null @@ -1,19 +0,0 @@ - 'submit', - ]; -} diff --git a/src/Form/Element/Text.php b/src/Form/Element/Text.php deleted file mode 100644 index 4579510..0000000 --- a/src/Form/Element/Text.php +++ /dev/null @@ -1,15 +0,0 @@ - 'text', - ]; -} diff --git a/src/Form/Element/Textarea.php b/src/Form/Element/Textarea.php deleted file mode 100644 index f4ffb6f..0000000 --- a/src/Form/Element/Textarea.php +++ /dev/null @@ -1,19 +0,0 @@ - 'textarea', - ]; -} diff --git a/src/Form/ElementInterface.php b/src/Form/ElementInterface.php deleted file mode 100644 index b56f7b4..0000000 --- a/src/Form/ElementInterface.php +++ /dev/null @@ -1,24 +0,0 @@ -getName(); - - foreach ($this->iterator as $elementOrFieldset) { - $elementOrFieldset->setName($name . '[' . $elementOrFieldset->getName() . ']'); - - if ($elementOrFieldset instanceof ModeAwareInterface) { - $elementOrFieldset->setMode($this->getMode()); - } - - // Recursively prepare elements - if ($elementOrFieldset instanceof ElementPrepareAwareInterface) { - if ($elementOrFieldset instanceof ModeAwareInterface) { - $elementOrFieldset->setMode($this->getMode()); - } - $elementOrFieldset->prepareElement($form); - } - } - } -} diff --git a/src/Form/Form.php b/src/Form/Form.php deleted file mode 100644 index aa8ffc5..0000000 --- a/src/Form/Form.php +++ /dev/null @@ -1,78 +0,0 @@ -add( - [ - 'name' => 'submit', - 'type' => Submit::class, - 'attributes' => [ - 'id' => strtolower($showText) . $this->getAttribute('name') . 'Button', - 'value' => $showText, - 'class' => $class, - ], - ], - ['priority' => $priority], - ); - } - - /** - * Ensures state is ready for use - * - * Marshalls the input filter, to ensure validation error messages are - * available, and prepares any elements and/or fieldsets that require - * preparation. - * - * @return $this - */ - public function prepare() - { - if ($this->isPrepared) { - return $this; - } - - $this->getInputFilter(); - - // If the user wants to, elements names can be wrapped by the form's name - if ($this->wrapElements()) { - $this->prepareElement($this); - } else { - foreach ($this->getIterator() as $elementOrFieldset) { - // insure all fieldsets and elements are in the same mode - if ($elementOrFieldset instanceof ModeAwareInterface) { - $elementOrFieldset->setMode($this->getMode()); - } - if ($elementOrFieldset instanceof Form) { - $elementOrFieldset->prepare(); - } elseif ($elementOrFieldset instanceof ElementPrepareAwareInterface) { - $elementOrFieldset->prepareElement($this); - } - } - } - - $this->isPrepared = true; - return $this; - } -} diff --git a/src/Form/Gridset.php b/src/Form/Gridset.php deleted file mode 100644 index 11d06bf..0000000 --- a/src/Form/Gridset.php +++ /dev/null @@ -1,11 +0,0 @@ - */ - protected $attributes = ['class' => 'form-row']; -} diff --git a/src/Form/HelpAwareInterface.php b/src/Form/HelpAwareInterface.php deleted file mode 100644 index 1344ede..0000000 --- a/src/Form/HelpAwareInterface.php +++ /dev/null @@ -1,26 +0,0 @@ - */ - protected $typeMap = []; - /** - * inline form css classes - */ - protected string $inlineFormClass = 'inline-form'; - protected string $inlineLabelClass = 'sr-only'; - - /** - * horizontal mode element wrapper - * wrapper for all input markup when in horizontal mode - */ - protected static string $horizontalElementWrapper = '
    %s
    '; - - /** - * Base Limatus input element styles - */ - protected array $typeToClassMap = [ - 'select' => 'form-control', - 'text' => 'form-control', - 'button' => 'btn', - 'checkbox' => 'form-check-input', - 'file' => 'form-control-file', - 'image' => 'form-control', - 'password' => 'form-control', - 'radio' => 'form-check-input', - 'reset' => 'btn', - 'submit' => 'btn', - 'date' => 'form-control', - 'datetime' => 'form-control', - 'datetime-local' => 'form-control', - 'email' => 'form-control', - 'month' => 'form-control', - 'number' => 'form-control', - 'range' => 'form-control', - 'search' => 'form-control', - 'tel' => 'form-control', - 'time' => 'form-control', - 'url' => 'form-control', - 'week' => 'form-control', - 'textarea' => 'form-control', - ]; - - protected function getTypeClass(string $key): string|null - { - $type = null; - if (array_key_exists($key, $this->typeToClassMap)) { - $type = $this->typeToClassMap[$key]; - } - return $type; - } - - /** - * Determine input type to use - */ - protected function getType(ElementInterface $element): string - { - $type = $element->getAttribute('type'); - if (empty($type)) { - return 'text'; - } - - $type = strtolower($type); - if (! isset($this->validTypes[$type])) { - return 'text'; - } - - return $type; - } -} diff --git a/src/Form/View/Helper/Event/RenderEvent.php b/src/Form/View/Helper/Event/RenderEvent.php new file mode 100644 index 0000000..b805b16 --- /dev/null +++ b/src/Form/View/Helper/Event/RenderEvent.php @@ -0,0 +1,104 @@ +attribs = $attribs; + if (isset($attribs['type']) && (ElementClass::tryFrom($attribs['type']) instanceof ElementClass)) { + $this->setType($attribs['type']); + } + return $this; + } + + public function getAttributes(): iterable + { + return $this->attribs; + } + + public function setElement(?ElementInterface $element): self + { + $this->element = $element; + return $this; + } + + public function getElement(): ?ElementInterface + { + return $this->element; + } + + public function setMarkup(string $markup): self + { + $this->markup = $markup; + return $this; + } + + public function getMarkup(): string + { + return $this->markup; + } + + public function setOptions(iterable $options): self + { + $this->options = $options; + if (isset($options['layout_mode']) && $options['layout_mode'] instanceof LayoutMode) { + $this->setLayoutMode($options['layout_mode']); + } + return $this; + } + + public function getOptions(): iterable + { + return $this->options; + } + + public function setType(?string $type): self + { + $this->type = $type; + return $this; + } + + public function getType(): ?string + { + return $this->type; + } + + public function setClassString(?string $classString): self + { + $this->classString = $classString; + return $this; + } + + public function getClassString(): ?string + { + return $this->classString; + } + + public function setLayoutMode(?LayoutMode $layoutMode): self + { + $this->layoutMode = $layoutMode; + return $this; + } + + public function getLayoutMode(): ?LayoutMode + { + return $this->layoutMode; + } +} diff --git a/src/Form/View/Helper/Factory/FormInputFactory.php b/src/Form/View/Helper/Factory/FormInputFactory.php deleted file mode 100644 index 8f01359..0000000 --- a/src/Form/View/Helper/Factory/FormInputFactory.php +++ /dev/null @@ -1,23 +0,0 @@ -has('ViewHelperManager') && $container->get('ViewHelperManager')->has(FormInput::class)) { - return new $requestedName($container->get('ViewHelperManager')->get(FormInput::class)); - } - return new $requestedName(new FormInput()); - } -} diff --git a/src/Form/View/Helper/Form.php b/src/Form/View/Helper/Form.php deleted file mode 100644 index 8622cc3..0000000 --- a/src/Form/View/Helper/Form.php +++ /dev/null @@ -1,130 +0,0 @@ - true, - 'action' => true, - 'autocomplete' => true, - 'enctype' => true, - 'method' => true, - 'name' => true, - 'novalidate' => true, - 'target' => true, - ]; - - /** - * Invoke as function - * - * @template T as null|FormInterface - * @psalm-param T $form - * @psalm-return (T is null ? self : string) - * @return Form|string - */ - public function __invoke(?FormInterface $form = null) - { - if (! $form) { - return $this; - } - return $this->render($form); - } - - /** - * Render a form from the provided $form, - */ - public function render(FormInterface $form): string - { - if (method_exists($form, 'prepare')) { - // should also set the mode for fieldsets and elements to the forms mode - $form->prepare(); - } - - $formContent = ''; - - $renderer = $this->getView(); - assert($renderer instanceof PhpRenderer); - foreach ($form as $element) { - if ($element instanceof ModeAwareInterface && $element instanceof FieldsetInterface) { - $mode = $element->getMode(); - - $formContent = match ($mode) { - ModeAwareInterface::GRID_MODE => $renderer->formGridCollection($element), - ModeAwareInterface::HORIZONTAL_MODE, - ModeAwareInterface::INLINE_MODE, - ModeAwareInterface::DEFAULT_MODE => $renderer->formCollection($element), - }; - } elseif ($element instanceof FieldsetInterface) { - $formContent .= $renderer->formCollection($element); - } else { - $formContent .= $renderer->formRow($element); - } - } - - return $this->openTag($form) . $formContent . $this->closeTag(); - } - - /** - * Generate an opening form tag - */ - public function openTag(?FormInterface $form = null): string - { - $doctype = $this->getDoctype(); - $attributes = []; - - if (! (Doctype::HTML5 === $doctype || Doctype::XHTML5 === $doctype)) { - $attributes = [ - 'action' => '', - 'method' => 'get', - ]; - } - - if ($form instanceof FormInterface) { - // bootstrap start - //$this->bootstrapForm($form, $mode); - // bootstrap end - $formAttributes = $form->getAttributes(); - if (! array_key_exists('id', $formAttributes) && array_key_exists('name', $formAttributes)) { - $formAttributes['id'] = $formAttributes['name']; - } - $attributes = array_merge($attributes, $formAttributes); - } - - if ($attributes) { - return sprintf('
    ', $this->createAttributesString($attributes)); - } - - return ''; - } - - /** - * Generate a closing form tag - */ - public function closeTag(): string - { - return '
    '; - } -} diff --git a/src/Form/View/Helper/FormBootstrapElement.php b/src/Form/View/Helper/FormBootstrapElement.php deleted file mode 100644 index 647a0b6..0000000 --- a/src/Form/View/Helper/FormBootstrapElement.php +++ /dev/null @@ -1,92 +0,0 @@ -%s'; - /** wrapper for horizontal elements that have to be wrapped AGAIN and uses the - * horizontal_attributes class */ - protected static string $horizontalCheckboxWrapper = '
    %s
    '; - protected static string $wrapper = '
    %s%s%s
    '; - protected Helper\FormHelp $helpText; - - public function __invoke(): self - { - return $this; - } - - public function render(BaseInterface $element, string $markup, string $errorString): string - { - if ($element instanceof ElementInterface) { - // do we have errors? if so let'em know - if ($errorString !== '') { - $element->setAttribute('class', 'is-invalid'); - } - // ok lets sort out what mode were in - if ($element instanceof ModeAwareInterface) { - if ($element instanceof Element\Checkbox) { - $markup = sprintf( - self::$checkboxWrapper, - $markup - ); - if ($element->getMode() === ModeAwareInterface::HORIZONTAL_MODE) { - // todo throw an exception if this is not set, we gotta have it for horizontal checkboxes - $markup = sprintf( - self::$horizontalCheckboxWrapper, - $this->createAttributesString($element->getHorizontalAttributes()), - $markup - ); - } - } - } - // todo: #5 validation messages are not showing for mode: horizontal - $markup = sprintf( - self::$wrapper, - $this->createAttributesString($element->getBootstrapAttributes()), - $markup, - $this->getHelpTextHelper()->render($element), - $errorString - ); - // return it ready or not - return $markup; - } elseif ($element instanceof BaseInterface) { - return $markup; - } - // we should never get here, stops phpstan from complaining - throw new InvalidElementException( - sprintf( - 'Expected Element implementing one of - Limatus\\Form\\ElementInterface, - Limatus\\Form\\NestedElementInterface, - Laminas\\Form\\ElementInterface received %s', - class_implements($element) - ) - ); - } - - protected function getHelpTextHelper(): Helper\FormHelp - { - if ($this->view !== null && method_exists($this->view, 'plugin')) { - $this->helpText = $this->view->plugin('formHelp'); - return $this->helpText; - } - - $this->helpText = new Helper\FormHelp(); - return $this->helpText; - } -} diff --git a/src/Form/View/Helper/FormCheckbox.php b/src/Form/View/Helper/FormCheckbox.php deleted file mode 100644 index 191fd98..0000000 --- a/src/Form/View/Helper/FormCheckbox.php +++ /dev/null @@ -1,83 +0,0 @@ - element from the provided $element - * - * @throws Exception\InvalidArgumentException - * @throws Exception\DomainException - */ - public function render(ElementInterface $element): string - { - if (! $element instanceof Element\Checkbox) { - throw new Exception\InvalidArgumentException(sprintf( - 'Requires $element to one of ' . Element\Checkbox::class . ' or ' . Element\Checkbox::class . ' recieved: %s', - $element::class - )); - } - - $name = $element->getName(); - if ($name === null || $name === '') { - throw new Exception\DomainException(sprintf( - '%s requires that the element has an assigned name; none discovered', - __METHOD__ - )); - } - - // force an id so the label will not wrap - if (! $element->hasAttribute('id')) { - $element->setAttribute('id', $name); - } - - $attributes = $element->getAttributes(); - $attributes['name'] = $name; - $attributes['type'] = $this->getInputType(); - $attributes['value'] = $element->getCheckedValue(); - $closingBracket = $this->getInlineClosingBracket(); - - if ($element->isChecked()) { - $attributes['checked'] = 'checked'; - } - - $rendered = sprintf( - 'createAttributesString($attributes), - $closingBracket - ); - - if ($element->useHiddenElement()) { - $hiddenAttributes = [ - 'disabled' => $attributes['disabled'] ?? false, - 'name' => $attributes['name'], - 'value' => $element->getUncheckedValue(), - ]; - - $rendered = sprintf( - 'createAttributesString($hiddenAttributes), - $closingBracket - ) . $rendered; - } - - return $rendered; - } - - /** - * Return input type - */ - protected function getInputType(): string - { - return 'checkbox'; - } -} diff --git a/src/Form/View/Helper/FormCollection.php b/src/Form/View/Helper/FormCollection.php deleted file mode 100644 index e4322d3..0000000 --- a/src/Form/View/Helper/FormCollection.php +++ /dev/null @@ -1,394 +0,0 @@ - - */ - protected $validTagAttributes = [ - 'name' => true, - ]; - - /** - * If set to true, collections are automatically wrapped around a fieldset - */ - protected bool $shouldWrap = true; - - /** - * This is the default wrapper that the collection is wrapped into - */ - protected string $wrapper = '%2$s%1$s%3$s'; - - /** - * This is the wrapper that $mode === horizontal wraps into - */ - protected string $horizontalWrapper = '
    %2$s
    '; - - /** - * This is the default label-wrapper - * - * @var string - */ - protected $labelWrapper = '%s'; - - /** - * This is the horizontal mode label wrapper - */ - protected string $horizontalLabelWrapper = '%s'; - - /** - * Where shall the template-data be inserted into - * - * @var string - */ - protected $templateWrapper = ''; - - /** - * horizontal mode template wrapper - */ - protected string $horizontalTemplateWrapper = ''; - - /** - * The name of the default view helper that is used to render sub elements. - * - * @var string - */ - protected $defaultElementHelper = 'formrow'; - - /** - * The view helper used to render sub elements. - * - * @var null|HelperInterface - */ - protected $elementHelper; - - /** - * The view helper used to render sub fieldsets. - * - * @var null|HelperInterface - */ - protected $fieldsetHelper; - - private array $doctypesAllowedToHaveNameAttribute = [ - Doctype::HTML5 => true, - Doctype::XHTML5 => true, - ]; - - /** - * Invoke helper as function - * - * Proxies to {@link render()}. - * - * @template T as null|ElementInterface - * @psalm-param T $element - * @psalm-return (T is null ? self : string) - * @return string|FormCollection - */ - public function __invoke(?ElementInterface $element = null, bool $wrap = true) - { - if (! $element) { - return $this; - } - $this->setShouldWrap($wrap); - - return $this->render($element); - } - - /** - * Render a collection by iterating through all fieldsets and elements - */ - public function render(ElementInterface $element): string - { - $renderer = $this->getView(); - if ($renderer !== null && ! method_exists($renderer, 'plugin')) { - // Bail early if renderer is not pluggable - return ''; - } - - $markup = ''; - $templateMarkup = ''; - $elementHelper = $this->getElementHelper(); - assert(is_callable($elementHelper)); - $fieldsetHelper = $this->getFieldsetHelper(); - assert(is_callable($fieldsetHelper)); - - if ($element instanceof CollectionElement && $element->shouldCreateTemplate()) { - $templateMarkup = $this->renderTemplate($element); - } - // Limatus, may be to get into this workflow for nested fieldsets - foreach ($element->getIterator() as $elementOrFieldset) { - if ($elementOrFieldset instanceof FieldsetInterface) { - $markup .= $fieldsetHelper(element: $elementOrFieldset, wrap: $this->shouldWrap()); - } elseif ($elementOrFieldset instanceof ElementInterface) { - $markup .= $elementHelper(element: $elementOrFieldset); - } - } - - // Every collection is wrapped by a fieldset if needed - if ($this->shouldWrap) { - $attributes = $element->getAttributes(); - if (! isset($this->doctypesAllowedToHaveNameAttribute[$this->getDoctype()])) { - unset($attributes['name']); - } - $attributesString = $attributes !== [] ? ' ' . $this->createAttributesString($attributes) : ''; - - $label = $element->getLabel(); - $legend = ''; - - if (! empty($label)) { - if (null !== ($translator = $this->getTranslator())) { - $label = $translator->translate( - $label, - $this->getTranslatorTextDomain() - ); - } - - if (! $element instanceof LabelAwareInterface || ! $element->getLabelOption('disable_html_escape')) { - $escapeHtmlHelper = $this->getEscapeHtmlHelper(); - $label = $escapeHtmlHelper($label); - } - - $legend = sprintf( - $this->labelWrapper, - $label - ); - } - - $markup = sprintf( - $this->wrapper, - $markup, - $legend, - $templateMarkup, - $attributesString - ); - } else { - $markup .= $templateMarkup; - } - - return $markup; - } - - /** - * Only render a template - */ - public function renderTemplate(CollectionElement $collection): string - { - $elementHelper = $this->getElementHelper(); - assert(is_callable($elementHelper)); - $escapeHtmlAttribHelper = $this->getEscapeHtmlAttrHelper(); - $fieldsetHelper = $this->getFieldsetHelper(); - assert(is_callable($fieldsetHelper)); - - $templateMarkup = ''; - - $elementOrFieldset = $collection->getTemplateElement(); - - if ($elementOrFieldset instanceof FieldsetInterface) { - $templateMarkup .= $fieldsetHelper($elementOrFieldset, $this->shouldWrap()); - } elseif ($elementOrFieldset instanceof ElementInterface) { - $templateMarkup .= $elementHelper($elementOrFieldset); - } - - return sprintf( - $this->getTemplateWrapper(), - $escapeHtmlAttribHelper($templateMarkup) - ); - } - - /** - * If set to true, collections are automatically wrapped around a fieldset - * - * @return $this - */ - public function setShouldWrap(bool $wrap) - { - $this->shouldWrap = $wrap; - return $this; - } - - /** - * Get wrapped - */ - public function shouldWrap(): bool - { - return $this->shouldWrap; - } - - /** - * Sets the name of the view helper that should be used to render sub elements. - * - * @param string $defaultSubHelper The name of the view helper to set. - * @return $this - */ - public function setDefaultElementHelper(string $defaultSubHelper) - { - $this->defaultElementHelper = $defaultSubHelper; - return $this; - } - - /** - * Gets the name of the view helper that should be used to render sub elements. - */ - public function getDefaultElementHelper(): string - { - return $this->defaultElementHelper; - } - - /** - * Sets the element helper that should be used by this collection. - * - * @param HelperInterface $elementHelper The element helper to use. - * @return $this - */ - public function setElementHelper(HelperInterface $elementHelper) - { - $this->elementHelper = $elementHelper; - return $this; - } - - /** - * Retrieve the element helper. - * - * @throws RuntimeException - */ - protected function getElementHelper(): HelperInterface - { - if ($this->elementHelper) { - return $this->elementHelper; - } - - if ($this->view !== null && method_exists($this->view, 'plugin')) { - $this->elementHelper = $this->view->plugin($this->getDefaultElementHelper()); - } - - if (! $this->elementHelper instanceof HelperInterface) { - throw new RuntimeException( - 'Invalid element helper set in FormCollection. The helper must be an ' - . 'instance of Laminas\View\Helper\HelperInterface.' - ); - } - - return $this->elementHelper; - } - - /** - * Sets the fieldset helper that should be used by this collection. - * - * @param HelperInterface $fieldsetHelper The fieldset helper to use. - * @return $this - */ - public function setFieldsetHelper(HelperInterface $fieldsetHelper) - { - $this->fieldsetHelper = $fieldsetHelper; - return $this; - } - - /** - * Retrieve the fieldset helper. - */ - protected function getFieldsetHelper(): HelperInterface - { - if ($this->fieldsetHelper) { - return $this->fieldsetHelper; - } - - return $this; - } - - /** - * Get the wrapper for the collection - */ - public function getWrapper(): string - { - return $this->wrapper; - } - - /** - * Set the wrapper for this collection - * - * The string given will be passed through sprintf with the following three - * replacements: - * - * 1. The content of the collection - * 2. The label of the collection. If no label is given this will be an empty - * string - * 3. The template span-tag. This might also be an empty string - * - * The preset default is
    %2$s%1$s%3$s
    - * - * @return $this - */ - public function setWrapper(string $wrapper) - { - $this->wrapper = $wrapper; - - return $this; - } - - /** - * Set the label-wrapper - * The string will be passed through sprintf with the label as single - * parameter - * This defaults to '%s' - * - * @return $this - */ - public function setLabelWrapper(string $labelWrapper) - { - $this->labelWrapper = $labelWrapper; - - return $this; - } - - /** - * Get the wrapper for the label - */ - public function getLabelWrapper(): string - { - return $this->labelWrapper; - } - - /** - * Ge the wrapper for the template - */ - public function getTemplateWrapper(): string - { - return $this->templateWrapper; - } - - /** - * Set the string where the template will be inserted into - * - * This string will be passed through sprintf and has the template as single - * parameter - * - * THis defaults to '' - * - * @return $this - */ - public function setTemplateWrapper(string $templateWrapper) - { - $this->templateWrapper = $templateWrapper; - - return $this; - } -} diff --git a/src/Form/View/Helper/FormDelegator.php b/src/Form/View/Helper/FormDelegator.php new file mode 100644 index 0000000..723c305 --- /dev/null +++ b/src/Form/View/Helper/FormDelegator.php @@ -0,0 +1,48 @@ +prepare(); + } + + $formContent = ''; + + $renderer = $this->getView(); + assert($renderer instanceof PhpRenderer); + // what LayoutMode should this helper use?, + $layoutModeOption = $form->getOption('layout_mode'); + $this->setLayoutMode($layoutModeOption); + + foreach ($form as $element) { + if ($element instanceof FieldsetInterface) { + $formContent .= $renderer->formCollection($element); + } else { + $formContent .= $renderer->formRow($element); + } + } + + return $this->openTag($form) . $formContent . $this->closeTag(); + } +} diff --git a/src/Form/View/Helper/FormDelegatorFactory.php b/src/Form/View/Helper/FormDelegatorFactory.php new file mode 100644 index 0000000..afdfb67 --- /dev/null +++ b/src/Form/View/Helper/FormDelegatorFactory.php @@ -0,0 +1,25 @@ +get(EventManagerInterface::class); + $delegator = new FormDelegator(); + $delegator->setEventManager($em); + return $delegator; + } +} diff --git a/src/Form/View/Helper/FormElement.php b/src/Form/View/Helper/FormElement.php deleted file mode 100644 index 3c5eb14..0000000 --- a/src/Form/View/Helper/FormElement.php +++ /dev/null @@ -1,196 +0,0 @@ - 'formbutton', - Element\Captcha::class => 'formcaptcha', - Element\Csrf::class => 'formhidden', - Element\Collection::class => 'formcollection', - Element\DateTimeSelect::class => 'formdatetimeselect', - Element\DateSelect::class => 'formdateselect', - Element\MonthSelect::class => 'formmonthselect', - ]; - - /** - * Type map to view helper - * - * @var array - */ - protected $typeMap = [ - 'checkbox' => 'formcheckbox', - 'color' => 'formcolor', - 'date' => 'formdate', - 'datetime' => 'formdatetime', - 'datetime-local' => 'formdatetimelocal', - 'email' => 'formemail', - 'file' => 'formfile', - 'hidden' => 'formhidden', - 'image' => 'formimage', - 'month' => 'formmonth', - 'multi_checkbox' => 'formmulticheckbox', - 'number' => 'formnumber', - 'password' => 'formpassword', - 'radio' => 'formradio', - 'range' => 'formrange', - 'reset' => 'formreset', - 'search' => 'formsearch', - 'select' => 'formselect', - 'submit' => 'formsubmit', - 'tel' => 'formtel', - 'text' => 'formtext', - 'textarea' => 'formtextarea', - 'time' => 'formtime', - 'url' => 'formurl', - 'week' => 'formweek', - ]; - - /** - * Default helper name - * - * @var string - */ - protected $defaultHelper = self::DEFAULT_HELPER; - - /** - * Invoke helper as function - * - * Proxies to {@link render()}. - * - * @template T as null|ElementInterface - * @psalm-param T $element - * @psalm-return (T is null ? self : string) - * @return string|self - */ - public function __invoke(?ElementInterface $element = null) - { - if (! $element) { - return $this; - } - return $this->render($element); - } - - /** - * Render an element - * - * Introspects the element type and attributes to determine which - * helper to utilize when rendering. - */ - public function render(ElementInterface $element): string - { - $renderer = $this->getView(); - if ($renderer === null || ! method_exists($renderer, 'plugin')) { - // Bail early if renderer is not pluggable - return ''; - } - - $renderedInstance = $this->renderInstance($element); - - if ($renderedInstance !== null) { - return $renderedInstance; - } - - $renderedType = $this->renderType($element); - - if ($renderedType !== null) { - return $renderedType; - } - - return $this->renderHelper($this->defaultHelper, $element); - } - - /** - * Set default helper name - * - * @return $this - */ - public function setDefaultHelper(string $name) - { - $this->defaultHelper = $name; - - return $this; - } - - /** - * Add form element type to plugin map - * - * @return $this - */ - public function addType(string $type, string $plugin) - { - $this->typeMap[$type] = $plugin; - - return $this; - } - - /** - * Add instance class to plugin map - * - * @return $this - */ - public function addClass(string $class, string $plugin) - { - $this->classMap[$class] = $plugin; - - return $this; - } - - /** - * Render element by helper name - */ - protected function renderHelper(string $name, ElementInterface $element): string - { - $renderer = $this->getView(); - assert($renderer instanceof PhpRenderer); - $helper = $renderer->plugin($name); - assert(is_callable($helper)); - return $helper($element); - } - - /** - * Render element by instance map - */ - protected function renderInstance(ElementInterface $element): ?string - { - foreach ($this->classMap as $class => $pluginName) { - if ($element instanceof $class) { - return $this->renderHelper($pluginName, $element); - } - } - - return null; - } - - /** - * Render element by type map - */ - protected function renderType(ElementInterface $element): ?string - { - $type = $element->getAttribute('type'); - - if (isset($this->typeMap[$type])) { - return $this->renderHelper($this->typeMap[$type], $element); - } - - return null; - } -} diff --git a/src/Form/View/Helper/FormElementDelegator.php b/src/Form/View/Helper/FormElementDelegator.php new file mode 100644 index 0000000..51c68ee --- /dev/null +++ b/src/Form/View/Helper/FormElementDelegator.php @@ -0,0 +1,69 @@ +getView(); + if ($renderer === null || ! method_exists($renderer, 'plugin')) { + // Bail early if renderer is not pluggable + return ''; + } + + $event = new RenderEvent(Events::RenderElement->value, $this); + $event->setAttributes($element->getAttributes()) + ->setOptions($element->getOptions()); + + $event->setMarkup(parent::render($element)); + + $result = $this->getEventManager()->triggerEvent($event); + return $result->last(); + + // $renderedInstance = $this->renderInstance($element); + + // if ($renderedInstance !== null) { + // $event->setClassString(get_class($element)); + // $event->setMarkup($renderedInstance); + // $result = $this->getEventManager()->triggerEvent($event); + // if ($result->stopped()) { + // return $result->last(); + // } + // } + + // $renderedType = $this->renderType($element); + + // if ($renderedType !== null) { + // $event->setMarkup($renderedType); + // $result = $this->getEventManager()->triggerEvent($event); + // if ($result->stopped()) { + // return $result->last(); + // } + // } + + // $event->setMarkup($this->renderHelper($this->defaultHelper, $element)); + // $result = $this->getEventManager()->triggerEvent($event); + // if ($result->stopped()) { + // return $result->last(); + // } + } +} diff --git a/src/Form/View/Helper/FormElementDelegatorFactory.php b/src/Form/View/Helper/FormElementDelegatorFactory.php new file mode 100644 index 0000000..715828e --- /dev/null +++ b/src/Form/View/Helper/FormElementDelegatorFactory.php @@ -0,0 +1,28 @@ +get(EventManagerInterface::class); + $delegator = new FormElementDelegator(); + $delegator->setEventManager($em); + $listener = $container->get(RenderListenerInterface::class); + $listener->attach($em); + return $delegator; + } +} diff --git a/src/Form/View/Helper/FormGridCollection.php b/src/Form/View/Helper/FormGridCollection.php deleted file mode 100644 index 2a55f6b..0000000 --- a/src/Form/View/Helper/FormGridCollection.php +++ /dev/null @@ -1,394 +0,0 @@ - - */ - protected $validTagAttributes = []; - - /** - * If set to true, collections are automatically wrapped around a fieldset - */ - protected bool $shouldWrap = true; - - /** - * This is the default wrapper that the collection is wrapped into - */ - protected string $wrapper = '%2$s%1$s%3$s'; - - /** - * This is the default label-wrapper - * - * @var string - */ - protected $labelWrapper = '%s'; - - /** - * Where shall the template-data be inserted into - * - * @var string - */ - protected $templateWrapper = ''; - - /** - * horizontal mode template wrapper - */ - protected string $horizontalTemplateWrapper = ''; - - /** - * The name of the default view helper that is used to render sub elements. - * - * @var string - */ - protected $defaultElementHelper = 'formrow'; - - /** - * The view helper used to render sub elements. - * - * @var null|HelperInterface - */ - protected $elementHelper; - - /** - * The view helper used to render sub fieldsets. - * - * @var null|HelperInterface - */ - protected $fieldsetHelper; - - private array $doctypesAllowedToHaveNameAttribute = [ - Doctype::HTML5 => true, - Doctype::XHTML5 => true, - ]; - - /** - * Invoke helper as function - * - * Proxies to {@link render()}. - * - * @template T as null|ElementInterface - * @psalm-param T $element - * @psalm-return (T is null ? self : string) - * @return string|FormCollection - */ - public function __invoke(?ElementInterface $element = null, bool $wrap = true) - { - if (! $element) { - return $this; - } - $this->setShouldWrap($wrap); - - return $this->render($element); - } - - /** - * Render a collection by iterating through all fieldsets and elements - */ - public function render(ElementInterface $element): string - { - $renderer = $this->getView(); - if ($renderer !== null && ! method_exists($renderer, 'plugin')) { - // Bail early if renderer is not pluggable - return ''; - } - - $markup = ''; - $templateMarkup = ''; - $elementHelper = $this->getElementHelper(); - assert(is_callable($elementHelper)); - $gridsetHelper = $this->getGridsetHelper(); - assert(is_callable($gridsetHelper)); - $fieldsetHelper = $this->getFieldsetHelper(); - assert(is_callable($fieldsetHelper)); - - if ($element instanceof CollectionElement && $element->shouldCreateTemplate()) { - $templateMarkup = $this->renderTemplate($element); - } - - foreach ($element->getIterator() as $elementOrFieldset) { - if ($elementOrFieldset instanceof GridsetInterface) { - $markup .= $gridsetHelper(element: $elementOrFieldset, wrap: $this->shouldWrap()); - } elseif ($elementOrFieldset instanceof FieldsetInterface) { - $markup .= $fieldsetHelper(element: $elementOrFieldset, wrap: $this->shouldWrap()); - } elseif ($elementOrFieldset instanceof ElementInterface) { - $markup .= $elementHelper(element: $elementOrFieldset); - } - } - - // Every collection is wrapped by a row - if ($this->shouldWrap) { - $attributes = $element->getAttributes(); - if (! isset($this->doctypesAllowedToHaveNameAttribute[$this->getDoctype()])) { - unset($attributes['name']); - } - $attributesString = $attributes !== [] ? ' ' . $this->createAttributesString($attributes) : ''; - - $label = $element->getLabel(); - $legend = ''; - - if (! empty($label)) { - if (null !== ($translator = $this->getTranslator())) { - $label = $translator->translate( - $label, - $this->getTranslatorTextDomain() - ); - } - - if (! $element instanceof LabelAwareInterface || ! $element->getLabelOption('disable_html_escape')) { - $escapeHtmlHelper = $this->getEscapeHtmlHelper(); - $label = $escapeHtmlHelper($label); - } - - $legend = sprintf( - $this->labelWrapper, - $label - ); - } - - $markup = sprintf( - $this->wrapper, - $markup, - $legend, - $templateMarkup, - $attributesString - ); - } else { - $markup .= $templateMarkup; - } - - return $markup; - } - - /** - * Only render a template - */ - public function renderTemplate(CollectionElement $collection): string - { - $elementHelper = $this->getElementHelper(); - assert(is_callable($elementHelper)); - $escapeHtmlAttribHelper = $this->getEscapeHtmlAttrHelper(); - $fieldsetHelper = $this->getFieldsetHelper(); - assert(is_callable($fieldsetHelper)); - - $templateMarkup = ''; - - $elementOrFieldset = $collection->getTemplateElement(); - - if ($elementOrFieldset instanceof FieldsetInterface) { - $templateMarkup .= $fieldsetHelper($elementOrFieldset, $this->shouldWrap()); - } elseif ($elementOrFieldset instanceof ElementInterface) { - $templateMarkup .= $elementHelper($elementOrFieldset); - } - - return sprintf( - $this->getTemplateWrapper(), - $escapeHtmlAttribHelper($templateMarkup) - ); - } - - /** - * If set to true, collections are automatically wrapped around a fieldset - * - * @return $this - */ - public function setShouldWrap(bool $wrap) - { - $this->shouldWrap = $wrap; - return $this; - } - - /** - * Get wrapped - */ - public function shouldWrap(): bool - { - return $this->shouldWrap; - } - - public function getGridSetHelper(): HelperInterface - { - if ($this->view !== null && method_exists($this->view, 'plugin')) { - return $this->view->plugin('formGridCollection'); - } - return new $this(); - } - - /** - * Sets the name of the view helper that should be used to render sub elements. - * - * @param string $defaultSubHelper The name of the view helper to set. - * @return $this - */ - public function setDefaultElementHelper(string $defaultSubHelper) - { - $this->defaultElementHelper = $defaultSubHelper; - return $this; - } - - /** - * Gets the name of the view helper that should be used to render sub elements. - */ - public function getDefaultElementHelper(): string - { - return $this->defaultElementHelper; - } - - /** - * Sets the element helper that should be used by this collection. - * - * @param HelperInterface $elementHelper The element helper to use. - * @return $this - */ - public function setElementHelper(HelperInterface $elementHelper) - { - $this->elementHelper = $elementHelper; - return $this; - } - - /** - * Retrieve the element helper. - * - * @throws RuntimeException - */ - protected function getElementHelper(): HelperInterface - { - if ($this->elementHelper) { - return $this->elementHelper; - } - - if ($this->view !== null && method_exists($this->view, 'plugin')) { - $this->elementHelper = $this->view->plugin($this->getDefaultElementHelper()); - } - - if (! $this->elementHelper instanceof HelperInterface) { - throw new RuntimeException( - 'Invalid element helper set in FormCollection. The helper must be an ' - . 'instance of Laminas\View\Helper\HelperInterface.' - ); - } - - return $this->elementHelper; - } - - /** - * Sets the fieldset helper that should be used by this collection. - * - * @param HelperInterface $fieldsetHelper The fieldset helper to use. - * @return $this - */ - public function setFieldsetHelper(HelperInterface $fieldsetHelper) - { - $this->fieldsetHelper = $fieldsetHelper; - return $this; - } - - /** - * Retrieve the fieldset helper. - */ - protected function getFieldsetHelper(): HelperInterface - { - if ($this->fieldsetHelper) { - return $this->fieldsetHelper; - } - - return $this; - } - - /** - * Get the wrapper for the collection - */ - public function getWrapper(): string - { - return $this->wrapper; - } - - /** - * Set the wrapper for this collection - * - * The string given will be passed through sprintf with the following three - * replacements: - * - * 1. The content of the collection - * 2. The label of the collection. If no label is given this will be an empty - * string - * 3. The template span-tag. This might also be an empty string - * - * The preset default is
    %2$s%1$s%3$s
    - * - * @return $this - */ - public function setWrapper(string $wrapper) - { - $this->wrapper = $wrapper; - - return $this; - } - - /** - * Set the label-wrapper - * The string will be passed through sprintf with the label as single - * parameter - * This defaults to '%s' - * - * @return $this - */ - public function setLabelWrapper(string $labelWrapper) - { - $this->labelWrapper = $labelWrapper; - - return $this; - } - - /** - * Get the wrapper for the label - */ - public function getLabelWrapper(): string - { - return $this->labelWrapper; - } - - /** - * Ge the wrapper for the template - */ - public function getTemplateWrapper(): string - { - return $this->templateWrapper; - } - - /** - * Set the string where the template will be inserted into - * - * This string will be passed through sprintf and has the template as single - * parameter - * - * THis defaults to '' - * - * @return $this - */ - public function setTemplateWrapper(string $templateWrapper) - { - $this->templateWrapper = $templateWrapper; - return $this; - } -} diff --git a/src/Form/View/Helper/FormHorizontalElement.php b/src/Form/View/Helper/FormHorizontalElement.php deleted file mode 100644 index 6eab63f..0000000 --- a/src/Form/View/Helper/FormHorizontalElement.php +++ /dev/null @@ -1,21 +0,0 @@ -%s'; - - public function __invoke(?string $markup = null): string|self - { - $this->setView($this->view); - if ($markup !== null) { - return sprintf($markup, self::$rowWrapper); - } - return $this; - } -} diff --git a/src/Form/View/Helper/FormInput.php b/src/Form/View/Helper/FormInput.php deleted file mode 100644 index 75c5316..0000000 --- a/src/Form/View/Helper/FormInput.php +++ /dev/null @@ -1,186 +0,0 @@ - true, - 'accept' => true, - 'alt' => true, - 'autocomplete' => true, - 'autofocus' => true, - 'checked' => true, - 'dirname' => true, - 'disabled' => true, - 'form' => true, - 'formaction' => true, - 'formenctype' => true, - 'formmethod' => true, - 'formnovalidate' => true, - 'formtarget' => true, - 'height' => true, - 'list' => true, - 'max' => true, - 'maxlength' => true, - 'min' => true, - 'multiple' => true, - 'pattern' => true, - 'placeholder' => true, - 'readonly' => true, - 'required' => true, - 'size' => true, - 'src' => true, - 'step' => true, - 'type' => true, - 'value' => true, - 'width' => true, - ]; - /** - * Valid values for the input type - * - * @var array - */ - protected $validTypes = [ - 'text' => true, - 'button' => true, - 'checkbox' => true, - 'file' => true, - 'hidden' => true, - 'image' => true, - 'password' => true, - 'radio' => true, - 'reset' => true, - 'select' => true, - 'submit' => true, - 'color' => true, - 'date' => true, - 'datetime' => true, - 'datetime-local' => true, - 'email' => true, - 'month' => true, - 'number' => true, - 'range' => true, - 'search' => true, - 'tel' => true, - 'time' => true, - 'url' => true, - 'week' => true, - ]; - - protected static string $horizontalWrapper = '
    %s
    '; - - protected static string $inputGroupWrapper = '
    %s%s
    '; - - protected static string $inputGroupTextWrapper = '
    %s
    '; - - /** - * Invoke helper as functor - * - * Proxies to {@link render()}. - * - * @template T as null|ElementInterface - * @psalm-param T $element - * @psalm-return (T is null ? self : string) - * @return string|FormInput - */ - public function __invoke(?ElementInterface $element = null) - { - if (! $element) { - return $this; - } - return $this->render($element); - } - - /** - * Force an id, if possible and use the original service to do its work - */ - public function render(ElementInterface $element): string - { - // force an id to prevent the input from being wrapped inside the label, we never want that - if ($element->getName() && ! $element->hasAttribute('id')) { - $element->setAttribute('id', $element->getName()); - } - // default rendering handles the input attributes - $markup = $this->defaultRender($element); - if ($element instanceof Form\ModeAwareInterface) { - $mode = $element->getMode(); - if (Form\ModeAwareInterface::HORIZONTAL_MODE === $mode) { - // if this is horizontal mode we need to wrap this and use the correct attribs - $markup = sprintf( - self::$horizontalWrapper, - $this->createAttributesString($element->getHorizontalAttributes()), - $markup - ); - } - if (Form\ModeAwareInterface::INLINE_MODE === $mode) { - $options = $element->getOptions(); - if (isset($options['input_group']) && isset($options['input_group_text'])) { - $inputText = sprintf( - self::$inputGroupTextWrapper, - $options['input_group_text'], - ); - $markup = sprintf( - self::$inputGroupWrapper, - $inputText, - $markup - ); - } - } - // This should be last, "normally" we have fewer of these than other elements - // if ( - // $element instanceof Form\Element\Submit - // || $element instanceof Form\Element\Button - // ) { - - // } - } - - return $markup; - } - - /** - * Render a form element from the provided $element - * - * @throws Exception\DomainException - */ - public function defaultRender(ElementInterface $element): string - { - $name = $element->getName(); - if ($name === null || $name === '') { - throw new Exception\DomainException(sprintf( - '%s requires that the element has an assigned name; none discovered', - __METHOD__ - )); - } - - $attributes = $element->getAttributes(); - $attributes['name'] = $name; - $type = $this->getType($element); - $attributes['type'] = $type; - $attributes['value'] = $element->getValue(); - if ('password' === $type) { - $attributes['value'] = ''; - } - - return sprintf( - 'createAttributesString($attributes), - $this->getInlineClosingBracket() - ); - } -} diff --git a/src/Form/View/Helper/FormInputDelegatorFactory.php b/src/Form/View/Helper/FormInputDelegatorFactory.php new file mode 100644 index 0000000..988c053 --- /dev/null +++ b/src/Form/View/Helper/FormInputDelegatorFactory.php @@ -0,0 +1,23 @@ +get(EventManagerInterface::class); + $delegator = new FormInputDelegator(); + $delegator->setEventManager($em); + $listener = $container->get(RenderListenerInterface::class); + $listener->attach($em); + return $delegator; + } +} diff --git a/src/Form/View/Helper/FormInputDelegatorphp b/src/Form/View/Helper/FormInputDelegatorphp new file mode 100644 index 0000000..f980d6f --- /dev/null +++ b/src/Form/View/Helper/FormInputDelegatorphp @@ -0,0 +1,72 @@ +%s'; + + protected static string $inputGroupWrapper = '
    %s%s
    '; + + protected static string $inputGroupTextWrapper = '
    %s
    '; + + /** + * Force an id, if possible and use the original service to do its work + */ + public function render(ElementInterface $element): string + { + // force an id to prevent the input from being wrapped inside the label, we never want that + if ($element->getName() && ! $element->hasAttribute('id')) { + $element->setAttribute('id', $element->getName()); + } + // default rendering handles the input attributes + $markup = parent::render($element); + if ($element instanceof Form\ModeAwareInterface) { + // $mode = $element->getMode(); + // if (Form\ModeAwareInterface::HORIZONTAL_MODE === $mode) { + // // if this is horizontal mode we need to wrap this and use the correct attribs + // $markup = sprintf( + // self::$horizontalWrapper, + // $this->createAttributesString($element->getHorizontalAttributes()), + // $markup + // ); + // } + // if (Form\ModeAwareInterface::INLINE_MODE === $mode) { + // $options = $element->getOptions(); + // if (isset($options['input_group']) && isset($options['input_group_text'])) { + // $inputText = sprintf( + // self::$inputGroupTextWrapper, + // $options['input_group_text'], + // ); + // $markup = sprintf( + // self::$inputGroupWrapper, + // $inputText, + // $markup + // ); + // } + // } + // This should be last, "normally" we have fewer of these than other elements + // if ( + // $element instanceof Form\Element\Submit + // || $element instanceof Form\Element\Button + // ) { + + // } + } + + return $markup; + } +} diff --git a/src/Form/View/Helper/FormLabel.php b/src/Form/View/Helper/FormLabel.php deleted file mode 100644 index f829e1d..0000000 --- a/src/Form/View/Helper/FormLabel.php +++ /dev/null @@ -1,11 +0,0 @@ -setLabelPosition($labelPosition); - } - - return $this->render($element); - } - - /** - * Render a form element from the provided $element - * - * @throws Exception\InvalidArgumentException - */ - public function render(ElementInterface $element): string - { - if (! $element instanceof MultiCheckboxElement) { - throw new Exception\InvalidArgumentException(sprintf( - '%s requires that the element is of type Laminas\Form\Element\MultiCheckbox', - __METHOD__ - )); - } - - $name = static::getName($element); - - $options = $element->getValueOptions(); - - $attributes = $element->getAttributes(); - $attributes['name'] = $name; - $attributes['type'] = $this->getInputType(); - $selectedOptions = (array) $element->getValue(); - - $rendered = $this->renderOptions($element, $options, $selectedOptions, $attributes); - - // Render hidden element - if ($element->useHiddenElement()) { - $rendered = $this->renderHiddenElement($element) . $rendered; - } - - return $rendered; - } - - /** - * Render options - */ - protected function renderOptions( - MultiCheckboxElement $element, - array $options, - array $selectedOptions, - array $attributes - ): string { - $escapeHtmlHelper = $this->getEscapeHtmlHelper(); - $labelHelper = $this->getLabelHelper(); - $labelClose = $labelHelper->closeTag(); - $labelPosition = $this->getLabelPosition(); - $globalLabelAttributes = []; - $closingBracket = $this->getInlineClosingBracket(); - - if ($element instanceof LabelAwareInterface) { - $globalLabelAttributes = $element->getLabelAttributes(); - } - - if (empty($globalLabelAttributes)) { - $globalLabelAttributes = $this->labelAttributes; - } - - $combinedMarkup = []; - $count = 0; - - foreach ($options as $key => $optionSpec) { - $count++; - if ($count > 1 && array_key_exists('id', $attributes)) { - unset($attributes['id']); - } - - $value = ''; - $label = ''; - $inputAttributes = $attributes; - $labelAttributes = $globalLabelAttributes; - $selected = isset($inputAttributes['selected']) - && $inputAttributes['type'] !== 'radio' - && $inputAttributes['selected']; - $disabled = isset($inputAttributes['disabled']) && $inputAttributes['disabled']; - - if (is_scalar($optionSpec)) { - $optionSpec = [ - 'label' => $optionSpec, - 'value' => $key, - ]; - } - - if (isset($optionSpec['value'])) { - $value = $optionSpec['value']; - } - - if (isset($optionSpec['label'])) { - $label = $optionSpec['label']; - } - - if (isset($optionSpec['selected'])) { - $selected = $optionSpec['selected']; - } - - if (isset($optionSpec['disabled'])) { - $disabled = $optionSpec['disabled']; - } - - if (isset($optionSpec['label_attributes'])) { - $labelAttributes = isset($labelAttributes) - ? array_merge($labelAttributes, $optionSpec['label_attributes']) - : $optionSpec['label_attributes']; - } - - if (isset($optionSpec['attributes'])) { - $inputAttributes = array_merge($inputAttributes, $optionSpec['attributes']); - } - - if (in_array($value, $selectedOptions)) { - $selected = true; - } - - $inputAttributes['value'] = $value; - $inputAttributes['checked'] = $selected; - $inputAttributes['disabled'] = $disabled; - - $input = sprintf( - 'createAttributesString($inputAttributes), - $closingBracket - ); - - if (null !== ($translator = $this->getTranslator())) { - $label = $translator->translate( - $label, - $this->getTranslatorTextDomain() - ); - } - - if (! $element instanceof LabelAwareInterface || ! $element->getLabelOption('disable_html_escape')) { - $label = $escapeHtmlHelper($label); - } - - $labelOpen = $labelHelper->openTag($labelAttributes); - $template = $labelOpen . '%s%s' . $labelClose; - $markup = match ($labelPosition) { - self::LABEL_PREPEND => sprintf($template, $label, $input), - default => sprintf($template, $input, $label), - }; - - $combinedMarkup[] = $markup; - } - - return implode($this->getSeparator(), $combinedMarkup); - } - - /** - * Render a hidden element for empty/unchecked value - */ - protected function renderHiddenElement(MultiCheckboxElement $element): string - { - $closingBracket = $this->getInlineClosingBracket(); - - $uncheckedValue = $element->getUncheckedValue() ?: $this->uncheckedValue; - - $hiddenAttributes = [ - 'name' => $element->getName(), - 'value' => $uncheckedValue, - ]; - - return sprintf( - 'createAttributesString($hiddenAttributes), - $closingBracket - ); - } - - /** - * Sets the attributes applied to option label. - * - * @return $this - */ - public function setLabelAttributes(?array $attributes) - { - $this->labelAttributes = $attributes; - return $this; - } - - /** - * Returns the attributes applied to each option label. - * - * @return array|null - */ - public function getLabelAttributes(): ?array - { - return $this->labelAttributes; - } - - /** - * Set value for labelPosition - * - * @throws Exception\InvalidArgumentException - * @return $this - */ - public function setLabelPosition(string $labelPosition) - { - $labelPosition = strtolower($labelPosition); - if (! in_array($labelPosition, [self::LABEL_APPEND, self::LABEL_PREPEND])) { - throw new Exception\InvalidArgumentException(sprintf( - '%s expects either %s::LABEL_APPEND or %s::LABEL_PREPEND; received "%s"', - __METHOD__, - self::class, - self::class, - $labelPosition - )); - } - $this->labelPosition = $labelPosition; - - return $this; - } - - /** - * Get position of label - */ - public function getLabelPosition(): string - { - return $this->labelPosition; - } - - /** - * Set separator string for checkbox elements - * - * @return $this - */ - public function setSeparator(string $separator) - { - $this->separator = $separator; - return $this; - } - - /** - * Get separator for checkbox elements - */ - public function getSeparator(): string - { - return $this->separator; - } - - /** - * Sets the option for prefixing the element with a hidden element - * for the unset value. - * - * @return $this - */ - public function setUseHiddenElement(bool $useHiddenElement) - { - $this->useHiddenElement = $useHiddenElement; - return $this; - } - - /** - * Returns the option for prefixing the element with a hidden element - * for the unset value. - */ - public function getUseHiddenElement(): bool - { - return $this->useHiddenElement; - } - - /** - * Sets the unchecked value used when "UseHiddenElement" is turned on. - * - * @return $this - */ - public function setUncheckedValue(string $value) - { - $this->uncheckedValue = $value; - return $this; - } - - /** - * Returns the unchecked value used when "UseHiddenElement" is turned on. - */ - public function getUncheckedValue(): string - { - return $this->uncheckedValue; - } - - /** - * Return input type - */ - protected function getInputType(): string - { - return 'checkbox'; - } - - /** - * Get element name - * - * @throws Exception\DomainException - */ - protected static function getName(ElementInterface $element): string - { - $name = $element->getName(); - if ($name === null || $name === '') { - throw new Exception\DomainException(sprintf( - '%s requires that the element has an assigned name; none discovered', - __METHOD__ - )); - } - return $name . '[]'; - } - - /** - * Retrieve the FormInput helper - */ - protected function getInputHelper(): FormInput - { - if (null !== $this->inputHelper) { - return $this->inputHelper; - } - - if (method_exists($this->view, 'plugin')) { - $this->inputHelper = $this->view->plugin('form_input'); - } - // this will be using a Laminas FormInput - if (! $this->inputHelper instanceof FormInput) { - $this->inputHelper = new FormInput(); - } - - return $this->inputHelper; - } - - /** - * Retrieve the FormLabel helper - */ - protected function getLabelHelper(): FormLabel - { - if ($this->labelHelper) { - return $this->labelHelper; - } - - if (method_exists($this->view, 'plugin')) { - $this->labelHelper = $this->view->plugin('form_label'); - } - - if (! $this->labelHelper instanceof FormLabel) { - $this->labelHelper = new FormLabel(); - } - - return $this->labelHelper; - } -} diff --git a/src/Form/View/Helper/FormRadio.php b/src/Form/View/Helper/FormRadio.php deleted file mode 100644 index e942196..0000000 --- a/src/Form/View/Helper/FormRadio.php +++ /dev/null @@ -1,26 +0,0 @@ -getName(); - } -} diff --git a/src/Form/View/Helper/FormRow.php b/src/Form/View/Helper/FormRow.php deleted file mode 100644 index e922c1c..0000000 --- a/src/Form/View/Helper/FormRow.php +++ /dev/null @@ -1,431 +0,0 @@ -getLabelPosition(); - } - - if ($renderErrors !== null) { - $this->setRenderErrors($renderErrors); - } - - if ($partial !== null) { - $this->setPartial($partial); - } - - return $this->render($element, $labelPosition); - } - - public function render( - Form\ElementInterface $element, - ?string $labelPosition = null - ): string { - $escapeHtmlHelper = $this->getEscapeHtmlHelper(); - $labelHelper = $this->getLabelHelper(); - $elementHelper = $this->getElementHelper(); - $elementErrorsHelper = $this->getElementErrorsHelper(); - - $label = $element->getLabel(); - $inputErrorClass = $this->getInputErrorClass(); - - if ($labelPosition === null) { - $labelPosition = $this->labelPosition; - } - - if (isset($label) && '' !== $label) { - // Translate the label - if (null !== ($translator = $this->getTranslator())) { - $label = $translator->translate($label, $this->getTranslatorTextDomain()); - } - } - - // Does this element have errors ? - if ($element->getMessages() && $inputErrorClass) { - $classAttributes = $element->hasAttribute('class') ? $element->getAttribute('class') . ' ' : ''; - $classAttributes .= $inputErrorClass; - - $element->setAttribute('class', $classAttributes); - } - - if ($this->partial) { - $vars = [ - 'element' => $element, - 'label' => $label, - 'labelAttributes' => $this->labelAttributes, - 'labelPosition' => $labelPosition, - 'renderErrors' => $this->renderErrors, - ]; - - return $this->view->render($this->partial, $vars); - } - - $elementErrors = ''; - if ($this->renderErrors) { - $elementErrors = $elementErrorsHelper->render($element); - } - - /** - * Limatus, $elementString holds the return of FormInput rendering - * If the element needs after the label is rendered, ie the - * element and label need inserted into a div it must happen below - */ - $elementString = $elementHelper->render($element); - - // hidden elements do not need a