Passed
Push — master ( 73547b...a0a706 )
by Andreas
36:17
created

detect_schema()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 26
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 5.0042

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 18
c 1
b 0
f 0
nc 5
nop 2
dl 0
loc 26
ccs 17
cts 18
cp 0.9444
crap 5.0042
rs 9.3554
1
<?php
2
/**
3
 * @package midgard.admin.asgard
4
 * @author CONTENT CONTROL http://www.contentcontrol-berlin.de/
5
 * @copyright CONTENT CONTROL http://www.contentcontrol-berlin.de/
6
 * @license http://www.gnu.org/licenses/gpl.html GNU General Public License
7
 */
8
9
use midcom\datamanager\schemadb;
10
use midcom\datamanager\validation\phpValidator;
11
12
/**
13
 * Helper class to create a DM schema from component's config
14
 *
15
 * @package midgard.admin.asgard
16
 */
17
class midgard_admin_asgard_schemadb_config
18
{
19
    private $component;
20
21
    /**
22
     * @var midcom_helper_configuration
23
     */
24
    private $config;
25
26
    private $is_folder;
27
28 2
    public function __construct(string $component, midcom_helper_configuration $config, bool $is_folder)
29
    {
30 2
        $this->component = $component;
31 2
        $this->config = $config;
32 2
        $this->is_folder = $is_folder;
33 2
    }
34
35 2
    public function create() : schemadb
36
    {
37
        // Load SchemaDb
38 2
        $schemadb_config_path = midcom::get()->componentloader->path_to_snippetpath($this->component) . '/config/config_schemadb.inc';
39 2
        $schemaname = 'default';
40
41 2
        if (file_exists($schemadb_config_path)) {
42
            $schemadb = schemadb::from_path('file:/' . str_replace('.', '/', $this->component) . '/config/config_schemadb.inc');
43
            if ($schemadb->has('config')) {
44
                $schemaname = 'config';
45
            }
46
            // TODO: Log error on deprecated config schema?
47
        } else {
48
            // Create dummy schema. Naughty component would not provide config schema.
49 2
            $schemadb = new schemadb(['default' => [
50 2
                'description' => 'configuration for ' . $this->component,
51
                'fields'      => []
52
            ]]);
53
        }
54 2
        $schema = $schemadb->get($schemaname);
55 2
        $schema->set('l10n_db', $this->component);
56 2
        $fields = $schema->get('fields');
57
58 2
        foreach ($this->config->_global as $key => $value) {
59
            // try to sniff what fields are missing in schema
60 2
            if (!array_key_exists($key, $fields)) {
61 2
                $fields[$key] = $this->detect_schema($key, $value);
62
            }
63
64 2
            if (   !isset($this->config->_local[$key])
65 2
                || $this->config->_local[$key] == $this->config->_global[$key]) {
66
                // No local configuration setting, note to user that this is the global value
67 2
                $fields[$key]['title'] = $schema->get_l10n()->get($fields[$key]['title']);
68 2
                $fields[$key]['title'] .= " <span class=\"global\">(" . midcom::get()->i18n->get_string('global value', 'midgard.admin.asgard') .")</span>";
69
            }
70
        }
71
72
        // Prepare defaults
73 2
        $config = array_intersect_key($this->config->get_all(), $fields);
74 2
        foreach ($config as $key => $value) {
75 2
            if (is_array($value)) {
76 2
                $fields[$key]['default'] = var_export($value, true);
77
            } else {
78 2
                if ($fields[$key]['widget'] == 'checkbox') {
79 2
                    $value = (boolean) $value;
80
                }
81 2
                $fields[$key]['default'] = $value;
82
            }
83
        }
84 2
        $schema->set('fields', $fields);
85 2
        $validation = $schema->get('validation') ?: [];
86 2
        $validation[] = [
87 2
            'callback' => [$this, 'check_config'],
88
        ];
89 2
        $schema->set('validation', $validation);
90 2
        return $schemadb;
91
    }
92
93 2
    private function detect_schema(string $key, $value) : array
94
    {
95
        $result = [
96 2
            'title'  => $key,
97 2
            'type'   => 'text',
98 2
            'widget' => 'text',
99
        ];
100
101 2
        $type = gettype($value);
102 2
        switch ($type) {
103 2
            case "boolean":
104 2
                $result['type'] = 'boolean';
105 2
                $result['widget'] = 'checkbox';
106 2
                break;
107 2
            case "array":
108 2
                $result['widget'] = 'textarea';
109
                // Complex Array fields should be readonly for topics as we cannot store and read them properly with parameters
110 2
                $result['readonly'] = $this->is_folder;
111 2
                break;
112 2
            case 'string':
113 2
                if (preg_match("/\n/", $value)) {
114
                    $result['widget'] = 'textarea';
115
                }
116
        }
117
118 2
        return $result;
119
    }
120
121
    /**
122
     * Ensure the configuration is valid (form validation callback)
123
     */
124
    public function check_config(array $values)
125
    {
126
        $current = $this->config->get_all();
127
        $result = [];
128
        foreach ($values as $key => $newval) {
129
            if ($newval === '' || !isset($current[$key])) {
130
                continue;
131
            }
132
            $val = $current[$key];
133
134
            if (is_array($val)) {
135
                $code = "<?php\n\$data = array({$newval}\n);\n?>";
136
                if ($error = phpValidator::lint($code)) {
137
                    $result[$key] = $error;
138
                }
139
            }
140
        }
141
        return $result ?: true;
142
    }
143
}