Completed
Push — master ( 173f5d...31a9ea )
by
unknown
15:41 queued 11s
created

ImageProvider::getFormatsForContext()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Sonata Project package.
7
 *
8
 * (c) Thomas Rabaix <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Sonata\MediaBundle\Provider;
15
16
use Gaufrette\Filesystem;
17
use Imagine\Image\ImagineInterface;
18
use Sonata\MediaBundle\CDN\CDNInterface;
19
use Sonata\MediaBundle\Generator\GeneratorInterface;
20
use Sonata\MediaBundle\Metadata\MetadataBuilderInterface;
21
use Sonata\MediaBundle\Model\MediaInterface;
22
use Sonata\MediaBundle\Thumbnail\ThumbnailInterface;
23
use Symfony\Component\HttpFoundation\File\File;
24
use Symfony\Component\HttpFoundation\File\UploadedFile;
25
26
/**
27
 * @final since sonata-project/media-bundle 3.21.0
28
 */
29
class ImageProvider extends FileProvider
30
{
31
    /**
32
     * @var ImagineInterface
33
     */
34
    protected $imagineAdapter;
35
36
    /**
37
     * @param string                   $name
38
     * @param MetadataBuilderInterface $metadata
39
     */
40
    public function __construct($name, Filesystem $filesystem, CDNInterface $cdn, GeneratorInterface $pathGenerator, ThumbnailInterface $thumbnail, array $allowedExtensions, array $allowedMimeTypes, ImagineInterface $adapter, ?MetadataBuilderInterface $metadata = null)
41
    {
42
        parent::__construct($name, $filesystem, $cdn, $pathGenerator, $thumbnail, $allowedExtensions, $allowedMimeTypes, $metadata);
43
44
        $this->imagineAdapter = $adapter;
45
    }
46
47
    /**
48
     * {@inheritdoc}
49
     */
50
    public function getProviderMetadata()
51
    {
52
        return new Metadata(
53
            $this->getName(),
54
            $this->getName().'.description',
55
            null,
56
            'SonataMediaBundle',
57
            ['class' => 'fa fa-picture-o']
58
        );
59
    }
60
61
    /**
62
     * {@inheritdoc}
63
     */
64
    public function getHelperProperties(MediaInterface $media, $format, $options = [])
65
    {
66
        if (isset($options['srcset'], $options['picture'])) {
67
            throw new \LogicException("The 'srcset' and 'picture' options must not be used simultaneously.");
68
        }
69
70
        if (MediaProviderInterface::FORMAT_REFERENCE === $format) {
71
            $box = $media->getBox();
72
        } else {
73
            $resizerFormat = $this->getFormat($format);
74
            if (false === $resizerFormat) {
75
                throw new \RuntimeException(sprintf('The image format "%s" is not defined.
76
                        Is the format registered in your ``sonata_media`` configuration?', $format));
77
            }
78
79
            $box = $this->resizer->getBox($media, $resizerFormat);
80
        }
81
82
        $mediaWidth = $box->getWidth();
83
84
        $params = [
85
            'alt' => $media->getDescription() ?: $media->getName(),
86
            'title' => $media->getName(),
87
            'src' => $this->generatePublicUrl($media, $format),
88
            'width' => $mediaWidth,
89
            'height' => $box->getHeight(),
90
        ];
91
92
        if (isset($options['picture'])) {
93
            $pictureParams = [];
94
            foreach ($options['picture'] as $key => $pictureFormat) {
95
                $formatName = $this->getFormatName($media, $pictureFormat);
96
                $settings = $this->getFormat($formatName);
97
                $src = $this->generatePublicUrl($media, $formatName);
98
                $mediaQuery = \is_string($key)
99
                    ? $key
100
                    : sprintf('(max-width: %dpx)', $this->resizer->getBox($media, $settings)->getWidth());
0 ignored issues
show
Security Bug introduced by
It seems like $settings defined by $this->getFormat($formatName) on line 96 can also be of type false; however, Sonata\MediaBundle\Resiz...izerInterface::getBox() does only seem to accept array, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
101
102
                $pictureParams['source'][] = ['media' => $mediaQuery, 'srcset' => $src];
103
            }
104
105
            unset($options['picture']);
106
            $pictureParams['img'] = $params + $options;
107
            $params = ['picture' => $pictureParams];
108
        } elseif (MediaProviderInterface::FORMAT_ADMIN !== $format) {
109
            $srcSetFormats = $this->getFormats();
110
111
            if (isset($options['srcset']) && \is_array($options['srcset'])) {
112
                $srcSetFormats = [];
113
                foreach ($options['srcset'] as $srcSetFormat) {
114
                    $formatName = $this->getFormatName($media, $srcSetFormat);
115
                    $srcSetFormats[$formatName] = $this->getFormat($formatName);
116
                }
117
                unset($options['srcset']);
118
119
                // Make sure the requested format is also in the srcSetFormats
120
                if (!isset($srcSetFormats[$format])) {
121
                    $srcSetFormats[$format] = $this->getFormat($format);
122
                }
123
            }
124
125
            if (!isset($options['srcset'])) {
126
                $srcSet = [];
127
128
                foreach ($srcSetFormats as $providerFormat => $settings) {
129
                    // Check if format belongs to the current media's context
130
                    if (0 === strpos($providerFormat, $media->getContext())) {
131
                        $width = $this->resizer->getBox($media, $settings)->getWidth();
132
133
                        $srcSet[] = sprintf('%s %dw', $this->generatePublicUrl($media, $providerFormat), $width);
134
                    }
135
                }
136
137
                // The reference format is not in the formats list
138
                $srcSet[] = sprintf(
139
                    '%s %dw',
140
                    $this->generatePublicUrl($media, MediaProviderInterface::FORMAT_REFERENCE),
141
                    $media->getBox()->getWidth()
142
                );
143
144
                $params['srcset'] = implode(', ', $srcSet);
145
            }
146
147
            $params['sizes'] = sprintf('(max-width: %1$dpx) 100vw, %1$dpx', $mediaWidth);
148
        }
149
150
        return array_merge($params, $options);
151
    }
152
153
    /**
154
     * {@inheritdoc}
155
     */
156
    public function updateMetadata(MediaInterface $media, $force = true): void
157
    {
158
        try {
159
            if (!$media->getBinaryContent() instanceof \SplFileInfo) {
160
                // this is now optimized at all!!!
161
                $path = tempnam(sys_get_temp_dir(), 'sonata_update_metadata');
162
                $fileObject = new \SplFileObject($path, 'w');
163
                $fileObject->fwrite($this->getReferenceFile($media)->getContent());
164
            } else {
165
                $fileObject = $media->getBinaryContent();
166
            }
167
168
            $image = $this->imagineAdapter->open($fileObject->getPathname());
169
            $size = $image->getSize();
170
171
            $media->setSize($fileObject->getSize());
172
            $media->setWidth($size->getWidth());
173
            $media->setHeight($size->getHeight());
174
        } catch (\LogicException $e) {
175
            $media->setProviderStatus(MediaInterface::STATUS_ERROR);
176
177
            $media->setSize(0);
178
            $media->setWidth(0);
179
            $media->setHeight(0);
180
        }
181
    }
182
183
    /**
184
     * {@inheritdoc}
185
     */
186
    public function generatePublicUrl(MediaInterface $media, $format)
187
    {
188
        if (MediaProviderInterface::FORMAT_REFERENCE === $format) {
189
            $path = $this->getReferenceImage($media);
190
        } else {
191
            $path = $this->thumbnail->generatePublicUrl($this, $media, $format);
192
        }
193
194
        // if $path is already an url, no further action is required
195
        if (null !== parse_url($path, PHP_URL_SCHEME)) {
196
            return $path;
197
        }
198
199
        return $this->getCdn()->getPath($path, $media->getCdnIsFlushable());
200
    }
201
202
    /**
203
     * {@inheritdoc}
204
     */
205
    public function generatePrivateUrl(MediaInterface $media, $format)
206
    {
207
        return $this->thumbnail->generatePrivateUrl($this, $media, $format);
208
    }
209
210
    /**
211
     * @return array<string, mixed>
0 ignored issues
show
Documentation introduced by
The doc-type array<string, could not be parsed: Expected ">" at position 5, but found "end of type". (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
212
     */
213
    public function getFormatsForContext(string $context): array
214
    {
215
        return array_filter($this->getFormats(), static function (string $providerFormat) use ($context): bool {
216
            return 0 === strpos($providerFormat, $context);
217
        }, ARRAY_FILTER_USE_KEY);
218
    }
219
220
    /**
221
     * {@inheritdoc}
222
     */
223
    protected function doTransform(MediaInterface $media): void
224
    {
225
        parent::doTransform($media);
226
227
        if ($media->getBinaryContent() instanceof UploadedFile) {
228
            $fileName = $media->getBinaryContent()->getClientOriginalName();
229
        } elseif ($media->getBinaryContent() instanceof File) {
230
            $fileName = $media->getBinaryContent()->getFilename();
231
        } else {
232
            // Should not happen, FileProvider should throw an exception in that case
233
            return;
234
        }
235
236
        if (!\in_array(strtolower(pathinfo($fileName, PATHINFO_EXTENSION)), $this->allowedExtensions, true)
237
            || !\in_array($media->getBinaryContent()->getMimeType(), $this->allowedMimeTypes, true)) {
238
            return;
239
        }
240
241
        try {
242
            $image = $this->imagineAdapter->open($media->getBinaryContent()->getPathname());
243
        } catch (\RuntimeException $e) {
244
            $media->setProviderStatus(MediaInterface::STATUS_ERROR);
245
246
            return;
247
        }
248
249
        $size = $image->getSize();
250
251
        $media->setWidth($size->getWidth());
252
        $media->setHeight($size->getHeight());
253
254
        $media->setProviderStatus(MediaInterface::STATUS_OK);
255
    }
256
}
257