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

MediaObjectFactory::__construct()   A

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 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