summaryrefslogtreecommitdiffstats
path: root/application/forms/ConfigForm.php
blob: 8b0c5f9c842a38a7be2402ec70fb206ccd0b12f0 (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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
<?php
/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */

namespace Icinga\Forms;

use Exception;
use Zend_Form_Decorator_Abstract;
use Icinga\Application\Config;
use Icinga\Application\Hook\ConfigFormEventsHook;
use Icinga\Exception\ConfigurationError;
use Icinga\Web\Form;
use Icinga\Web\Notification;

/**
 * Form base-class providing standard functionality for configuration forms
 */
class ConfigForm extends Form
{
    /**
     * The configuration to work with
     *
     * @var Config
     */
    protected $config;

    /**
     * {@inheritdoc}
     *
     * Values from subforms are directly added to the returned values array instead of being grouped by the subforms'
     * names.
     */
    public function getValues($suppressArrayNotation = false)
    {
        $values = parent::getValues($suppressArrayNotation);
        foreach (array_keys($this->_subForms) as $name) {
            // Zend returns values from subforms grouped by their names, but we want them flat
            $values = array_merge($values, $values[$name]);
            unset($values[$name]);
        }
        return $values;
    }

    /**
     * Set the configuration to use when populating the form or when saving the user's input
     *
     * @param   Config      $config     The configuration to use
     *
     * @return  $this
     */
    public function setIniConfig(Config $config)
    {
        $this->config = $config;
        return $this;
    }

    public function isValid($formData)
    {
        $valid = parent::isValid($formData);

        if ($valid && ConfigFormEventsHook::runIsValid($this) === false) {
            foreach (ConfigFormEventsHook::getLastErrors() as $msg) {
                $this->error($msg);
            }

            $valid = false;
        }

        return $valid;
    }

    public function onSuccess()
    {
        $sections = array();
        foreach (static::transformEmptyValuesToNull($this->getValues()) as $sectionAndPropertyName => $value) {
            list($section, $property) = explode('_', $sectionAndPropertyName, 2);
            $sections[$section][$property] = $value;
        }

        foreach ($sections as $section => $config) {
            if ($this->isEmptyConfig($config)) {
                $this->config->removeSection($section);
            } else {
                $this->config->setSection($section, $config);
            }
        }

        if ($this->save()) {
            Notification::success($this->translate('New configuration has successfully been stored'));
        } else {
            return false;
        }

        if (ConfigFormEventsHook::runOnSuccess($this) === false) {
            Notification::error($this->translate(
                'Configuration successfully stored. Though, one or more module hooks failed to run.'
                . ' See logs for details'
            ));
        }
    }

    public function onRequest()
    {
        $values = array();
        foreach ($this->config as $section => $properties) {
            foreach ($properties as $name => $value) {
                $values[$section . '_' . $name] = $value;
            }
        }

        $this->populate($values);
    }

    /**
     * Persist the current configuration to disk
     *
     * If an error occurs the user is shown a view describing the issue and displaying the raw INI configuration.
     *
     * @return  bool                    Whether the configuration could be persisted
     */
    public function save()
    {
        try {
            $this->writeConfig($this->config);
        } catch (ConfigurationError $e) {
            $this->addError($e->getMessage());

            return false;
        } catch (Exception $e) {
            $this->addDecorator('ViewScript', array(
                'viewModule'    => 'default',
                'viewScript'    => 'showConfiguration.phtml',
                'errorMessage'  => $e->getMessage(),
                'configString'  => $this->config,
                'filePath'      => $this->config->getConfigFile(),
                'placement'     => Zend_Form_Decorator_Abstract::PREPEND
            ));
            return false;
        }

        return true;
    }

    /**
     * Write the configuration to disk
     *
     * @param   Config  $config
     */
    protected function writeConfig(Config $config)
    {
        $config->saveIni();
    }

    /**
     * Get whether the given config is empty or has only empty values
     *
     * @param array|Config $config
     *
     * @return bool
     */
    protected function isEmptyConfig($config)
    {
        if ($config instanceof Config) {
            $config = $config->toArray();
        }

        foreach ($config as $value) {
            if ($value !== null) {
                return false;
            }
        }

        return true;
    }

    /**
     * Transform all empty values of the given array to null
     *
     * @param   array   $values
     *
     * @return  array
     */
    public static function transformEmptyValuesToNull(array $values)
    {
        array_walk($values, function (&$v) {
            if ($v === '' || $v === false || $v === array()) {
                $v = null;
            }
        });

        return $values;
    }
}