summaryrefslogtreecommitdiffstats
path: root/library/Icinga/Web/Form/Decorator/FormHints.php
blob: 2a0f1932df7b94d37a8d3b0264ac4fefd901b1c0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
<?php
/* Icinga Web 2 | (c) 2015 Icinga Development Team | GPLv2+ */

namespace Icinga\Web\Form\Decorator;

use Zend_Form_Decorator_Abstract;
use Icinga\Web\Form;

/**
 * Decorator to add a list of hints at the top or bottom of a form
 *
 * The hint for required form elements is automatically being handled.
 */
class FormHints extends Zend_Form_Decorator_Abstract
{
    /**
     * A list of element class names to be ignored when detecting which message to use to describe required elements
     *
     * @var array
     */
    protected $blacklist;

    /**
     * {@inheritdoc}
     */
    public function __construct($options = null)
    {
        parent::__construct($options);
        $this->blacklist = array(
            'Zend_Form_Element_Hidden',
            'Zend_Form_Element_Submit',
            'Zend_Form_Element_Button',
            'Icinga\Web\Form\Element\Note',
            'Icinga\Web\Form\Element\Button',
            'Icinga\Web\Form\Element\CsrfCounterMeasure'
        );
    }

    /**
     * Render form hints
     *
     * @param   string      $content    The html rendered so far
     *
     * @return  ?string                  The updated html
     */
    public function render($content = '')
    {
        $form = $this->getElement();
        if (! $form instanceof Form) {
            return $content;
        }

        $view = $form->getView();
        if ($view === null) {
            return $content;
        }

        $hints = $this->recurseForm($form, $entirelyRequired);
        if ($entirelyRequired !== null) {
            $hints[] = sprintf(
                $form->getView()->translate('%s Required field'),
                $form->getRequiredCue()
            );
        }

        if (empty($hints)) {
            return $content;
        }

        $html = '<ul class="form-info">';
        foreach ($hints as $hint) {
            if (is_array($hint)) {
                list($hint, $properties) = $hint;
                $html .= '<li' . $view->propertiesToString($properties) . '>' . $view->escape($hint) . '</li>';
            } else {
                $html .= '<li>' . $view->escape($hint) . '</li>';
            }
        }

        switch ($this->getPlacement()) {
            case self::APPEND:
                return $content . $html . '</ul>';
            case self::PREPEND:
                return $html . '</ul>' . $content;
        }
    }

    /**
     * Recurse the given form and return the hints for it and all of its subforms
     *
     * @param   Form    $form               The form to recurse
     * @param   mixed   $entirelyRequired   Set by reference, true means all elements in the hierarchy are
     *                                       required, false only a partial subset and null none at all
     * @param   bool    $elementsPassed     Whether there were any elements passed during the recursion until now
     *
     * @return  array
     */
    protected function recurseForm(Form $form, &$entirelyRequired = null, $elementsPassed = false)
    {
        $requiredLabels = array();
        if ($form->getRequiredCue() !== null) {
            $partiallyRequired = $partiallyOptional = false;
            foreach ($form->getElements() as $element) {
                if (! in_array($element->getType(), $this->blacklist)) {
                    if (! $element->isRequired()) {
                        $partiallyOptional = true;
                        if ($entirelyRequired) {
                            $entirelyRequired = false;
                        }
                    } else {
                        $partiallyRequired = true;
                        if (($label = $element->getDecorator('label')) !== false) {
                            $requiredLabels[] = $label;
                        }
                    }
                }
            }

            if (! $elementsPassed) {
                $elementsPassed = $partiallyRequired || $partiallyOptional;
                if ($entirelyRequired === null && $partiallyRequired) {
                    $entirelyRequired = ! $partiallyOptional;
                }
            } elseif ($entirelyRequired === null && $partiallyRequired) {
                $entirelyRequired = false;
            }
        }

        $hints = array($form->getHints());
        foreach ($form->getSubForms() as $subForm) {
            $hints[] = $this->recurseForm($subForm, $entirelyRequired, $elementsPassed);
        }

        if ($entirelyRequired) {
            foreach ($requiredLabels as $label) {
                $label->setRequiredSuffix('');
            }
        }

        return call_user_func_array('array_merge', $hints);
    }
}