Passed
Push — master ( a7ed20...e72196 )
by Daniel
08:57 queued 03:23
created

MediaObjectFactory   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 154
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 85
c 1
b 0
f 0
dl 0
loc 154
ccs 0
cts 80
cp 0
rs 10
wmc 18

6 Methods

Rating   Name   Duplication   Size   Complexity  
A createFromImagine() 0 14 2
A create() 0 30 4
B createMediaObjects() 0 34 6
A getMediaObjectsForImagineFilters() 0 22 4
A __construct() 0 20 1
A populateMediaObjectFromCache() 0 8 1
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\Factory\Uploadable;
15
16
use ApiPlatform\Core\Api\IriConverterInterface;
17
use Doctrine\Common\Collections\ArrayCollection;
18
use Doctrine\Persistence\ManagerRegistry;
19
use League\Flysystem\Filesystem;
20
use League\Flysystem\UnableToReadFile;
21
use Liip\ImagineBundle\Service\FilterService;
22
use Silverback\ApiComponentsBundle\Annotation\UploadableField;
23
use Silverback\ApiComponentsBundle\AnnotationReader\UploadableAnnotationReader;
24
use Silverback\ApiComponentsBundle\Entity\Core\FileInfo;
25
use Silverback\ApiComponentsBundle\Entity\Utility\ImagineFiltersInterface;
26
use Silverback\ApiComponentsBundle\Flysystem\FilesystemProvider;
27
use Silverback\ApiComponentsBundle\Imagine\FlysystemDataLoader;
28
use Silverback\ApiComponentsBundle\Model\Uploadable\MediaObject;
29
use Silverback\ApiComponentsBundle\Uploadable\FileInfoCacheHelper;
30
use Silverback\ApiComponentsBundle\Utility\ClassMetadataTrait;
31
use Symfony\Component\HttpFoundation\RequestStack;
32
use Symfony\Component\HttpFoundation\UrlHelper;
33
use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;
34
35
/**
36
 * @author Daniel West <[email protected]>
37
 */
38
class MediaObjectFactory
39
{
40
    use ClassMetadataTrait;
41
42
    private FileInfoCacheHelper $fileInfoCacheHelper;
43
    private UploadableAnnotationReader $annotationReader;
44
    private FilesystemProvider $filesystemProvider;
45
    private FlysystemDataLoader $flysystemDataLoader;
46
    private RequestStack $requestStack;
47
    private IriConverterInterface $iriConverter;
48
    private UrlHelper $urlHelper;
49
    private ?FilterService $filterService;
50
51
    public function __construct(
52
        ManagerRegistry $managerRegistry,
53
        FileInfoCacheHelper $fileInfoCacheHelper,
54
        UploadableAnnotationReader $annotationReader,
55
        FilesystemProvider $filesystemProvider,
56
        FlysystemDataLoader $flysystemDataLoader,
57
        RequestStack $requestStack,
58
        IriConverterInterface $iriConverter,
59
        UrlHelper $urlHelper,
60
        ?FilterService $filterService = null
61
    ) {
62
        $this->initRegistry($managerRegistry);
63
        $this->fileInfoCacheHelper = $fileInfoCacheHelper;
64
        $this->annotationReader = $annotationReader;
65
        $this->filesystemProvider = $filesystemProvider;
66
        $this->flysystemDataLoader = $flysystemDataLoader;
67
        $this->requestStack = $requestStack;
68
        $this->iriConverter = $iriConverter;
69
        $this->urlHelper = $urlHelper;
70
        $this->filterService = $filterService;
71
    }
72
73
    public function createMediaObjects(object $object): ?ArrayCollection
74
    {
75
        $collection = new ArrayCollection();
76
        $classMetadata = $this->getClassMetadata($object);
77
78
        $configuredProperties = $this->annotationReader->getConfiguredProperties($object, true);
79
80
        $resourceId = $this->iriConverter->getIriFromItem($object);
81
        foreach ($configuredProperties as $fileProperty => $fieldConfiguration) {
82
            $propertyMediaObjects = [];
83
            $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

83
            $filesystem = $this->filesystemProvider->getFilesystem(/** @scrutinizer ignore-type */ $fieldConfiguration->adapter);
Loading history...
84
            $path = $classMetadata->getFieldValue($object, $fieldConfiguration->property);
85
            if (!$path) {
86
                continue;
87
            }
88
            if (!$filesystem->fileExists($path)) {
89
                continue;
90
            }
91
92
            $converter = new CamelCaseToSnakeCaseNameConverter();
93
            $contentUrl = sprintf('%s/download/%s', $resourceId, $converter->normalize($fileProperty));
94
95
            // Populate the primary MediaObject
96
            try {
97
                $propertyMediaObjects[] = $this->create($filesystem, $path, $contentUrl);
98
            } catch (UnableToReadFile $exception) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
99
            }
100
101
            array_push($propertyMediaObjects, ...$this->getMediaObjectsForImagineFilters($object, $path, $fieldConfiguration, $fileProperty));
102
103
            $collection->set($fieldConfiguration->property, $propertyMediaObjects);
104
        }
105
106
        return $collection->count() ? $collection : null;
107
    }
108
109
    /**
110
     * @return MediaObject[]
111
     */
112
    private function getMediaObjectsForImagineFilters(object $object, string $path, UploadableField $uploadableField, string $fileProperty): array
113
    {
114
        $mediaObjects = [];
115
        if (!$this->filterService) {
116
            return $mediaObjects;
117
        }
118
119
        // Let the data loader which should be configured for imagine to know which adapter to use
120
        $this->flysystemDataLoader->setAdapter($uploadableField->adapter);
121
122
        $filters = $uploadableField->imagineFilters;
123
        if ($object instanceof ImagineFiltersInterface) {
124
            $request = $this->requestStack->getMasterRequest();
125
            array_push($filters, ...$object->getImagineFilters($fileProperty, $request));
0 ignored issues
show
Bug introduced by
It seems like $filters can also be of type null; however, parameter $array of array_push() does only seem to accept array, 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

125
            array_push(/** @scrutinizer ignore-type */ $filters, ...$object->getImagineFilters($fileProperty, $request));
Loading history...
126
        }
127
128
        foreach ($filters as $filter) {
129
            $resolvedUrl = $this->filterService->getUrlOfFilteredImage($path, $filter);
130
            $mediaObjects[] = $this->createFromImagine($resolvedUrl, $path, $filter);
131
        }
132
133
        return $mediaObjects;
134
    }
135
136
    private function create(Filesystem $filesystem, string $filename, string $contentUrl): MediaObject
137
    {
138
        $mediaObject = new MediaObject();
139
140
        $mediaObject->contentUrl = $this->urlHelper->getAbsoluteUrl($contentUrl);
141
        $mediaObject->imagineFilter = null;
142
143
        $fileInfo = $this->fileInfoCacheHelper->resolveCache($filename);
144
        if ($fileInfo) {
145
            return $this->populateMediaObjectFromCache($mediaObject, $fileInfo);
146
        }
147
148
        $mediaObject->fileSize = $filesystem->fileSize($filename);
149
        $mediaObject->mimeType = $filesystem->mimeType($filename);
150
        if (false !== strpos($mediaObject->mimeType, 'image/')) {
151
            $file = $filesystem->read($filename);
152
            if ('image/svg+xml' === $mediaObject->mimeType) {
153
                $xmlget = simplexml_load_string(file_get_contents($file));
154
                $xmlattributes = $xmlget->attributes();
155
                $mediaObject->width = (int) $xmlattributes->width;
156
                $mediaObject->height = (int) $xmlattributes->height;
157
            } else {
158
                [ $mediaObject->width, $mediaObject->height ] = @getimagesize($file);
159
            }
160
        }
161
162
        $fileInfo = new FileInfo($filename, $mediaObject->mimeType, $mediaObject->fileSize, $mediaObject->width, $mediaObject->height);
163
        $this->fileInfoCacheHelper->saveCache($fileInfo);
164
165
        return $mediaObject;
166
    }
167
168
    private function createFromImagine(string $contentUrl, string $path, string $imagineFilter): MediaObject
169
    {
170
        $mediaObject = new MediaObject();
171
        $mediaObject->contentUrl = $contentUrl;
172
        $mediaObject->imagineFilter = $imagineFilter;
173
174
        $fileInfo = $this->fileInfoCacheHelper->resolveCache($path, $imagineFilter);
175
        if ($fileInfo) {
176
            return $this->populateMediaObjectFromCache($mediaObject, $fileInfo);
177
        }
178
        $mediaObject->width = $mediaObject->height = $mediaObject->fileSize = -1;
179
        $mediaObject->mimeType = '';
180
181
        return $mediaObject;
182
    }
183
184
    private function populateMediaObjectFromCache(MediaObject $mediaObject, FileInfo $fileInfo): MediaObject
185
    {
186
        $mediaObject->fileSize = $fileInfo->fileSize;
187
        $mediaObject->mimeType = $fileInfo->mimeType;
188
        $mediaObject->width = $fileInfo->width;
189
        $mediaObject->height = $fileInfo->height;
190
191
        return $mediaObject;
192
    }
193
}
194