Issues (27)

src/Handlers/DatabaseHandler.php (4 issues)

1
<?php
2
3
/**
4
 * This file is part of BlitzPHP Parametres.
5
 *
6
 * (c) 2025 Dimitri Sitchet Tomkeu <[email protected]>
7
 *
8
 * For the full copyright and license information, please view
9
 * the LICENSE file that was distributed with this source code.
10
 */
11
12
namespace BlitzPHP\Parametres\Handlers;
13
14
use BlitzPHP\Database\Builder\BaseBuilder;
15
use BlitzPHP\Database\Connection\BaseConnection;
0 ignored issues
show
The type BlitzPHP\Database\Connection\BaseConnection was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
16
use BlitzPHP\Database\ConnectionResolver;
17
use BlitzPHP\Utilities\Date;
18
use RuntimeException;
19
use stdClass;
20
21
/**
22
 * Fournit une persistance de base de données pour les paramètres.
23
 * Utilise ArrayHandler pour le stockage afin de minimiser les appels à la base de données.
24
 */
25
class DatabaseHandler extends ArrayHandler
26
{
27
    /**
28
     * La connexion à la base de données pour les paramètres.
29
     */
30
    private BaseConnection $db;
31
32
    /**
33
     * Le générateur de requêtes pour la table Paramètres.
34
     */
35
    private BaseBuilder $builder;
36
37
    /**
38
     * Tableau des contextes qui ont été stockés.
39
     *
40
     * @var list<null>|list<string>
0 ignored issues
show
The type BlitzPHP\Parametres\Handlers\list was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
41
     */
42
    private array $hydrated = [];
43
44
    private stdClass $config;
45
46
    /**
47
     * @param array<string,mixed> $config
48
     */
49
    public function __construct(array $config = [])
50
    {
51
        if ($config === []) {
52
            $config = config('parametres.database', []);
53
        }
54
55
        $this->config = (object) $config;
56
57
        $this->db      = (new ConnectionResolver())->connect($this->config->group);
58
        $this->builder = $this->db->table($this->config->table);
59
    }
60
61
    /**
62
     * Vérifie si ce gestionnaire a une valeur définie.
63
     */
64
    public function has(string $file, string $property, ?string $context = null): bool
65
    {
66
        $this->hydrate($context);
67
68
        return $this->hasStored($file, $property, $context);
69
    }
70
71
    /**
72
     * Tentative d'extraction d'une valeur de la base de données.
73
     * Pour améliorer les performances, toutes les valeurs sont lues et stockées lors du premier appel
74
     * pour chaque contexte, puis récupérées dans la base de données.
75
     *
76
     * @return mixed|null
77
     */
78
    public function get(string $file, string $property, ?string $context = null): mixed
79
    {
80
        return $this->getStored($file, $property, $context);
81
    }
82
83
    /**
84
     * Enregistre les valeurs dans la base de données pour les retrouver ultérieurement.
85
     *
86
     * @throws RuntimeException En cas d'échec de la base de données
87
     */
88
    public function set(string $file, string $property, mixed $value = null, ?string $context = null): void
89
    {
90
        $time     = Date::now()->format('Y-m-d H:i:s');
91
        $type     = gettype($value);
92
        $prepared = $this->prepareValue($value);
93
94
        // S'il a été stocké, nous devons le mettre à jour
95
        if ($this->has($file, $property, $context)) {
96
            $result = $this->builder()->where('file', $file)->where('key', $property);
97
98
            if ($context === null) {
99
                $result = $result->whereNull('context');
100
            } else {
101
                $result = $result->where('context', $context);
102
            }
103
104
            $result = $result->update([
105
                'value'      => $prepared,
106
                'type'       => $type,
107
                'context'    => $context,
108
                'updated_at' => $time,
109
            ]);
110
            // ...sinon l'insérer
111
        } else {
112
            $result = $this->builder()->insert([
113
                'file'       => $file,
114
                'key'        => $property,
115
                'value'      => $prepared,
116
                'type'       => $type,
117
                'context'    => $context,
118
                'created_at' => $time,
119
                'updated_at' => $time,
120
            ]);
121
        }
122
123
        if (! $result) {
0 ignored issues
show
$result is of type BlitzPHP\Database\Result\BaseResult, thus it always evaluated to true.
Loading history...
124
            throw new RuntimeException($this->db->error()['message'] ?? 'Erreur d\'écriture dans la base de données.');
125
        }
126
127
        // Mise à jour du stockage
128
        $this->setStored($file, $property, $value, $context);
129
    }
130
131
    /**
132
     * Supprime l'enregistrement du stockage permanent, s'il existe, et du cache local.
133
     */
134
    public function forget(string $file, string $property, ?string $context = null): void
135
    {
136
        $this->hydrate($context);
137
138
        // Supprimer de la base de données
139
140
        $builder = $this->builder()->where('file', $file)->where('key', $property);
141
142
        if (null === $context) {
143
            $builder->whereNull('context');
144
        } else {
145
            $builder->where('context', $context);
146
        }
147
148
        $result = $builder->delete();
149
150
        if (! $result) {
0 ignored issues
show
$result is of type BlitzPHP\Database\Result\BaseResult, thus it always evaluated to true.
Loading history...
151
            throw new RuntimeException($this->db->error()['message'] ?? 'Erreur d\'écriture dans la base de données.');
152
        }
153
154
        // Supprimer de la mémoire locale
155
        $this->forgetStored($file, $property, $context);
156
    }
157
158
    /**
159
     * Supprime tous les enregistrements de la mémoire permanente, si elle existe, et du cache local.
160
     */
161
    public function flush(): void
162
    {
163
        $this->builder()->truncate();
164
165
        parent::flush();
166
    }
167
168
    /**
169
     * Récupère les valeurs de la base de données en vrac pour minimiser les appels.
170
     * Le général (null) est toujours récupéré une fois, les contextes sont récupérés dans leur intégralité pour chaque nouvelle requête.
171
     *
172
     * @throws RuntimeException En cas d'échec de la base de données
173
     */
174
    private function hydrate(?string $context = null): void
175
    {
176
        // Vérification de l'achèvement des travaux
177
        if (in_array($context, $this->hydrated, true)) {
178
            return;
179
        }
180
181
        if ($context === null) {
182
            $this->hydrated[] = null;
183
            $query            = $this->builder()->whereNull('context');
184
        } else {
185
            $query = $this->builder()->where('context', $context);
186
187
            // Si le général n'a pas été hydraté, nous le ferons en même temps.
188
            if (! in_array(null, $this->hydrated, true)) {
189
                $this->hydrated[] = null;
190
                $query->orWhereNull('context');
191
            }
192
193
            $this->hydrated[] = $context;
194
        }
195
196
        foreach ($query->result('object') as $row) {
197
            $this->setStored($row->file, $row->key, $this->parseValue($row->value, $row->type), $row->context);
198
        }
199
    }
200
201
    private function builder(): BaseBuilder
202
    {
203
        return $this->builder->reset()->table($this->config->table);
204
    }
205
}
206