Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 49
0.00% covered (danger)
0.00%
0 / 16
CRAP
0.00% covered (danger)
0.00%
0 / 1
state_helper
0.00% covered (danger)
0.00%
0 / 49
0.00% covered (danger)
0.00%
0 / 16
420
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 is_action_in_progress
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 new_provider
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 new_definition_value
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 update_type
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 storage_index
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 set_storage_index
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 remove_storage_index
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 set_remove_storage_index
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 file_index
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 set_file_index
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 storages
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 init
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
20
 clear_state
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 load_state
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 save_state
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 *
4 * This file is part of the phpBB Forum Software package.
5 *
6 * @copyright (c) phpBB Limited <https://www.phpbb.com>
7 * @license GNU General Public License, version 2 (GPL-2.0)
8 *
9 * For full copyright and license information, please see
10 * the docs/CREDITS.txt file.
11 *
12 */
13
14namespace phpbb\storage;
15
16use phpbb\config\config;
17use phpbb\config\db_text;
18use phpbb\di\service_collection;
19use phpbb\request\request;
20use phpbb\storage\exception\action_in_progress_exception;
21use phpbb\storage\exception\no_action_in_progress_exception;
22
23class state_helper
24{
25    /** @var config */
26    protected $config;
27
28    /** @var db_text $config_text */
29    protected $config_text;
30
31    /** @var service_collection */
32    protected $provider_collection;
33
34    /**
35     * @param config $config
36     * @param db_text $config_text
37     * @param service_collection $provider_collection
38     */
39    public function __construct(config $config, db_text $config_text, service_collection $provider_collection)
40    {
41        $this->config = $config;
42        $this->config_text = $config_text;
43        $this->provider_collection = $provider_collection;
44    }
45
46    /**
47     * Returns if there is an action in progress
48     *
49     * @return bool
50     */
51    public function is_action_in_progress(): bool
52    {
53        return !empty(json_decode($this->config_text->get('storage_update_state'), true));
54    }
55
56    /**
57     * Get new provider for the specified storage
58     *
59     * @param string $storage_name
60     *
61     * @return string
62     */
63    public function new_provider(string $storage_name): string
64    {
65        $state = $this->load_state();
66
67        return $state['storages'][$storage_name]['provider'];
68    }
69
70    /**
71     * Get new definition value for the specified storage
72     *
73     * @param string $storage_name
74     * @param string $definition
75     *
76     * @return string
77     */
78    public function new_definition_value(string $storage_name, string $definition): string
79    {
80        $state = $this->load_state();
81
82        return $state['storages'][$storage_name]['config'][$definition];
83    }
84
85    /**
86     * Get the update type
87     *
88     * @return update_type
89     */
90    public function update_type(): update_type
91    {
92        $state = $this->load_state();
93
94        return update_type::from($state['update_type']);
95    }
96
97    /**
98     * Get the current storage index
99     *
100     * @return int
101     */
102    public function storage_index(): int
103    {
104        $state = $this->load_state();
105
106        return $state['storage_index'];
107    }
108
109    /**
110     * Update the storage index
111     *
112     * @param int $storage_index
113     *
114     * @return void
115     */
116    public function set_storage_index(int $storage_index): void
117    {
118        $state = $this->load_state();
119
120        $state['storage_index'] = $storage_index;
121
122        $this->save_state($state);
123    }
124
125    /**
126     * Get the current remove storage index
127     *
128     * @return int
129     */
130    public function remove_storage_index(): int
131    {
132        $state = $this->load_state();
133
134        return $state['remove_storage_index'];
135    }
136
137    /**
138     * Update the remove storage index
139     *
140     * @param int $storage_index
141     *
142     * @return void
143     */
144    public function set_remove_storage_index(int $storage_index): void
145    {
146        $state = $this->load_state();
147
148        $state['remove_storage_index'] = $storage_index;
149
150        $this->save_state($state);
151    }
152
153    /**
154     * Get the file index
155     *
156     * @return int
157     */
158    public function file_index(): int
159    {
160        $state = $this->load_state();
161
162        return $state['file_index'];
163    }
164
165    /**
166     * Set the file index
167     *
168     * @param int $file_index
169     * @return void
170     */
171    public function set_file_index(int $file_index): void
172    {
173        $state = $this->load_state();
174
175        $state['file_index'] = $file_index;
176
177        $this->save_state($state);
178    }
179
180    /**
181     * Get the storage names to be updated
182     *
183     * @return array
184     */
185    public function storages(): array
186    {
187        $state = $this->load_state();
188
189        return array_keys($state['storages']);
190    }
191
192    /**
193     * Start a indexing or delete process.
194     *
195     * @param update_type $update_type
196     * @param array $modified_storages
197     * @param request $request
198     *
199     * @throws action_in_progress_exception  If there is an action in progress
200     * @throws \JsonException
201     */
202    public function init(update_type $update_type, array $modified_storages, request $request): void
203    {
204        // Is not possible to start a new process when there is one already running
205        if ($this->is_action_in_progress())
206        {
207            throw new action_in_progress_exception();
208        }
209
210        $state = [
211            // Save the value of the checkbox, to remove all files from the
212            // old storage once they have been successfully moved
213            'update_type' => $update_type->value,
214            'storages' => [],
215            'storage_index' => 0,
216            'file_index' => 0,
217            'remove_storage_index' => 0,
218        ];
219
220        // Save in the state the selected storages and their new configuration
221        foreach ($modified_storages as $storage_name)
222        {
223            $state['storages'][$storage_name] = [];
224
225            $state['storages'][$storage_name]['provider'] = $request->variable([$storage_name, 'provider'], '');
226
227            $options = $this->provider_collection->get_by_class($request->variable([$storage_name, 'provider'], ''))->get_options();
228
229            foreach (array_keys($options) as $definition)
230            {
231                /** @psalm-suppress InvalidArrayOffset */
232                $state['storages'][$storage_name]['config'][$definition] = $request->variable([$storage_name, $definition], '');
233            }
234        }
235
236        $this->save_state($state);
237    }
238
239    /**
240     * Clear the state
241     *
242     * @throws \JsonException
243     */
244    public function clear_state(): void
245    {
246        $this->save_state();
247    }
248
249    /**
250     * Load the state from the database
251     *
252     * @return array
253     *
254     * @throws no_action_in_progress_exception If there is no action in progress
255     */
256    private function load_state(): array
257    {
258        // Is not possible to execute an action over state if is empty
259        if (!$this->is_action_in_progress())
260        {
261            throw new no_action_in_progress_exception();
262        }
263
264        return json_decode($this->config_text->get('storage_update_state'), true) ?? [];
265    }
266
267    /**
268     * Save the specified state in the database
269     *
270     * @param array $state
271     *
272     * @throws \JsonException
273     */
274    private function save_state(array $state = []): void
275    {
276        $this->config_text->set('storage_update_state', json_encode($state, JSON_THROW_ON_ERROR));
277    }
278}