Passed
Push — main ( 8fe145...85e465 )
by Thierry
13:46
created

StorageManager   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 154
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 38
c 1
b 0
f 0
dl 0
loc 154
rs 10
wmc 19

9 Methods

Rating   Name   Duplication   Size   Complexity  
A get() 0 13 4
A register() 0 3 1
A registerDefaults() 0 6 2
A make() 0 9 3
A loadTranslations() 0 8 1
A config() 0 14 3
A translator() 0 11 2
A __construct() 0 8 2
A setConfigGetter() 0 4 1
1
<?php
2
3
/**
4
 * StorageManager.php
5
 *
6
 * File storage manager.
7
 *
8
 * @package jaxon-storage
9
 * @author Thierry Feuzeu <[email protected]>
10
 * @copyright 2025 Thierry Feuzeu <[email protected]>
11
 * @license https://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
12
 * @link https://github.com/jaxon-php/jaxon-core
13
 */
14
15
namespace Jaxon\Storage;
16
17
use Jaxon\Config\Config;
18
use Jaxon\Utils\Translation\Translator;
19
use Lagdo\Facades\Logger;
20
use League\Flysystem\Filesystem;
21
use League\Flysystem\Local\LocalFilesystemAdapter;
22
use Closure;
23
24
use function dirname;
25
use function is_array;
26
use function is_callable;
27
use function is_string;
28
29
class StorageManager
30
{
31
    /**
32
     * @var array<string, Closure>
33
     */
34
    protected $aAdapters = [];
35
36
    /**
37
     * @var Config|null
38
     */
39
    protected Config|null $xConfig = null;
40
41
    /**
42
     * The constructor
43
     *
44
     * @param Closure|null $xConfigGetter
45
     * @param Translator|null $xTranslator
46
     */
47
    public function __construct(private Closure|null $xConfigGetter = null,
48
        protected Translator|null $xTranslator = null)
49
    {
50
        $this->registerDefaults();
51
52
        if($xTranslator !== null)
53
        {
54
            $this->loadTranslations($xTranslator);
55
        }
56
    }
57
58
    /**
59
     * @param Closure $xConfigGetter
60
     *
61
     * @return void
62
     */
63
    public function setConfigGetter(Closure $xConfigGetter): void
64
    {
65
        $this->xConfigGetter = $xConfigGetter;
66
        $this->xConfig = null;
67
    }
68
69
    /**
70
     * @return void
71
     */
72
    private function loadTranslations(Translator $xTranslator): void
73
    {
74
        // Translation directory
75
        $sTranslationDir = dirname(__DIR__) . '/translations';
76
        // Load the storage translations
77
        $xTranslator->loadTranslations("$sTranslationDir/en/storage.php", 'en');
78
        $xTranslator->loadTranslations("$sTranslationDir/fr/storage.php", 'fr');
79
        $xTranslator->loadTranslations("$sTranslationDir/es/storage.php", 'es');
80
    }
81
82
    /**
83
     * Get a translator with the translations loaded.
84
     *
85
     * @return Translator
86
     */
87
    public function translator(): Translator
88
    {
89
        if($this->xTranslator !== null)
90
        {
91
            return $this->xTranslator;
92
        }
93
94
        $this->xTranslator = new Translator();
95
        $this->loadTranslations($this->xTranslator);
0 ignored issues
show
Bug introduced by
$this->xTranslator of type null is incompatible with the type Jaxon\Utils\Translation\Translator expected by parameter $xTranslator of Jaxon\Storage\StorageManager::loadTranslations(). ( Ignorable by Annotation )

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

95
        $this->loadTranslations(/** @scrutinizer ignore-type */ $this->xTranslator);
Loading history...
96
97
        return $this->xTranslator;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->xTranslator returns the type null which is incompatible with the type-hinted return Jaxon\Utils\Translation\Translator.
Loading history...
98
    }
99
100
    /**
101
     * @param string $sAdapter
102
     * @param Closure $cFactory
103
     *
104
     * @return void
105
     */
106
    public function register(string $sAdapter, Closure $cFactory)
107
    {
108
        $this->aAdapters[$sAdapter] = $cFactory;
109
    }
110
111
    /**
112
     * Register the file storage adapters
113
     *
114
     * @return void
115
     */
116
    private function registerDefaults()
117
    {
118
        // Local file system adapter
119
        $this->register('local', function(string $sRootDir, array $aOptions) {
120
            return empty($aOptions) ? new LocalFilesystemAdapter($sRootDir) :
121
                new LocalFilesystemAdapter($sRootDir, ...$aOptions);
0 ignored issues
show
Bug introduced by
$aOptions is expanded, but the parameter $visibility of League\Flysystem\Local\L...mAdapter::__construct() does not expect variable arguments. ( Ignorable by Annotation )

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

121
                new LocalFilesystemAdapter($sRootDir, /** @scrutinizer ignore-type */ ...$aOptions);
Loading history...
122
        });
123
    }
124
125
    /**
126
     * @param string $sAdapter
127
     * @param string $sRootDir
128
     * @param array $aOptions
129
     *
130
     * @return Filesystem
131
     * @throws Exception
132
     */
133
    public function make(string $sAdapter, string $sRootDir, array $aOptions = []): Filesystem
134
    {
135
        if(!isset($this->aAdapters[$sAdapter]) || !is_callable($this->aAdapters[$sAdapter]))
136
        {
137
            Logger::error("Jaxon Storage: adapter '$sAdapter' not configured.");
138
            throw new Exception($this->translator()->trans('errors.storage.adapter'));
139
        }
140
141
        return new Filesystem($this->aAdapters[$sAdapter]($sRootDir, $aOptions));
142
    }
143
144
    /**
145
     * @throws Exception
146
     * @return Config
147
     */
148
    private function config(): Config
149
    {
150
        if($this->xConfig !== null)
151
        {
152
            return $this->xConfig;
153
        }
154
155
        if($this->xConfigGetter === null)
156
        {
157
            Logger::error("Jaxon Storage: No config getter set.");
158
            throw new Exception($this->translator()->trans('errors.storage.getter'));
159
        }
160
161
        return $this->xConfig = ($this->xConfigGetter)();
162
    }
163
164
    /**
165
     * @param string $sOptionName
166
     *
167
     * @return Filesystem
168
     * @throws Exception
169
     */
170
    public function get(string $sOptionName): Filesystem
171
    {
172
        $xConfig = $this->config();
173
        $sAdapter = $xConfig->getOption("$sOptionName.adapter");
174
        $sRootDir = $xConfig->getOption("$sOptionName.dir");
175
        $aOptions = $xConfig->getOption("$sOptionName.options", []);
176
        if(!is_string($sAdapter) || !is_string($sRootDir) || !is_array($aOptions))
177
        {
178
            Logger::error("Jaxon Storage: incorrect values in '$sOptionName' options.");
179
            throw new Exception($this->translator()->trans('errors.storage.options'));
180
        }
181
182
        return $this->make($sAdapter, $sRootDir, $aOptions);
183
    }
184
}
185