Passed
Push — feature/uploadable ( 7c6d25...a7ed20 )
by Daniel
11:07
created

UploadableHelper::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 16
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 7
nc 1
nop 7
dl 0
loc 16
ccs 0
cts 8
cp 0
crap 2
rs 10
c 1
b 0
f 0
1
<?php
2
3
/*
4
 * This file is part of the Silverback API Components Bundle Project
5
 *
6
 * (c) Daniel West <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace Silverback\ApiComponentsBundle\Uploadable;
15
16
use Doctrine\Common\Collections\ArrayCollection;
17
use Doctrine\Persistence\ManagerRegistry;
18
use League\Flysystem\Filesystem;
19
use League\Flysystem\UnableToReadFile;
20
use Liip\ImagineBundle\Service\FilterService;
21
use Silverback\ApiComponentsBundle\Annotation\UploadableField;
22
use Silverback\ApiComponentsBundle\AnnotationReader\UploadableAnnotationReader;
23
use Silverback\ApiComponentsBundle\Entity\Utility\ImagineFiltersInterface;
24
use Silverback\ApiComponentsBundle\Factory\Uploadable\MediaObjectFactory;
25
use Silverback\ApiComponentsBundle\Flysystem\FilesystemProvider;
26
use Silverback\ApiComponentsBundle\Imagine\FlysystemDataLoader;
27
use Silverback\ApiComponentsBundle\Model\Uploadable\MediaObject;
28
use Silverback\ApiComponentsBundle\Model\Uploadable\UploadedDataUriFile;
29
use Silverback\ApiComponentsBundle\Utility\ClassMetadataTrait;
30
use Symfony\Component\HttpFoundation\FileBag;
31
use Symfony\Component\HttpFoundation\RequestStack;
32
use Symfony\Component\PropertyAccess\PropertyAccess;
33
34
/**
35
 * @author Daniel West <[email protected]>
36
 */
37
class UploadableHelper
38
{
39
    use ClassMetadataTrait;
40
41
    private UploadableAnnotationReader $annotationReader;
42
    private FilesystemProvider $filesystemProvider;
43
    private MediaObjectFactory $mediaObjectFactory;
44
    private RequestStack $requestStack;
45
    private ?FilterService $filterService;
46
    private FlysystemDataLoader $flysystemDataLoader;
47
48
    public function __construct(
49
        ManagerRegistry $registry,
50
        UploadableAnnotationReader $annotationReader,
51
        FilesystemProvider $filesystemProvider,
52
        MediaObjectFactory $mediaObjectFactory,
53
        RequestStack $requestStack,
54
        FlysystemDataLoader $flysystemDataLoader,
55
        ?FilterService $filterService = null
56
    ) {
57
        $this->initRegistry($registry);
58
        $this->annotationReader = $annotationReader;
59
        $this->filesystemProvider = $filesystemProvider;
60
        $this->mediaObjectFactory = $mediaObjectFactory;
61
        $this->requestStack = $requestStack;
62
        $this->flysystemDataLoader = $flysystemDataLoader;
63
        $this->filterService = $filterService;
64
    }
65
66
    public function setUploadedFilesFromFileBag(object $object, FileBag $fileBag): void
67
    {
68
        $propertyAccessor = PropertyAccess::createPropertyAccessor();
69
        $configuredProperties = $this->annotationReader->getConfiguredProperties($object, false, true);
70
71
        /**
72
         * @var UploadableField[] $configuredProperties
73
         */
74
        foreach ($configuredProperties as $fileProperty => $fieldConfiguration) {
75
            if ($file = $fileBag->get($fileProperty, null)) {
76
                $propertyAccessor->setValue($object, $fileProperty, $file);
77
            }
78
        }
79
    }
80
81
    public function storeFilesMetadata(object $object): void
82
    {
83
        $configuredProperties = $this->annotationReader->getConfiguredProperties($object, true, true);
84
        $classMetadata = $this->getClassMetadata($object);
85
86
        foreach ($configuredProperties as $fileProperty => $fieldConfiguration) {
87
            // Let the data loader which should be configured for imagine to know which adapter to use
88
            $this->flysystemDataLoader->setAdapter($fieldConfiguration->adapter);
89
90
            $filename = $classMetadata->getFieldValue($object, $fieldConfiguration->property);
91
            if ($object instanceof ImagineFiltersInterface && $this->filterService) {
92
                $filters = $object->getImagineFilters(null);
93
                foreach ($filters as $filter) {
94
                    // This will trigger the cached file to be store
95
                    // When cached files are store we save the file info
96
                    $this->filterService->getUrlOfFilteredImage($filename, $filter);
97
                }
98
            }
99
        }
100
    }
101
102
    public function persistFiles(object $object): void
103
    {
104
        $propertyAccessor = PropertyAccess::createPropertyAccessor();
105
        $classMetadata = $this->getClassMetadata($object);
106
107
        $configuredProperties = $this->annotationReader->getConfiguredProperties($object, true, true);
108
        /**
109
         * @var UploadableField[] $configuredProperties
110
         */
111
        foreach ($configuredProperties as $fileProperty => $fieldConfiguration) {
112
            $currentFilepath = $classMetadata->getFieldValue($object, $fieldConfiguration->property);
113
            if ($currentFilepath) {
114
                $this->removeFilepath($object, $fieldConfiguration);
0 ignored issues
show
Bug introduced by
It seems like $fieldConfiguration can also be of type string; however, parameter $fieldConfiguration of Silverback\ApiComponents...elper::removeFilepath() does only seem to accept Silverback\ApiComponents...otation\UploadableField, maybe add an additional type check? ( Ignorable by Annotation )

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

114
                $this->removeFilepath($object, /** @scrutinizer ignore-type */ $fieldConfiguration);
Loading history...
115
            }
116
            /** @var UploadedDataUriFile|null $file */
117
            $file = $propertyAccessor->getValue($object, $fileProperty);
118
            if (!$file) {
119
                $classMetadata->setFieldValue($object, $fieldConfiguration->property, null);
120
                continue;
121
            }
122
123
            $filesystem = $this->getFilesystemFromFieldConfiguration($fieldConfiguration);
0 ignored issues
show
Bug introduced by
It seems like $fieldConfiguration can also be of type string; however, parameter $fieldConfiguration of Silverback\ApiComponents...romFieldConfiguration() does only seem to accept Silverback\ApiComponents...otation\UploadableField, maybe add an additional type check? ( Ignorable by Annotation )

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

123
            $filesystem = $this->getFilesystemFromFieldConfiguration(/** @scrutinizer ignore-type */ $fieldConfiguration);
Loading history...
124
125
            $path = $fieldConfiguration->prefix ?? '';
126
            $path .= $file->getFilename();
127
            $stream = fopen($file->getRealPath(), 'r');
128
            $filesystem->writeStream($path, $stream, [
129
                'mimetype' => $file->getMimeType(),
130
            ]);
131
            $classMetadata->setFieldValue($object, $fieldConfiguration->property, $path);
132
            $propertyAccessor->setValue($object, $fileProperty, null);
133
        }
134
    }
135
136
    public function deleteFiles(object $object): void
137
    {
138
        $classMetadata = $this->getClassMetadata($object);
139
140
        $configuredProperties = $this->annotationReader->getConfiguredProperties($object, true, true);
141
        foreach ($configuredProperties as $fileProperty => $fieldConfiguration) {
142
            $currentFilepath = $classMetadata->getFieldValue($object, $fieldConfiguration->property);
143
            if ($currentFilepath) {
144
                $this->removeFilepath($object, $fieldConfiguration);
0 ignored issues
show
Bug introduced by
It seems like $fieldConfiguration can also be of type string; however, parameter $fieldConfiguration of Silverback\ApiComponents...elper::removeFilepath() does only seem to accept Silverback\ApiComponents...otation\UploadableField, maybe add an additional type check? ( Ignorable by Annotation )

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

144
                $this->removeFilepath($object, /** @scrutinizer ignore-type */ $fieldConfiguration);
Loading history...
145
            }
146
        }
147
    }
148
149
    public function getMediaObjects(object $object): ?ArrayCollection
150
    {
151
        $collection = new ArrayCollection();
152
        $classMetadata = $this->getClassMetadata($object);
153
154
        $configuredProperties = $this->annotationReader->getConfiguredProperties($object, true, true);
155
        foreach ($configuredProperties as $fileProperty => $fieldConfiguration) {
156
            $propertyMediaObjects = [];
157
            $filesystem = $this->getFilesystemFromFieldConfiguration($fieldConfiguration);
0 ignored issues
show
Bug introduced by
It seems like $fieldConfiguration can also be of type string; however, parameter $fieldConfiguration of Silverback\ApiComponents...romFieldConfiguration() does only seem to accept Silverback\ApiComponents...otation\UploadableField, maybe add an additional type check? ( Ignorable by Annotation )

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

157
            $filesystem = $this->getFilesystemFromFieldConfiguration(/** @scrutinizer ignore-type */ $fieldConfiguration);
Loading history...
158
            $path = $classMetadata->getFieldValue($object, $fieldConfiguration->property);
159
            if (!$path) {
160
                continue;
161
            }
162
            if (!$filesystem->fileExists($path)) {
163
                continue;
164
            }
165
166
            // Populate the primary MediaObject
167
            try {
168
                $propertyMediaObjects[] = $this->mediaObjectFactory->create($filesystem, $path);
169
            } catch (UnableToReadFile $exception) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
170
            }
171
172
            if ($object instanceof ImagineFiltersInterface) {
173
                array_push($propertyMediaObjects, ...$this->getMediaObjectsForImagineFilters($object, $path, $fieldConfiguration->adapter));
0 ignored issues
show
Bug introduced by
It seems like $fieldConfiguration->adapter can also be of type null; however, parameter $adapter of Silverback\ApiComponents...ectsForImagineFilters() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

173
                array_push($propertyMediaObjects, ...$this->getMediaObjectsForImagineFilters($object, $path, /** @scrutinizer ignore-type */ $fieldConfiguration->adapter));
Loading history...
174
            }
175
176
            $collection->set($fieldConfiguration->property, $propertyMediaObjects);
177
        }
178
179
        return $collection->count() ? $collection : null;
180
    }
181
182
    /**
183
     * @return MediaObject[]
184
     */
185
    private function getMediaObjectsForImagineFilters(ImagineFiltersInterface $object, string $path, string $adapter): array
186
    {
187
        // Let the data loader which should be configured for imagine to know which adapter to use
188
        $this->flysystemDataLoader->setAdapter($adapter);
189
190
        $mediaObjects = [];
191
        if (!$this->filterService) {
192
            return $mediaObjects;
193
        }
194
195
        $request = $this->requestStack->getMasterRequest();
196
        $filters = $object->getImagineFilters($request);
197
        foreach ($filters as $filter) {
198
            $resolvedUrl = $this->filterService->getUrlOfFilteredImage($path, $filter);
199
            $mediaObjects[] = $this->mediaObjectFactory->createFromImagine($resolvedUrl, $path, $filter);
200
        }
201
202
        return $mediaObjects;
203
    }
204
205
    private function getFilesystemFromFieldConfiguration(UploadableField $fieldConfiguration): Filesystem
206
    {
207
        return $this->filesystemProvider->getFilesystem($fieldConfiguration->adapter);
0 ignored issues
show
Bug introduced by
It seems like $fieldConfiguration->adapter can also be of type null; however, parameter $name of Silverback\ApiComponents...ovider::getFilesystem() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

207
        return $this->filesystemProvider->getFilesystem(/** @scrutinizer ignore-type */ $fieldConfiguration->adapter);
Loading history...
208
    }
209
210
    private function removeFilepath(object $object, UploadableField $fieldConfiguration): void
211
    {
212
        $classMetadata = $this->getClassMetadata($object);
213
214
        $filesystem = $this->filesystemProvider->getFilesystem($fieldConfiguration->adapter);
0 ignored issues
show
Bug introduced by
It seems like $fieldConfiguration->adapter can also be of type null; however, parameter $name of Silverback\ApiComponents...ovider::getFilesystem() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

214
        $filesystem = $this->filesystemProvider->getFilesystem(/** @scrutinizer ignore-type */ $fieldConfiguration->adapter);
Loading history...
215
        $currentFilepath = $classMetadata->getFieldValue($object, $fieldConfiguration->property);
216
        if ($filesystem->fileExists($currentFilepath)) {
217
            $filesystem->delete($currentFilepath);
218
        }
219
    }
220
}
221