DatabaseConfig   A
last analyzed

Complexity

Total Complexity 18

Size/Duplication

Total Lines 129
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 44
c 0
b 0
f 0
dl 0
loc 129
rs 10
wmc 18

5 Methods

Rating   Name   Duplication   Size   Complexity  
A valueFromString() 0 13 4
A dump() 0 20 6
A valueToString() 0 13 4
A read() 0 18 3
A __construct() 0 4 1
1
<?php
2
/**
3
 * BEdita, API-first content management framework
4
 * Copyright 2016 ChannelWeb Srl, Chialab Srl
5
 *
6
 * This file is part of BEdita: you can redistribute it and/or modify
7
 * it under the terms of the GNU Lesser General Public License as published
8
 * by the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * See LICENSE.LGPL or <http://gnu.org/licenses/lgpl-3.0.html> for more details.
12
 */
13
namespace BEdita\Core\Configure\Engine;
14
15
use Cake\Core\Configure\ConfigEngineInterface;
16
use Cake\Database\Exception;
17
use Cake\Datasource\ModelAwareTrait;
18
19
/**
20
 * BEdita database configuration engine.
21
 *
22
 * Configuration parameters are stored in `config` table
23
 *
24
 * Each `config.name` in database should be a first level key in Configure (without dots)
25
 * Some keys like 'Datasources', 'Cache' and 'EmailTransport' are reserved and may not be stored in database
26
 * Instead each corresponding `config.content` field should be either a string or JSON
27
 * `config.context` represents a group of parameters loaded via Configure::load($key, 'database')
28
 *
29
 * DatabaseConfig also manipulates how 'null', 'true', 'false' are handled.
30
 * These values will be converted to their boolean equivalents or to null.
31
 *
32
 * @since 4.0.0
33
 * @property \BEdita\Core\Model\Table\ConfigTable $Config
34
 */
35
class DatabaseConfig implements ConfigEngineInterface
36
{
37
    use ModelAwareTrait;
38
39
    /**
40
     * Application id
41
     *
42
     * @var int
43
     */
44
    protected $applicationId = null;
45
46
    /**
47
     * Reserved keys not storable in database
48
     *
49
     * @var array
50
     */
51
    public const RESERVED_KEYS = ['Datasources', 'Cache', 'EmailTransport', 'Session', 'Error', 'App'];
52
53
    /**
54
     * Setup application `id` if provided.
55
     *
56
     * @param int $applicationId Application id
57
     */
58
    public function __construct($applicationId = null)
59
    {
60
        $this->applicationId = $applicationId;
61
        $this->loadModel('Config');
62
    }
63
64
    /**
65
     * Read configuration from database of `$key` parameters group
66
     * and return the results as an array.
67
     * Parameter group is mapped to database column `config.context`.
68
     *
69
     * @param string|null $key The group of parameters to read from database (see `config.context`).
70
     * @return array Parsed configuration values.
71
     */
72
    public function read($key): array
73
    {
74
        return $this->Config->fetchConfig($this->applicationId, $key)
75
            ->all()
76
            ->filter(function (array $item): bool {
77
                return !in_array($item['name'], self::RESERVED_KEYS);
78
            })
79
            ->map(function (array $item): array {
80
                $content = json_decode($item['content'], true);
81
                if ($content === null && json_last_error() !== JSON_ERROR_NONE) {
82
                    $content = static::valueFromString($item['content']);
83
                }
84
                $item['content'] = $content;
85
86
                return $item;
87
            })
88
            ->combine('name', 'content')
89
            ->toArray();
90
    }
91
92
    /**
93
     * Dumps Configure data array to Database.
94
     *
95
     * @param string $key The group parameter to write to.
96
     * @param array $data The data to write.
97
     * @return bool Success.
98
     */
99
    public function dump($key, array $data): bool
100
    {
101
        $context = $key;
102
        $entities = [];
103
        foreach ($data as $name => $content) {
104
            if (in_array($name, self::RESERVED_KEYS)) {
105
                continue;
106
            }
107
            $content = is_array($content) ? json_encode($content) : static::valueToString($content);
108
            $entities[] = $this->Config->newEntity(compact('name', 'context', 'content'));
109
        }
110
        $this->Config->getConnection()->transactional(function () use ($entities) {
111
            foreach ($entities as $entity) {
112
                if (!$this->Config->save($entity, ['atomic' => false])) {
113
                    throw new Exception(sprintf('Config save failed: %s', print_r($entity->getErrors(), true)));
0 ignored issues
show
Bug introduced by
It seems like print_r($entity->getErrors(), true) can also be of type true; however, parameter $values of sprintf() does only seem to accept double|integer|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

113
                    throw new Exception(sprintf('Config save failed: %s', /** @scrutinizer ignore-type */ print_r($entity->getErrors(), true)));
Loading history...
114
                }
115
            }
116
        });
117
118
        return true;
119
    }
120
121
    /**
122
     * Converts a value into its string equivalent
123
     *
124
     * @param mixed $value Value to export.
125
     * @return string String value for database.
126
     */
127
    protected static function valueToString($value): string
128
    {
129
        if ($value === null) {
130
            return 'null';
131
        }
132
        if ($value === true) {
133
            return 'true';
134
        }
135
        if ($value === false) {
136
            return 'false';
137
        }
138
139
        return (string)$value;
140
    }
141
142
    /**
143
     * Converts a value from its string value to its 'natural' form.
144
     *
145
     * Note that for lowercased variant of 'true', 'false' and 'null'
146
     * are converted without errors from `json_decode()`.
147
     *
148
     * @param string $value Value to convert, if necessary.
149
     * @return mixed String Natural form value.
150
     */
151
    protected static function valueFromString($value)
152
    {
153
        if ($value === 'NULL') {
154
            return null;
155
        }
156
        if ($value === 'TRUE') {
157
            return true;
158
        }
159
        if ($value === 'FALSE') {
160
            return false;
161
        }
162
163
        return $value;
164
    }
165
}
166