Passed
Push — master ( 52a18c...705018 )
by Daniel
11:52
created

MediaObjectFactory   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 145
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

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

6 Methods

Rating   Name   Duplication   Size   Complexity  
A create() 0 30 4
A createFromImagine() 0 14 2
B createMediaObjects() 0 34 6
A getMediaObjectsForImagineFilters() 0 22 4
A __construct() 0 11 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\Helper\Uploadable\FileInfoCacheManager;
28
use Silverback\ApiComponentsBundle\Imagine\FlysystemDataLoader;
29
use Silverback\ApiComponentsBundle\Model\Uploadable\MediaObject;
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 FileInfoCacheManager $fileInfoCacheManager;
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(ManagerRegistry $managerRegistry, FileInfoCacheManager $fileInfoCacheManager, UploadableAnnotationReader $annotationReader, FilesystemProvider $filesystemProvider, FlysystemDataLoader $flysystemDataLoader, RequestStack $requestStack, IriConverterInterface $iriConverter, UrlHelper $urlHelper, ?FilterService $filterService = null)
52
    {
53
        $this->initRegistry($managerRegistry);
54
        $this->fileInfoCacheManager = $fileInfoCacheManager;
55
        $this->annotationReader = $annotationReader;
56
        $this->filesystemProvider = $filesystemProvider;
57
        $this->flysystemDataLoader = $flysystemDataLoader;
58
        $this->requestStack = $requestStack;
59
        $this->iriConverter = $iriConverter;
60
        $this->urlHelper = $urlHelper;
61
        $this->filterService = $filterService;
62
    }
63
64
    public function createMediaObjects(object $object): ?ArrayCollection
65
    {
66
        $collection = new ArrayCollection();
67
        $classMetadata = $this->getClassMetadata($object);
68
69
        $configuredProperties = $this->annotationReader->getConfiguredProperties($object, true);
70
71
        $resourceId = $this->iriConverter->getIriFromItem($object);
72
        foreach ($configuredProperties as $fileProperty => $fieldConfiguration) {
73
            $propertyMediaObjects = [];
74
            $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

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

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