MediaObjectFactory::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
nc 1
nop 9
dl 0
loc 12
ccs 0
cts 2
cp 0
crap 2
rs 10
c 1
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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 FilesystemFactory $filesystemFactory,
50
        private readonly ServiceLocator $urlGenerators,
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
            // todo: consultation on perhaps attributes which can be configured with environment variables or best way to achieve easier implementation
77
            $urlGeneratorReference = $fieldConfiguration->urlGenerator ?? 'api';
78
            $urlGenerator = $this->urlGenerators->get($urlGeneratorReference);
79
            if ('api' !== $urlGenerator) {
80
                $adapter = $this->filesystemFactory->getAdapter($fieldConfiguration->adapter);
81
                if (
82
                    ($urlGenerator instanceof TemporaryUrlGenerator && !($adapter instanceof \League\Flysystem\UrlGeneration\TemporaryUrlGenerator))
83
                    || ($urlGenerator instanceof PublicUrlGenerator && !($adapter instanceof \League\Flysystem\UrlGeneration\PublicUrlGenerator))
84
                ) {
85
                    $urlGeneratorReference = 'api';
86
                    $urlGenerator = $this->urlGenerators->get($urlGeneratorReference);
87
                }
88
            }
89
90
            if (!$urlGenerator instanceof UploadableUrlGeneratorInterface) {
91
                throw new InvalidArgumentException(sprintf('The url generator provided must implement %s', UploadableUrlGeneratorInterface::class));
92
            }
93
            $contentUrl = $urlGenerator->generateUrl($object, $fileProperty, $filesystem, $path);
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($fileProperty, $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->getMainRequest();
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 = $contentUrl;
141
        $mediaObject->imagineFilter = null;
142
143
        $fileInfo = $this->fileInfoCacheManager->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 (str_contains($mediaObject->mimeType, 'image/')) {
151
            $file = str_replace("\0", '', $filesystem->read($filename));
152
            if ('image/svg+xml' === $mediaObject->mimeType) {
153
                $xmlGet = simplexml_load_string($file);
154
                $xmlAttributes = $xmlGet->attributes();
155
                $mediaObject->width = $xmlAttributes ? (int) $xmlAttributes->width : null;
156
                $mediaObject->height = $xmlAttributes ? (int) $xmlAttributes->height : null;
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->fileInfoCacheManager->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->fileInfoCacheManager->resolveCache($path, $imagineFilter);
175
        if ($fileInfo) {
176
            return $this->populateMediaObjectFromCache($mediaObject, $fileInfo);
177
        }
178
179
        $mediaObject->width = $mediaObject->height = $mediaObject->fileSize = -1;
180
        $mediaObject->mimeType = '';
181
182
        return $mediaObject;
183
    }
184
185
    private function populateMediaObjectFromCache(MediaObject $mediaObject, FileInfo $fileInfo): MediaObject
186
    {
187
        $mediaObject->fileSize = $fileInfo->fileSize;
188
        $mediaObject->mimeType = $fileInfo->mimeType;
189
        $mediaObject->width = $fileInfo->width;
190
        $mediaObject->height = $fileInfo->height;
191
192
        return $mediaObject;
193
    }
194
}
195