Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
33.33% covered (danger)
33.33%
10 / 30
44.44% covered (danger)
44.44%
4 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
ChainedFileStorage
33.33% covered (danger)
33.33%
10 / 30
44.44% covered (danger)
44.44%
4 / 9
114.00
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
3
 createNewUpload
40.00% covered (danger)
40.00%
2 / 5
0.00% covered (danger)
0.00%
0 / 1
4.94
 getProxy
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 loadFromStorage
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
12
 iterate
37.50% covered (danger)
37.50%
3 / 8
0.00% covered (danger)
0.00%
0 / 1
7.91
 pathToPsr
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 psrToPath
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 resourceToPath
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 pathToResource
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2namespace Apie\Core\FileStorage;
3
4use Apie\Core\Exceptions\FileStorageException;
5use Exception;
6use LogicException;
7use Psr\Http\Message\UploadedFileInterface;
8use Throwable;
9
10final class ChainedFileStorage implements PsrAwareStorageInterface, ResourceAwareStorageInterface
11{
12    /**
13     * @var array<int, PsrAwareStorageInterface> $psrAwareStorages
14     */
15    private array $psrAwareStorages;
16
17    /**
18     * @var array<int, ResourceAwareStorageInterface> $resourceAwareStorages
19     */
20    private array $resourceAwareStorages;
21
22    /**
23     * @param array<int, PsrAwareStorageInterface> $psrAwareStorages
24     * @param array<int, ResourceAwareStorageInterface> $resourceAwareStorages
25     */
26    public function __construct(
27        iterable $psrAwareStorages,
28        iterable $resourceAwareStorages
29    ) {
30        $this->psrAwareStorages = is_array($psrAwareStorages) ? $psrAwareStorages : iterator_to_array($psrAwareStorages);
31        $this->resourceAwareStorages = is_array($resourceAwareStorages) ? $resourceAwareStorages : iterator_to_array($resourceAwareStorages);
32    }
33
34    public function createNewUpload(
35        UploadedFileInterface $fileUpload,
36        string $className = StoredFile::class
37    ): StoredFile {
38        foreach ($this->psrAwareStorages as $psrAwareStorage) {
39            return $psrAwareStorage->createNewUpload($fileUpload, $className);
40        }
41        foreach ($this->resourceAwareStorages as $resourceAwareStorage) {
42            return $resourceAwareStorage->createNewUpload($fileUpload, $className);
43        }
44
45        throw new \LogicException("I can not create an upload");
46    }
47
48    public function getProxy(
49        string $storagePath,
50        string $className = StoredFile::class
51    ): StoredFile {
52        return $className::createFromStorage(
53            $this,
54            $storagePath
55        );
56    }
57
58    /**
59     * @template T of StoredFile
60     * @param class-string<T> $className
61     * @return T
62     */
63    public function loadFromStorage(
64        string $storagePath,
65        string $className = StoredFile::class
66    ): StoredFile {
67        $errors = [];
68        $list = [...$this->psrAwareStorages, ...$this->resourceAwareStorages];
69        foreach ($list as $psrAwareStorage) {
70            try {
71                return $psrAwareStorage->loadFromStorage($storagePath, $className);
72            } catch (Exception $error) {
73                $errors[] = $error;
74            }
75        }
76
77        throw new FileStorageException('I can not load from "' . $storagePath . '"', $errors);
78    }
79
80    /**
81     * @param array<int, object> $list
82     */
83    private function iterate(array $list, string $methodName, mixed... $arguments): mixed
84    {
85        $collectedExceptions = [];
86        foreach ($list as $storage) {
87            try {
88                return $storage->$methodName(...$arguments);
89            } catch (Throwable $error) {
90                $collectedExceptions[] = $error;
91            }
92        }
93        if (empty($collectedExceptions)) {
94            $collectedExceptions[] = new LogicException('There is no configured storage class for ' . $methodName);
95        }
96        throw new FileStorageException('There was a problem calling ' . $methodName, $collectedExceptions);
97    }
98
99    public function pathToPsr(string $path): UploadedFileInterface
100    {
101        return $this->iterate($this->psrAwareStorages, 'pathToPsr', $path);
102    }
103
104    public function psrToPath(UploadedFileInterface $uploadedFile): string
105    {
106        return $this->iterate($this->psrAwareStorages, 'psrToPath', $uploadedFile);
107    }
108
109    public function resourceToPath(mixed $resource): string
110    {
111        return $this->iterate($this->resourceAwareStorages, 'resourceToPath', $resource);
112    }
113
114    public function pathToResource(string $path): mixed
115    {
116        return $this->iterate($this->resourceAwareStorages, 'pathToResource', $path);
117    }
118}