Completed
Push — master ( 9d1467...eea971 )
by
unknown
11:57
created

AbstractProvider   B

Complexity

Total Complexity 42

Size/Duplication

Total Lines 474
Duplicated Lines 7.59 %

Coupling/Cohesion

Components 5
Dependencies 9

Test Coverage

Coverage 85.64%

Importance

Changes 0
Metric Value
wmc 42
lcom 5
cbo 9
dl 36
loc 474
ccs 155
cts 181
cp 0.8564
rs 8.295
c 0
b 0
f 0

28 Methods

Rating   Name   Duplication   Size   Complexity  
A setFilesystem() 0 4 1
A setTranslator() 0 4 1
A getTranslator() 0 4 1
A setImageConstraintOptions() 0 4 1
A setHttpClient() 0 4 1
A getHttpClient() 0 4 1
A getFilesystem() 0 4 1
A setMedia() 0 6 1
A update() 0 4 1
A getTranslationDomain() 0 4 1
A buildCreateForm() 0 7 1
A buildEditForm() 0 47 1
A buildProviderEditFormBefore() 0 3 1
A buildProviderEditFormAfter() 0 3 1
B handleFileUpload() 0 38 5
B getFileMetaData() 0 24 5
A updateImage() 0 16 2
B doAddFileField() 0 30 2
A addImageField() 18 18 1
A addRequiredImageField() 18 18 1
A getFilenameByFile() 0 9 1
A writeToFilesystem() 0 12 2
A supports() 0 14 4
A disableErrorHandler() 0 7 1
A restoreErrorHandler() 0 4 1
A validate() 0 3 1
A getEmbedTemplate() 0 7 1
A getTitle() 0 4 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like AbstractProvider often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use AbstractProvider, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace MediaMonks\SonataMediaBundle\Provider;
4
5
use League\Flysystem\Filesystem;
6
use MediaMonks\SonataMediaBundle\Client\HttpClientInterface;
7
use MediaMonks\SonataMediaBundle\Model\AbstractMedia;
8
use MediaMonks\SonataMediaBundle\Form\Type\MediaFocalPointType;
9
use MediaMonks\SonataMediaBundle\Model\MediaInterface;
10
use Sonata\AdminBundle\Form\FormMapper;
11
use Sonata\CoreBundle\Validator\ErrorElement;
12
use Symfony\Component\Form\Extension\Core\Type\FileType;
13
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
14
use Symfony\Component\Form\Extension\Core\Type\TextType;
15
use Symfony\Component\HttpFoundation\File\UploadedFile;
16
use Symfony\Component\Translation\TranslatorInterface;
17
use Symfony\Component\Validator\Constraints as Constraint;
18
19
abstract class AbstractProvider implements ProviderInterface
20
{
21
    const SUPPORT_EMBED = 'embed';
22
    const SUPPORT_IMAGE = 'image';
23
    const SUPPORT_DOWNLOAD = 'download';
24
25
    const TYPE_AUDIO = 'audio';
26
    const TYPE_IMAGE = 'image';
27
    const TYPE_FILE = 'file';
28
    const TYPE_VIDEO = 'video';
29
30
    /**
31
     * @var Filesystem
32
     */
33
    protected $filesystem;
34
35
    /**
36
     * @var TranslatorInterface
37
     */
38
    private $translator;
39
40
    /**
41
     * @var array
42
     */
43
    private $imageConstraintOptions = [];
44
45
    /**
46
     * @var HttpClientInterface
47
     */
48
    private $httpClient;
49
50
    /**
51
     * @var AbstractMedia
52
     */
53
    private $media;
54
55
    /**
56
     * @param Filesystem $filesystem
57
     */
58 10
    public function setFilesystem(Filesystem $filesystem)
59
    {
60 10
        $this->filesystem = $filesystem;
61 10
    }
62
63
    /**
64
     * @param TranslatorInterface $translator
65
     */
66 10
    public function setTranslator(TranslatorInterface $translator)
67
    {
68 10
        $this->translator = $translator;
69 10
    }
70
71
    /**
72
     * @return \Symfony\Component\Translation\TranslatorInterface
73
     */
74
    public function getTranslator()
75
    {
76
        return $this->translator;
77
    }
78
79
    /**
80
     * @param array $options
81
     */
82 10
    public function setImageConstraintOptions(array $options)
83
    {
84 10
        $this->imageConstraintOptions = $options;
85 10
    }
86
87
    /**
88
     * @param HttpClientInterface $httpClient
89
     */
90 10
    public function setHttpClient(HttpClientInterface $httpClient)
91
    {
92 10
        $this->httpClient = $httpClient;
93 10
    }
94
95
    /**
96
     * @return HttpClientInterface
97
     */
98 3
    public function getHttpClient()
99
    {
100 3
        return $this->httpClient;
101
    }
102
103
    /**
104
     * @return Filesystem
105
     */
106 7
    public function getFilesystem()
107
    {
108 7
        return $this->filesystem;
109
    }
110
111
    /**
112
     * @param AbstractMedia $media
113
     * @return AbstractProvider
114
     */
115 8
    public function setMedia($media)
116
    {
117 8
        $this->media = $media;
118
119 8
        return $this;
120
    }
121
122
    /**
123
     * @param AbstractMedia $media
124
     * @param $providerReferenceUpdated
125
     */
126 7
    public function update(AbstractMedia $media, $providerReferenceUpdated)
127
    {
128 7
        $this->updateImage($media);
129 7
    }
130
131
    /**
132
     * @return string
133
     */
134
    public function getTranslationDomain()
135
    {
136
        return 'MediaMonksSonataMediaBundle';
137
    }
138
139
    /**
140
     * @param FormMapper $formMapper
141
     */
142 8
    public function buildCreateForm(FormMapper $formMapper)
143
    {
144
        $formMapper
145 8
            ->add('provider', 'hidden');
146
147 8
        $this->buildProviderCreateForm($formMapper);
148 8
    }
149
150
    /**
151
     * @param FormMapper $formMapper
152
     */
153 7
    public function buildEditForm(FormMapper $formMapper)
154
    {
155
        $formMapper
156 7
            ->tab('general')
157 7
            ->add('provider', HiddenType::class);
158
159 7
        $this->buildProviderEditFormBefore($formMapper);
160
161 7
        $formMapper->add(
162 7
            'imageContent',
163 7
            'file',
164
            [
165 7
                'required'    => false,
166
                'constraints' => [
167 7
                    new Constraint\File(),
168
                ],
169 7
                'label'       => 'form.replacement_image',
170
            ]
171
        )
172 7
            ->add('title', TextType::class, ['label' => 'form.title'])
173 7
            ->add(
174 7
                'description',
175 7
                TextType::class,
176 7
                ['label' => 'form.description', 'required' => false]
177
            )
178 7
            ->add(
179 7
                'authorName',
180 7
                TextType::class,
181 7
                ['label' => 'form.authorName', 'required' => false]
182
            )
183 7
            ->add(
184 7
                'copyright',
185 7
                TextType::class,
186 7
                ['label' => 'form.copyright', 'required' => false]
187
            )
188 7
            ->end()
189 7
            ->end()
190 7
            ->tab('image')
191 7
            ->add('focalPoint', MediaFocalPointType::class, [
192 7
                'media' => $this->media
193
            ])
194 7
            ->end()
195 7
            ->end()
196
        ;
197
198 7
        $this->buildProviderEditFormAfter($formMapper);
199 7
    }
200
201
    /**
202
     * @param FormMapper $formMapper
203
     */
204
    public function buildProviderEditFormBefore(FormMapper $formMapper)
205
    {
206
    }
207
208
    /**
209
     * @param FormMapper $formMapper
210
     */
211 6
    public function buildProviderEditFormAfter(FormMapper $formMapper)
212
    {
213 6
    }
214
215
    /**
216
     * @param AbstractMedia $media
217
     * @param bool $useAsImage
218
     * @return string|void
219
     */
220 4
    protected function handleFileUpload(AbstractMedia $media, $useAsImage = false)
221
    {
222
        /**
223
         * @var UploadedFile $file
224
         */
225 4
        $file = $media->getBinaryContent();
226
227 4
        if (empty($file)) {
228
            return;
229
        }
230
231 4
        $filename = $this->getFilenameByFile($file);
232 4
        $this->writeToFilesystem($file, $filename);
233
234 4
        $media->setProviderMetadata(
235 4
            array_merge(
236 4
                $media->getProviderMetaData(),
237 4
                $this->getFileMetaData($file)
238
            )
239
        );
240
241 4
        if (empty($media->getImage()) && $useAsImage) {
242 2
            $media->setImage($filename);
243 2
            $media->setImageMetaData($media->getProviderMetaData());
244
        }
245
246 4
        if (empty($media->getTitle())) {
247 4
            $media->setTitle(
248 4
                str_replace(
249 4
                    '_',
250 4
                    ' ',
251 4
                    pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME)
252
                )
253
            );
254
        }
255
256 4
        return $filename;
257
    }
258
259
    /**
260
     * @param UploadedFile $file
261
     * @return array
262
     */
263 4
    protected function getFileMetaData(UploadedFile $file)
264
    {
265
        $fileData = [
266 4
            'originalName'      => $file->getClientOriginalName(),
267 4
            'originalExtension' => $file->getClientOriginalExtension(),
268 4
            'mimeType'          => $file->getClientMimeType(),
269 4
            'size'              => $file->getSize(),
270
        ];
271
272 4
        if (strpos($file->getClientMimeType(), 'image') !== false) {
273
            $this->disableErrorHandler();
274
            $imageSize = getimagesize($file->getRealPath());
275
            if (is_array($imageSize)) {
276
                list($width, $height) = $imageSize;
277
                if (is_int($width) && is_int($height)) {
278
                    $fileData['height'] = $height;
279
                    $fileData['width']  = $width;
280
                }
281
            }
282
            $this->restoreErrorHandler();
283
        }
284
285 4
        return $fileData;
286
    }
287
288
    /**
289
     * @param AbstractMedia $media
290
     */
291 7
    public function updateImage(AbstractMedia $media)
292
    {
293
        /**
294
         * @var UploadedFile $file
295
         */
296 7
        $file = $media->getImageContent();
297 7
        if (empty($file)) {
298 5
            return;
299
        }
300
301 2
        $filename = $this->getFilenameByFile($file);
302 2
        $this->writeToFilesystem($file, $filename);
303
304 2
        $media->setImage($filename);
305 2
        $media->setImageMetaData($this->getFileMetaData($file));
306 2
    }
307
308
    /**
309
     * @param \Sonata\AdminBundle\Form\FormMapper $formMapper
310
     * @param $name
311
     * @param $label
312
     * @param $required
313
     * @param array $constraints
314
     */
315 5
    protected function doAddFileField(
316
        FormMapper $formMapper,
317
        $name,
318
        $label,
319
        $required,
320
        $constraints = []
321
    ) {
322 5
        if ($required) {
323 5
            $constraints = array_merge(
324
                [
325 5
                    new Constraint\NotBlank(),
326 5
                    new Constraint\NotNull(),
327
                ],
328 5
                $constraints
329
            );
330
        }
331
332
        $formMapper
333 5
            ->add(
334
                $name,
335 5
                FileType::class,
336
                [
337 5
                    'multiple'    => false,
338
                    'data_class'  => null,
339 5
                    'constraints' => $constraints,
340 5
                    'label'       => $label,
341 5
                    'required'    => $required,
342
                ]
343
            );
344 5
    }
345
346
    /**
347
     * @param FormMapper $formMapper
348
     * @param string $name
349
     * @param string $label
350
     * @param array $options
351
     */
352 2 View Code Duplication
    public function addImageField(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
353
        FormMapper $formMapper,
354
        $name,
355
        $label,
356
        $options = []
357
    ) {
358 2
        $this->doAddFileField(
359
            $formMapper,
360
            $name,
361
            $label,
362 2
            false,
363
            [
364 2
                new Constraint\Image(
365 2
                    array_merge($this->imageConstraintOptions, $options)
366
                ),
367
            ]
368
        );
369 2
    }
370
371
    /**
372
     * @param FormMapper $formMapper
373
     * @param $name
374
     * @param $label
375
     * @param array $options
376
     */
377 2 View Code Duplication
    public function addRequiredImageField(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
378
        FormMapper $formMapper,
379
        $name,
380
        $label,
381
        $options = []
382
    ) {
383 2
        $this->doAddFileField(
384
            $formMapper,
385
            $name,
386
            $label,
387 2
            true,
388
            [
389 2
                new Constraint\Image(
390 2
                    array_merge($this->imageConstraintOptions, $options)
391
                ),
392
            ]
393
        );
394 2
    }
395
396
    /**
397
     * @param UploadedFile $file
398
     * @return string
399
     */
400 4
    protected function getFilenameByFile(UploadedFile $file)
401
    {
402 4
        return sprintf(
403 4
            '%s_%d.%s',
404 4
            sha1($file->getClientOriginalName()),
405 4
            time(),
406 4
            $file->getClientOriginalExtension()
407
        );
408
    }
409
410
    /**
411
     * @param UploadedFile $file
412
     * @param $filename
413
     * @throws \Exception
414
     */
415 4
    protected function writeToFilesystem(UploadedFile $file, $filename)
416
    {
417 4
        $this->disableErrorHandler();
418 4
        $stream = fopen($file->getRealPath(), 'r+');
419 4
        $written = $this->getFilesystem()->writeStream($filename, $stream);
420 4
        fclose($stream); // this sometime messes up
421 4
        $this->restoreErrorHandler();
422
423 4
        if (!$written) {
424
            throw new \Exception('Could not write to file system');
425
        }
426 4
    }
427
428
    /**
429
     * @param $renderType
430
     * @return boolean
431
     */
432 7
    public function supports($renderType)
433
    {
434 7
        if ($renderType === self::SUPPORT_EMBED) {
435 7
            return $this->supportsEmbed();
436
        }
437 7
        if ($renderType === self::SUPPORT_IMAGE) {
438 7
            return $this->supportsImage();
439
        }
440 7
        if ($renderType === self::SUPPORT_DOWNLOAD) {
441 7
            return $this->supportsDownload();
442
        }
443
444
        return false;
445
    }
446
447
    /**
448
     *
449
     */
450 7
    protected function disableErrorHandler()
451
    {
452 7
        set_error_handler(
453 7
            function () {
454 7
            }
455
        );
456 7
    }
457
458
    /**
459
     *
460
     */
461 7
    protected function restoreErrorHandler()
462
    {
463 7
        restore_error_handler();
464 7
    }
465
466
    /**
467
     * @param ErrorElement $errorElement
468
     * @param AbstractMedia $media
469
     */
470 5
    public function validate(ErrorElement $errorElement, AbstractMedia $media)
471
    {
472 5
    }
473
474
    /**
475
     * @return string
476
     */
477 2
    public function getEmbedTemplate()
478
    {
479 2
        return sprintf(
480 2
            'MediaMonksSonataMediaBundle:Provider:%s_embed.html.twig',
481 2
            $this->getName()
482
        );
483
    }
484
485
    /**
486
     * @return string
487
     */
488
    public function getTitle()
489
    {
490
        return $this->translator->trans($this->getName());
491
    }
492
}
493