Passed
Push — main ( fe2f17...ba3d9b )
by Daniel
15:33
created

MediaObjectFactory::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
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 8
dl 0
loc 11
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\Flysystem\FilesystemProvider;
26
use Silverback\ApiComponentsBundle\Helper\Uploadable\FileInfoCacheManager;
27
use Silverback\ApiComponentsBundle\Imagine\FlysystemDataLoader;
28
use Silverback\ApiComponentsBundle\Model\Uploadable\MediaObject;
29
use Silverback\ApiComponentsBundle\Utility\ClassMetadataTrait;
30
use Symfony\Component\HttpFoundation\RequestStack;
31
32
/**
33
 * @author Daniel West <[email protected]>
34
 */
35
class MediaObjectFactory
36
{
37
    use ClassMetadataTrait;
38
39
    public function __construct(
40
        ManagerRegistry $managerRegistry,
41
        private readonly FileInfoCacheManager $fileInfoCacheManager,
42
        private readonly UploadableAttributeReader $annotationReader,
43
        private readonly FilesystemProvider $filesystemProvider,
44
        private readonly FlysystemDataLoader $flysystemDataLoader,
45
        private readonly RequestStack $requestStack,
46
        private readonly ApiUrlGenerator $urlGenerator,
47
        private readonly ?FilterService $filterService = null)
48
    {
49
        $this->initRegistry($managerRegistry);
50
    }
51
52
    public function createMediaObjects(object $object): ?ArrayCollection
53
    {
54
        $collection = new ArrayCollection();
55
        $classMetadata = $this->getClassMetadata($object);
56
57
        $configuredProperties = $this->annotationReader->getConfiguredProperties($object, true);
58
59
        foreach ($configuredProperties as $fileProperty => $fieldConfiguration) {
60
            $propertyMediaObjects = [];
61
            // todo: we may need to look at the performance of this when getting the components. yes, the response is cached, but even first load on a page with lots of files, could be very bad
62
            $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

62
            $filesystem = $this->filesystemProvider->getFilesystem(/** @scrutinizer ignore-type */ $fieldConfiguration->adapter);
Loading history...
63
            $path = $classMetadata->getFieldValue($object, $fieldConfiguration->property);
64
            if (!$path) {
65
                continue;
66
            }
67
            if (!$filesystem->fileExists($path)) {
68
                continue;
69
            }
70
71
            // todo: the content URL perhaps will just be a public URL from the source/CDN instead of via this API download action
72
//            if ($filesystem instanceof PublicUrlGenerator) {
73
//                // $filesystem->publicUrl();
74
//            }
75
//            if ($filesystem instanceof TemporaryUrlGenerator) {
76
//                // $filesystem->temporaryUrl();
77
//            }
78
            $contentUrl = $this->urlGenerator->generateUrl($object, $fileProperty);
79
80
            // Populate the primary MediaObject
81
            try {
82
                $propertyMediaObjects[] = $this->create($filesystem, $path, $contentUrl);
83
            } catch (UnableToReadFile $exception) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
84
            }
85
86
            array_push($propertyMediaObjects, ...$this->getMediaObjectsForImagineFilters($object, $path, $fieldConfiguration, $fileProperty));
87
88
            $collection->set($fileProperty, $propertyMediaObjects);
89
        }
90
91
        return $collection->count() ? $collection : null;
92
    }
93
94
    /**
95
     * @return MediaObject[]
96
     */
97
    private function getMediaObjectsForImagineFilters(object $object, string $path, UploadableField $uploadableField, string $fileProperty): array
98
    {
99
        $mediaObjects = [];
100
        if (!$this->filterService) {
101
            return $mediaObjects;
102
        }
103
104
        // Let the data loader which should be configured for imagine to know which adapter to use
105
        $this->flysystemDataLoader->setAdapter($uploadableField->adapter);
106
107
        $filters = $uploadableField->imagineFilters;
108
        if ($object instanceof ImagineFiltersInterface) {
109
            $request = $this->requestStack->getMainRequest();
110
            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

110
            array_push(/** @scrutinizer ignore-type */ $filters, ...$object->getImagineFilters($fileProperty, $request));
Loading history...
111
        }
112
113
        foreach ($filters as $filter) {
114
            $resolvedUrl = $this->filterService->getUrlOfFilteredImage($path, $filter);
115
            $mediaObjects[] = $this->createFromImagine($resolvedUrl, $path, $filter);
116
        }
117
118
        return $mediaObjects;
119
    }
120
121
    private function create(Filesystem $filesystem, string $filename, string $contentUrl): MediaObject
122
    {
123
        $mediaObject = new MediaObject();
124
125
        $mediaObject->contentUrl = $contentUrl;
126
        $mediaObject->imagineFilter = null;
127
128
        $fileInfo = $this->fileInfoCacheManager->resolveCache($filename);
129
        if ($fileInfo) {
130
            return $this->populateMediaObjectFromCache($mediaObject, $fileInfo);
131
        }
132
133
        $mediaObject->fileSize = $filesystem->fileSize($filename);
134
        $mediaObject->mimeType = $filesystem->mimeType($filename);
135
        if (str_contains($mediaObject->mimeType, 'image/')) {
136
            $file = str_replace("\0", '', $filesystem->read($filename));
137
            if ('image/svg+xml' === $mediaObject->mimeType) {
138
                $xmlGet = simplexml_load_string($file);
139
                $xmlAttributes = $xmlGet->attributes();
140
                $mediaObject->width = $xmlAttributes ? (int) $xmlAttributes->width : null;
141
                $mediaObject->height = $xmlAttributes ? (int) $xmlAttributes->height : null;
142
            } else {
143
                [$mediaObject->width, $mediaObject->height] = @getimagesize($file);
144
            }
145
        }
146
147
        $fileInfo = new FileInfo($filename, $mediaObject->mimeType, $mediaObject->fileSize, $mediaObject->width, $mediaObject->height);
148
        $this->fileInfoCacheManager->saveCache($fileInfo);
149
150
        return $mediaObject;
151
    }
152
153
    private function createFromImagine(string $contentUrl, string $path, string $imagineFilter): MediaObject
154
    {
155
        $mediaObject = new MediaObject();
156
        $mediaObject->contentUrl = $contentUrl;
157
        $mediaObject->imagineFilter = $imagineFilter;
158
159
        $fileInfo = $this->fileInfoCacheManager->resolveCache($path, $imagineFilter);
160
        if ($fileInfo) {
161
            return $this->populateMediaObjectFromCache($mediaObject, $fileInfo);
162
        }
163
164
        // todo: check why we are setting this, from imagine we should know this info I'm guessing
165
        // todo: should we not save the info to cache as well as above?
166
        $mediaObject->width = $mediaObject->height = $mediaObject->fileSize = -1;
167
        $mediaObject->mimeType = '';
168
169
        return $mediaObject;
170
    }
171
172
    private function populateMediaObjectFromCache(MediaObject $mediaObject, FileInfo $fileInfo): MediaObject
173
    {
174
        $mediaObject->fileSize = $fileInfo->fileSize;
175
        $mediaObject->mimeType = $fileInfo->mimeType;
176
        $mediaObject->width = $fileInfo->width;
177
        $mediaObject->height = $fileInfo->height;
178
179
        return $mediaObject;
180
    }
181
}
182