FileStorage   A
last analyzed

Complexity

Total Complexity 18

Size/Duplication

Total Lines 172
Duplicated Lines 0 %

Test Coverage

Coverage 56%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 54
c 1
b 0
f 0
dl 0
loc 172
ccs 28
cts 50
cp 0.56
rs 10
wmc 18

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 8 1
A addCallback() 0 4 1
A checkCallbackName() 0 7 2
A runCallbacks() 0 9 2
A remove() 0 15 3
A removeVariant() 0 20 3
A getStorage() 0 3 1
A store() 0 24 5
1
<?php
2
3
/**
4
 * Copyright (c) Florian Krämer (https://florian-kraemer.net)
5
 * Licensed under The MIT License
6
 * For full copyright and license information, please see the LICENSE.txt
7
 * Redistributions of files must retain the above copyright notice.
8
 *
9
 * @copyright Copyright (c) Florian Krämer (https://florian-kraemer.net)
10
 * @author    Florian Krämer
11
 * @link      https://github.com/Phauthentic
12
 * @license   https://opensource.org/licenses/MIT MIT License
13
 */
14
15
declare(strict_types=1);
16
17
namespace Phauthentic\Infrastructure\Storage;
18
19
use InvalidArgumentException;
20
use League\Flysystem\AdapterInterface;
21
use League\Flysystem\Config;
22
use Phauthentic\Infrastructure\Storage\PathBuilder\PathBuilderInterface;
23
use Phauthentic\Infrastructure\Storage\Processor\Exception\VariantDoesNotExistException;
24
use Phauthentic\Infrastructure\Storage\Processor\Exception\VariantException;
25
use Phauthentic\Infrastructure\Storage\UrlBuilder\UrlBuilderInterface;
26
use RuntimeException;
27
28
/**
29
 * File Storage
30
 */
31
class FileStorage implements FileStorageInterface
32
{
33
    /**
34
     * @var array
35
     */
36
    protected array $callbacks = [
37
        'beforeSave' => [],
38
        'afterSave' => [],
39
        'beforeRemove' => [],
40
        'afterRemove' => [],
41
    ];
42
43
    /**
44
     * @var \Phauthentic\Infrastructure\Storage\PathBuilder\PathBuilderInterface|null
45
     */
46
    protected ?PathBuilderInterface $pathBuilder;
47
48
    /**
49
     * @var \Phauthentic\Infrastructure\Storage\UrlBuilder\UrlBuilderInterface|null
50
     */
51
    protected ?UrlBuilderInterface $urlBuilder;
52
53
    /**
54
     * @var \Phauthentic\Infrastructure\Storage\StorageServiceInterface
55
     */
56
    protected StorageServiceInterface $storageService;
57
58
    /**
59
     * Constructor
60
     *
61
     * @param \Phauthentic\Infrastructure\Storage\StorageServiceInterface $storageService Storage Service
62
     * @param \Phauthentic\Infrastructure\Storage\PathBuilder\PathBuilderInterface|null $pathBuilder Path Builder
63
     * @param \Phauthentic\Infrastructure\Storage\UrlBuilder\UrlBuilderInterface|null $urlBuilder Path Builder
64 1
     */
65
    public function __construct(
66
        StorageServiceInterface $storageService,
67
        ?PathBuilderInterface $pathBuilder = null,
68
        ?UrlBuilderInterface $urlBuilder = null
69 1
    ) {
70 1
        $this->storageService = $storageService;
71 1
        $this->pathBuilder = $pathBuilder;
72 1
        $this->urlBuilder = $urlBuilder;
73
    }
74
75
    /**
76
     * @param string $name Name of the callback
77
     * @return void
78 1
     */
79
    protected function checkCallbackName(string $name): void
80 1
    {
81
        if (!array_key_exists($name, $this->callbacks)) {
82
            throw new InvalidArgumentException(sprintf(
83
                'Invalid callback `%s`, only %s are valid',
84
                $name,
85
                implode(', ', array_keys($this->callbacks))
86
            ));
87 1
        }
88
    }
89
90
    /**
91
     * Adds a callback
92
     *
93
     * @param string $name
94
     * @param callable $callable Callable
95
     * @return void
96
     */
97
    public function addCallback($name, callable $callable): void
98
    {
99
        $this->checkCallbackName($name);
100
        $this->callbacks[$name][] = $callable;
101
    }
102
103
    /**
104
     * @param string $name Name of the callback
105
     * @param \Phauthentic\Infrastructure\Storage\FileInterface $file File
106
     * @return \Phauthentic\Infrastructure\Storage\FileInterface
107 1
     */
108
    public function runCallbacks(string $name, FileInterface $file): FileInterface
109 1
    {
110
        $this->checkCallbackName($name);
111 1
112
        foreach ($this->callbacks[$name] as $callback) {
113
            $file = $callback($file);
114
        }
115 1
116
        return $file;
117
    }
118
119
    /**
120
     * @inheritDoc
121 1
     * @throws \RuntimeException
122
     */
123 1
    public function store(FileInterface $file, ?Config $config = null): FileInterface
124
    {
125 1
        if ($config === null) {
126 1
            $config = new Config();
127
        }
128
129 1
        if ($this->pathBuilder !== null) {
130
            $file = $file->buildPath($this->pathBuilder);
131
        }
132
133 1
        if ($this->urlBuilder !== null) {
134
            $file = $file->buildUrl($this->urlBuilder);
135 1
        }
136 1
137
        $file = $this->runCallbacks('beforeSave', $file);
138 1
139
        $storage = $this->getStorage($file->storage());
140
        $resource = $file->resource();
141
        if ($resource === null) {
142
            throw new RuntimeException('No resource given');
143
        }
144 1
        $storage->writeStream($file->path(), $resource, $config);
145
146 1
        return $this->runCallbacks('afterSave', $file);
147
    }
148
149 1
    /**
150
     * @inheritDoc
151
     */
152
    public function remove(FileInterface $file): FileInterface
153
    {
154
        $file = $this->runCallbacks('beforeRemove', $file);
155
156 1
        // Delete all variants of the file
157
        foreach ($file->variants() as $variant) {
158 1
            if (!empty($variant['path'])) {
159
                $this->getStorage($file->storage())->delete($variant['path']);
160
            }
161
        }
162
163
        // Delete the file
164
        $this->getStorage($file->storage())->delete($file->path());
165
166
        return $this->runCallbacks('afterRemove', $file);
167
    }
168
169
    /**
170
     * @inheritDoc
171
     */
172
    public function removeVariant(FileInterface $file, string $name): FileInterface
173
    {
174
        if (!$file->hasVariant($name)) {
175
            throw VariantDoesNotExistException::withName($name);
176
        }
177
178
        $variant = $file->variant($name);
179
        if (empty($variant['path'])) {
180
            throw new VariantException(sprintf(
181
                'Variant `%s` is missing a path',
182
                $name
183
            ));
184
        }
185
186
        $this->getStorage($file->storage())->delete($variant['path']);
187
188
        $variants = $file->variants();
189
        unset($variants[$name]);
190
191
        return $file->withVariants($variants, false);
192 1
    }
193
194 1
    /**
195
     * Gets the storage abstraction to use
196
     *
197
     * @param string $storage Storage name to use
198
     * @return \League\Flysystem\AdapterInterface
199
     */
200
    public function getStorage(string $storage): AdapterInterface
201
    {
202
        return $this->storageService->adapter($storage);
203
    }
204
}
205