Passed
Pull Request — develop (#9)
by mark
03:04
created

FileStorage::store()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 22
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 4.0582

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 12
c 1
b 0
f 0
nc 8
nop 1
dl 0
loc 22
ccs 11
cts 13
cp 0.8462
crap 4.0582
rs 9.8666
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
     */
65 1
    public function __construct(
66
        StorageServiceInterface $storageService,
67
        ?PathBuilderInterface $pathBuilder = null,
68
        ?UrlBuilderInterface $urlBuilder = null
69
    ) {
70 1
        $this->storageService = $storageService;
71 1
        $this->pathBuilder = $pathBuilder;
72 1
        $this->urlBuilder = $urlBuilder;
73 1
    }
74
75
    /**
76
     * @param string $name Name of the callback
77
     * @return void
78
     */
79 1
    protected function checkCallbackName(string $name): void
80
    {
81 1
        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
        }
88 1
    }
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
     */
108 1
    public function runCallbacks(string $name, FileInterface $file): FileInterface
109
    {
110 1
        $this->checkCallbackName($name);
111
112 1
        foreach ($this->callbacks[$name] as $callback) {
113
            $file = $callback($file);
114
        }
115
116 1
        return $file;
117
    }
118
119
    /**
120
     * @inheritDoc
121
     * @throws \RuntimeException
122
     */
123 1
    public function store(FileInterface $file): FileInterface
124
    {
125 1
        $config = new Config();
126
127 1
        if ($this->pathBuilder !== null) {
128 1
            $file = $file->buildPath($this->pathBuilder);
129
        }
130
131 1
        if ($this->urlBuilder !== null) {
132
            $file = $file->buildUrl($this->urlBuilder);
133
        }
134
135 1
        $file = $this->runCallbacks('beforeSave', $file);
136
137 1
        $storage = $this->getStorage($file->storage());
138 1
        $resource = $file->resource();
139 1
        if ($resource === null) {
140
            throw new RuntimeException('No resource given');
141
        }
142 1
        $storage->writeStream($file->path(), $resource, $config);
143
144 1
        return $this->runCallbacks('afterSave', $file);
145
    }
146
147
    /**
148
     * @inheritDoc
149
     */
150 1
    public function remove(FileInterface $file): FileInterface
151
    {
152 1
        $file = $this->runCallbacks('beforeRemove', $file);
153
154
        // Delete all variants of the file
155 1
        foreach ($file->variants() as $variant) {
156
            if (!empty($variant['path'])) {
157
                $this->getStorage($file->storage())->delete($variant['path']);
158
            }
159
        }
160
161
        // Delete the file
162 1
        $this->getStorage($file->storage())->delete($file->path());
163
164 1
        return $this->runCallbacks('afterRemove', $file);
165
    }
166
167
    /**
168
     * @inheritDoc
169
     */
170
    public function removeVariant(FileInterface $file, string $name): FileInterface
171
    {
172
        if (!$file->hasVariant($name)) {
173
            throw VariantDoesNotExistException::withName($name);
174
        }
175
176
        $variant = $file->variant($name);
177
        if (empty($variant['path'])) {
178
            throw new VariantException(sprintf(
179
                'Variant `%s` is missing a path',
180
                $name
181
            ));
182
        }
183
184
        $this->getStorage($file->storage())->delete($variant['path']);
185
186
        $variants = $file->variants();
187
        unset($variants[$name]);
188
189
        return $file->withVariants($variants, false);
190
    }
191
192
    /**
193
     * Gets the storage abstraction to use
194
     *
195
     * @param string $storage Storage name to use
196
     * @return \League\Flysystem\AdapterInterface
197
     */
198 1
    public function getStorage(string $storage): AdapterInterface
199
    {
200 1
        return $this->storageService->adapter($storage);
201
    }
202
}
203