Passed
Push — master ( eb41ee...393929 )
by
unknown
11:11
created

ImageService::getImage()   B

Complexity

Conditions 11
Paths 7

Size

Total Lines 40
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 19
c 2
b 0
f 0
dl 0
loc 40
rs 7.3166
cc 11
nc 7
nop 3

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
declare(strict_types=1);
4
5
/*
6
 * This file is part of the TYPO3 CMS project.
7
 *
8
 * It is free software; you can redistribute it and/or modify it under
9
 * the terms of the GNU General Public License, either version 2
10
 * of the License, or any later version.
11
 *
12
 * For the full copyright and license information, please read the
13
 * LICENSE.txt file that was distributed with this source code.
14
 *
15
 * The TYPO3 project - inspiring people to share!
16
 */
17
18
namespace TYPO3\CMS\Extbase\Service;
19
20
use Psr\Http\Message\ServerRequestInterface;
21
use TYPO3\CMS\Core\Http\ApplicationType;
22
use TYPO3\CMS\Core\LinkHandling\LinkService;
23
use TYPO3\CMS\Core\Page\AssetCollector;
24
use TYPO3\CMS\Core\Resource\File;
25
use TYPO3\CMS\Core\Resource\FileInterface;
26
use TYPO3\CMS\Core\Resource\FileReference;
27
use TYPO3\CMS\Core\Resource\ProcessedFile;
28
use TYPO3\CMS\Core\Resource\ResourceFactory;
29
use TYPO3\CMS\Core\SingletonInterface;
30
use TYPO3\CMS\Core\Utility\GeneralUtility;
31
use TYPO3\CMS\Core\Utility\MathUtility;
32
33
/**
34
 * Service for processing images
35
 */
36
class ImageService implements SingletonInterface
37
{
38
    /**
39
     * @var ResourceFactory
40
     */
41
    protected $resourceFactory;
42
43
    /**
44
     * ImageService constructor.
45
     *
46
     * @param ResourceFactory $resourceFactory
47
     */
48
    public function __construct(ResourceFactory $resourceFactory)
49
    {
50
        $this->resourceFactory = $resourceFactory;
51
    }
52
53
    /**
54
     * Create a processed file
55
     *
56
     * @param FileInterface|FileReference $image
57
     * @param array $processingInstructions
58
     * @return ProcessedFile
59
     */
60
    public function applyProcessingInstructions($image, array $processingInstructions): ProcessedFile
61
    {
62
        /*
63
         * todo: this method should be split to be able to have a proper method signature.
64
         * todo: actually, this method only really works with objects of type \TYPO3\CMS\Core\Resource\File, as this
65
         * todo: is the only implementation that supports the support method.
66
         */
67
        if (is_callable([$image, 'getOriginalFile'])) {
68
            // Get the original file from the file reference
69
            $image = $image->getOriginalFile();
0 ignored issues
show
Bug introduced by
The method getOriginalFile() does not exist on TYPO3\CMS\Core\Resource\FileInterface. It seems like you code against a sub-type of TYPO3\CMS\Core\Resource\FileInterface such as TYPO3\CMS\Core\Resource\FileReference or TYPO3\CMS\Core\Resource\ProcessedFile. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

69
            /** @scrutinizer ignore-call */ 
70
            $image = $image->getOriginalFile();
Loading history...
70
        }
71
72
        $processedImage = $image->process(ProcessedFile::CONTEXT_IMAGECROPSCALEMASK, $processingInstructions);
0 ignored issues
show
Bug introduced by
The method process() does not exist on TYPO3\CMS\Core\Resource\FileInterface. It seems like you code against a sub-type of TYPO3\CMS\Core\Resource\FileInterface such as TYPO3\CMS\Core\Resource\File. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

72
        /** @scrutinizer ignore-call */ 
73
        $processedImage = $image->process(ProcessedFile::CONTEXT_IMAGECROPSCALEMASK, $processingInstructions);
Loading history...
Bug introduced by
The method process() does not exist on TYPO3\CMS\Core\Resource\FileReference. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

72
        /** @scrutinizer ignore-call */ 
73
        $processedImage = $image->process(ProcessedFile::CONTEXT_IMAGECROPSCALEMASK, $processingInstructions);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
73
        $this->setCompatibilityValues($processedImage);
74
75
        return $processedImage;
76
    }
77
78
    /**
79
     * Get public url of image depending on the environment
80
     *
81
     * @param FileInterface $image
82
     * @param bool|false $absolute Force absolute URL
83
     * @return string
84
     */
85
    public function getImageUri(FileInterface $image, bool $absolute = false): string
86
    {
87
        $imageUrl = $image->getPublicUrl();
88
        if ($imageUrl === null) {
89
            // Image is missing probably, return an empty string instead of parsing
90
            return '';
91
        }
92
93
        $parsedUrl = parse_url($imageUrl);
94
        // no prefix in case of an already fully qualified URL
95
        if (isset($parsedUrl['host'])) {
96
            $uriPrefix = '';
97
        } elseif (($GLOBALS['TYPO3_REQUEST'] ?? null) instanceof ServerRequestInterface
98
            && ApplicationType::fromRequest($GLOBALS['TYPO3_REQUEST'])->isFrontend()
99
        ) {
100
            $uriPrefix = $GLOBALS['TSFE']->absRefPrefix;
101
        } else {
102
            $uriPrefix = GeneralUtility::getIndpEnv('TYPO3_SITE_PATH');
103
        }
104
105
        if ($absolute) {
106
            // If full URL has no scheme we add the same scheme as used by the site
107
            // so we have an absolute URL also usable outside of browser scope (e.g. in an email message)
108
            if (isset($parsedUrl['host']) && !isset($parsedUrl['scheme'])) {
109
                $uriPrefix = (GeneralUtility::getIndpEnv('TYPO3_SSL') ? 'https:' : 'http:') . $uriPrefix;
110
            }
111
            return GeneralUtility::locationHeaderUrl($uriPrefix . $imageUrl);
112
        }
113
        return $uriPrefix . $imageUrl;
114
    }
115
116
    /**
117
     * Get File or FileReference object
118
     *
119
     * This method is a factory and compatibility method that does not belong to
120
     * this service, but is put here for pragmatic reasons for the time being.
121
     * It should be removed once we do not support string sources for images anymore.
122
     *
123
     * @param string $src
124
     * @param FileInterface|\TYPO3\CMS\Extbase\Domain\Model\FileReference|null $image
125
     * @param bool $treatIdAsReference
126
     * @return FileInterface|File|FileReference
127
     * @throws \UnexpectedValueException
128
     * @internal
129
     */
130
    public function getImage(string $src, $image, bool $treatIdAsReference): FileInterface
131
    {
132
        if ($image instanceof File || $image instanceof FileReference) {
133
            // We already received a valid file and therefore just return it
134
            return $image;
135
        }
136
137
        if (is_callable([$image, 'getOriginalResource'])) {
138
            // We have a domain model, so we need to fetch the FAL resource object from there
139
            $originalResource = $image->getOriginalResource();
0 ignored issues
show
Bug introduced by
The method getOriginalResource() does not exist on TYPO3\CMS\Core\Resource\FileInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

139
            /** @scrutinizer ignore-call */ 
140
            $originalResource = $image->getOriginalResource();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
Bug introduced by
The method getOriginalResource() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

139
            /** @scrutinizer ignore-call */ 
140
            $originalResource = $image->getOriginalResource();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
140
            if (!($originalResource instanceof File || $originalResource instanceof FileReference)) {
0 ignored issues
show
introduced by
$originalResource is always a sub-type of TYPO3\CMS\Core\Resource\FileReference.
Loading history...
141
                throw new \UnexpectedValueException('No original resource could be resolved for supplied file ' . get_class($image), 1625838481);
142
            }
143
            return $originalResource;
144
        }
145
146
        if ($image !== null) {
147
            // Some value is given for $image, but it's not a valid type
148
            throw new \UnexpectedValueException(
149
                'Supplied file must be File or FileReference, ' . (($type = gettype($image)) === 'object' ? get_class($image) : $type) . ' given.',
150
                1625585157
151
            );
152
        }
153
154
        // Since image is not given, try to resolve an image from the source string
155
        $resolvedImage = $this->getImageFromSourceString($src, $treatIdAsReference);
156
157
        if ($resolvedImage instanceof File || $resolvedImage instanceof FileReference) {
158
            return $resolvedImage;
159
        }
160
161
        if ($resolvedImage === null) {
162
            // No image could be resolved using the given source string
163
            throw new \UnexpectedValueException('Supplied ' . $src . ' could not be resolved to a File or FileReference.', 1625585158);
164
        }
165
166
        // A FileInterface was found, however only File and FileReference are valid
167
        throw new \UnexpectedValueException(
168
            'Resolved file object type ' . get_class($resolvedImage) . ' for ' . $src . ' must be File or FileReference.',
169
            1382687163
170
        );
171
    }
172
173
    /**
174
     * Get File or FileReference object by src
175
     *
176
     * @param string $src
177
     * @param bool $treatIdAsReference
178
     * @return FileInterface|null
179
     */
180
    protected function getImageFromSourceString(string $src, bool $treatIdAsReference): ?FileInterface
181
    {
182
        if (($GLOBALS['TYPO3_REQUEST'] ?? null) instanceof ServerRequestInterface
183
            && ApplicationType::fromRequest($GLOBALS['TYPO3_REQUEST'])->isBackend()
184
            && strpos($src, '../') === 0
185
        ) {
186
            $src = substr($src, 3);
187
        }
188
        if (MathUtility::canBeInterpretedAsInteger($src)) {
189
            if ($treatIdAsReference) {
190
                $image = $this->resourceFactory->getFileReferenceObject($src);
0 ignored issues
show
Bug introduced by
$src of type string is incompatible with the type integer expected by parameter $uid of TYPO3\CMS\Core\Resource\...etFileReferenceObject(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

190
                $image = $this->resourceFactory->getFileReferenceObject(/** @scrutinizer ignore-type */ $src);
Loading history...
191
            } else {
192
                $image = $this->resourceFactory->getFileObject($src);
0 ignored issues
show
Bug introduced by
$src of type string is incompatible with the type integer expected by parameter $uid of TYPO3\CMS\Core\Resource\...actory::getFileObject(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

192
                $image = $this->resourceFactory->getFileObject(/** @scrutinizer ignore-type */ $src);
Loading history...
193
            }
194
        } elseif (strpos($src, 't3://file') === 0) {
195
            // We have a t3://file link to a file in FAL
196
            $linkService = GeneralUtility::makeInstance(LinkService::class);
197
            $data = $linkService->resolveByStringRepresentation($src);
198
            $image = $data['file'];
199
        } else {
200
            // We have a combined identifier or legacy (storage 0) path
201
            $image = $this->resourceFactory->retrieveFileOrFolderObject($src);
202
        }
203
204
        // Check the resolved image as this could also be a FolderInterface
205
        return $image instanceof FileInterface ? $image : null;
206
    }
207
208
    /**
209
     * Set compatibility values to frontend controller object
210
     * in case we are in frontend environment.
211
     *
212
     * @param ProcessedFile $processedImage
213
     */
214
    protected function setCompatibilityValues(ProcessedFile $processedImage): void
215
    {
216
        $publicUrl = $processedImage->getPublicUrl();
217
        if ($publicUrl !== null) {
218
            // only add the processed image to AssetCollector if the public url is not NULL
219
            $imageInfoValues = $this->getCompatibilityImageResourceValues($processedImage);
220
            GeneralUtility::makeInstance(AssetCollector::class)->addMedia(
221
                $publicUrl,
222
                $imageInfoValues
223
            );
224
        }
225
    }
226
227
    /**
228
     * Calculates the compatibility values
229
     * This is duplicate code taken from ContentObjectRenderer::getImgResource()
230
     * Ideally we should get rid of this code in both places.
231
     *
232
     * @param ProcessedFile $processedImage
233
     * @return array
234
     */
235
    protected function getCompatibilityImageResourceValues(ProcessedFile $processedImage): array
236
    {
237
        $originalFile = $processedImage->getOriginalFile();
238
        return [
239
            0 => $processedImage->getProperty('width'),
240
            1 => $processedImage->getProperty('height'),
241
            2 => $processedImage->getExtension(),
242
            3 => $processedImage->getPublicUrl(),
243
            'origFile' => $originalFile->getPublicUrl(),
244
            'origFile_mtime' => $originalFile->getModificationTime(),
245
        ];
246
    }
247
}
248