Passed
Push — main ( 4ecde6...2875e2 )
by Daniel
15:20
created

MediaObjectFactory::createMediaObjects()   C

Complexity

Conditions 12
Paths 21

Size

Total Lines 48
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 156

Importance

Changes 2
Bugs 0 Features 1
Metric Value
cc 12
eloc 28
nc 21
nop 1
dl 0
loc 48
ccs 0
cts 27
cp 0
crap 156
rs 6.9666
c 2
b 0
f 1

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 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\AttributeReader\UploadableAttributeReader;
23
use Silverback\ApiComponentsBundle\Entity\Core\FileInfo;
24
use Silverback\ApiComponentsBundle\Entity\Utility\ImagineFiltersInterface;
25
use Silverback\ApiComponentsBundle\Exception\InvalidArgumentException;
26
use Silverback\ApiComponentsBundle\Flysystem\FilesystemFactory;
27
use Silverback\ApiComponentsBundle\Flysystem\FilesystemProvider;
28
use Silverback\ApiComponentsBundle\Helper\Uploadable\FileInfoCacheManager;
29
use Silverback\ApiComponentsBundle\Imagine\FlysystemDataLoader;
30
use Silverback\ApiComponentsBundle\Model\Uploadable\MediaObject;
31
use Silverback\ApiComponentsBundle\Utility\ClassMetadataTrait;
32
use Symfony\Component\DependencyInjection\ServiceLocator;
33
use Symfony\Component\HttpFoundation\RequestStack;
34
35
/**
36
 * @author Daniel West <[email protected]>
37
 */
38
class MediaObjectFactory
39
{
40
    use ClassMetadataTrait;
41
42
    public function __construct(
43
        ManagerRegistry $managerRegistry,
44
        private readonly FileInfoCacheManager $fileInfoCacheManager,
45
        private readonly UploadableAttributeReader $annotationReader,
46
        private readonly FilesystemProvider $filesystemProvider,
47
        private readonly FlysystemDataLoader $flysystemDataLoader,
48
        private readonly RequestStack $requestStack,
49
        private readonly ServiceLocator $urlGenerators,
50
        private readonly FilesystemFactory $filesystemFactory,
51
        private readonly ?FilterService $filterService = null
52
    ) {
53
        $this->initRegistry($managerRegistry);
54
    }
55
56
    public function createMediaObjects(object $object): ?ArrayCollection
57
    {
58
        $collection = new ArrayCollection();
59
        $classMetadata = $this->getClassMetadata($object);
60
61
        $configuredProperties = $this->annotationReader->getConfiguredProperties($object, true);
62
63
        foreach ($configuredProperties as $fileProperty => $fieldConfiguration) {
64
            $propertyMediaObjects = [];
65
66
            $filesystem = $this->filesystemProvider->getFilesystem($fieldConfiguration->adapter);
67
            $path = $classMetadata->getFieldValue($object, $fieldConfiguration->property);
68
            if (!$path) {
69
                continue;
70
            }
71
72
            if (!$filesystem->fileExists($path)) {
73
                continue;
74
            }
75
76
            $urlGenerator = $fieldConfiguration->urlGenerator;
77
            if ($urlGenerator !== 'api') {
78
                $adapter = $this->filesystemFactory->getAdapter($fieldConfiguration->adapter);
79
                if (
80
                    ($urlGenerator === 'temporary' && !($adapter instanceof \League\Flysystem\UrlGeneration\TemporaryUrlGenerator)) ||
81
                    ($urlGenerator === 'public' && !($adapter instanceof \League\Flysystem\UrlGeneration\PublicUrlGenerator))
82
                ) {
83
                    $urlGenerator = 'api';
84
                }
85
            }
86
            $urlGenerator = $this->urlGenerators->get($urlGenerator);
87
            if (!$urlGenerator instanceof UploadableUrlGeneratorInterface) {
88
                throw new InvalidArgumentException(sprintf('The url generator provided must implement %s', UploadableUrlGeneratorInterface::class));
89
            }
90
            $contentUrl = $urlGenerator->generateUrl($object, $fileProperty, $filesystem, $path);
91
92
            // Populate the primary MediaObject
93
            try {
94
                $propertyMediaObjects[] = $this->create($filesystem, $path, $contentUrl);
95
            } catch (UnableToReadFile $exception) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
96
            }
97
98
            array_push($propertyMediaObjects, ...$this->getMediaObjectsForImagineFilters($object, $path, $fieldConfiguration, $fileProperty));
99
100
            $collection->set($fileProperty, $propertyMediaObjects);
101
        }
102
103
        return $collection->count() ? $collection : null;
104
    }
105
106
    /**
107
     * @return MediaObject[]
108
     */
109
    private function getMediaObjectsForImagineFilters(object $object, string $path, UploadableField $uploadableField, string $fileProperty): array
110
    {
111
        $mediaObjects = [];
112
        if (!$this->filterService) {
113
            return $mediaObjects;
114
        }
115
116
        // Let the data loader which should be configured for imagine to know which adapter to use
117
        $this->flysystemDataLoader->setAdapter($uploadableField->adapter);
118
119
        $filters = $uploadableField->imagineFilters;
120
        if ($object instanceof ImagineFiltersInterface) {
121
            $request = $this->requestStack->getMainRequest();
122
            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

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