VideoSliderItem   C
last analyzed

Complexity

Total Complexity 38

Size/Duplication

Total Lines 347
Duplicated Lines 45.53 %

Coupling/Cohesion

Components 2
Dependencies 17

Importance

Changes 0
Metric Value
wmc 38
lcom 2
cbo 17
dl 158
loc 347
rs 6.6
c 0
b 0
f 0

13 Methods

Rating   Name   Duplication   Size   Complexity  
A getVideoType() 0 3 1
A singular_name() 0 3 1
A plural_name() 0 3 1
A getSliderTypes() 9 9 2
A getCMSFields() 72 72 1
A fieldLabels() 0 3 1
A labels() 0 14 1
A getVideoId() 9 9 3
C getEmbedLink() 22 22 8
B validate() 21 21 5
A getSliderImage() 0 7 2
C fetchVideosPicture() 16 41 8
A getBetterButtonsActions() 9 9 4

How to fix   Duplicated Code   

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:

1
<?php
2
3
/**
4
 * @author    Donatas Navidonskis <[email protected]>
5
 * @since     2017
6
 * @class     VideoSliderItem
7
 *
8
 * @property int     CoverID
9
 * @property int     Mp4ID
10
 * @property int     WebMID
11
 * @property int     OggID
12
 * @property string  Type
13
 * @property string  URL
14
 * @property boolean AutoPlay
15
 *
16
 * @method File Mp4
17
 * @method File WebM
18
 * @method File Ogg
19
 * @method Image Cover
20
 *
21
 * @TODO      implement https://github.com/xemle/html5-video-php package to convert webm and ogg videos when saving.
22
 */
23
class VideoSliderItem extends BaseSliderItem {
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
24
25
    /**
26
     * @var array
27
     * @config
28
     */
29
    private static $db = [
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by
The property $db is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
30
        'Type'     => 'Enum(array("Youtube", "Vimeo", "File"), "File")',
31
        'URL'      => 'Varchar(128)',
32
        'AutoPlay' => 'Boolean(true)',
33
    ];
34
35
    /**
36
     * @var array
37
     * @config
38
     */
39
    private static $has_one = [
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by
The property $has_one is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
40
        'Mp4'   => 'File',
41
        'WebM'  => 'File',
42
        'Ogg'   => 'File',
43
        'Cover' => 'Image',
44
    ];
45
46
    /**
47
     * Allow to call those functions.
48
     *
49
     * @var array
50
     * @config
51
     */
52
    private static $better_buttons_actions = [
0 ignored issues
show
Unused Code introduced by
The property $better_buttons_actions is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
53
        'fetchVideosPicture',
54
    ];
55
56
    /**
57
     * Set providers default embed link. The key value should
58
     * be equal within Type field value.
59
     * {VideoId} - will be replaced with actual video id
60
     * {AutoPlay} - will be replaced within key of AutoPlay.
61
     *
62
     * @var array
63
     * @config
64
     */
65
    private static $embed_links = [
0 ignored issues
show
Unused Code introduced by
The property $embed_links is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
66
        "Youtube" => [
67
            "Link"     => "https://www.youtube.com/embed/{VideoId}{AutoPlay}",
68
            "AutoPlay" => "?autoplay=1",
69
        ],
70
        "Vimeo"   => [
71
            "Link"     => "https://player.vimeo.com/video/{VideoId}{AutoPlay}",
72
            "AutoPlay" => "?autoplay=1",
73
        ],
74
        // Set your own providers options
75
    ];
76
77
    /**
78
     * @var array
79
     * @config
80
     */
81
    private static $thumbnail_links = [
0 ignored issues
show
Unused Code introduced by
The property $thumbnail_links is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
82
        "youtube" => "https://img.youtube.com/vi/{VideoId}/maxresdefault.jpg",
83
        "vimeo"   => "http://vimeo.com/api/v2/video/{VideoId}.php",
84
    ];
85
86
    /**
87
     * @return string
88
     */
89
    public function getVideoType() {
90
        return strtolower($this->Type);
91
    }
92
93
    /**
94
     * @return string
95
     */
96
    public function singular_name() {
97
        return _t('VideoSliderItem.SINGULARNAME', 'Video slider');
98
    }
99
100
    /**
101
     * @return string
102
     */
103
    public function plural_name() {
104
        return _t('VideoSliderItem.PLURALNAME', 'Video sliders');
105
    }
106
107
    /**
108
     * @return array
109
     */
110 View Code Duplication
    public function getSliderTypes() {
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...
111
        $types = [];
112
113
        foreach ($this->dbObject('Type')->enumValues() as $type) {
114
            $types[$type] = $this->fieldLabel($type);
115
        }
116
117
        return $types;
118
    }
119
120
    /**
121
     * @return \FieldList
122
     */
123 View Code Duplication
    public function getCMSFields() {
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...
124
        $fields = parent::getCMSFields();
125
        $fields->removeByName(['Type', 'Mp4', 'WebM', 'Ogg', 'URL', 'AutoPlay', 'Cover']);
126
        $fields->findOrMakeTab('Root.Media', $this->fieldLabel('Media'));
127
128
        $fields->addFieldsToTab('Root.Media', [
129
            $coverField = UploadField::create('Cover', $this->fieldLabel('Cover')),
130
            DropdownField::create('AutoPlay', $this->fieldLabel('TurnOnAutoPlayMode'), BlocksUtility::localized_answers()),
131
            $videoType = OptionsetField::create('Type', $this->fieldLabel('Type'), $this->getSliderTypes(), 'File'),
132
            $uploadFieldContainer = DisplayLogicWrapper::create(
133
                $mp4UploadField = UploadField::create('Mp4', $this->fieldLabel('VideoMp4')),
134
                $webMUploadField = UploadField::create('WebM', $this->fieldLabel('VideoWebM')),
135
                $oggUploadField = UploadField::create('Ogg', $this->fieldLabel('VideoOgg'))
136
            ),
137
            $urlAddressField = TextField::create('URL', $this->fieldLabel('URLAddress'))->setRightTitle(
138
                $this->fieldLabel('SetVideoURLAddress')
139
            ),
140
        ]);
141
142
        $coverField
143
            ->setAllowedMaxFileNumber(1)
144
            ->setAllowedFileCategories('image')
145
            ->setRightTitle(
146
                _t('VideoSliderItem.SET_VIDEO_COVER_IMAGE', 'Set video cover image')
147
            )
148
            ->setFolderName(
149
                sprintf('%s/Sliders', BaseBlock::config()->upload_directory)
150
            );
151
152
        $mp4UploadField
153
            ->setAllowedMaxFileNumber(1)
154
            ->setAllowedExtensions('mp4')
0 ignored issues
show
Documentation introduced by
'mp4' is of type string, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
155
            ->setRightTitle(
156
                _t('VideoSliderItem.ALLOWED_FILE_EXTENSIONS', 'Allowed file extensions: {extensions}', [
0 ignored issues
show
Documentation introduced by
array('extensions' => '.mp4') is of type array<string,string,{"extensions":"string"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
157
                    'extensions' => '.mp4',
158
                ])
159
            )
160
            ->setFolderName(
161
                sprintf('%s/Video-Sliders', BaseBlock::config()->upload_directory)
162
            );
163
164
        $webMUploadField
165
            ->setAllowedMaxFileNumber(1)
166
            ->setAllowedExtensions('webm')
0 ignored issues
show
Documentation introduced by
'webm' is of type string, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
167
            ->setRightTitle(
168
                _t('VideoSliderItem.ALLOWED_FILE_EXTENSIONS', 'Allowed file extensions: {extensions}', [
0 ignored issues
show
Documentation introduced by
array('extensions' => '.webm') is of type array<string,string,{"extensions":"string"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
169
                    'extensions' => '.webm',
170
                ])
171
            )
172
            ->setFolderName(
173
                sprintf('%s/Video-Sliders', BaseBlock::config()->upload_directory)
174
            );
175
176
        $oggUploadField
177
            ->setAllowedMaxFileNumber(1)
178
            ->setAllowedExtensions('ogg')
0 ignored issues
show
Documentation introduced by
'ogg' is of type string, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
179
            ->setRightTitle(
180
                _t('VideoSliderItem.ALLOWED_FILE_EXTENSIONS', 'Allowed file extensions: {extensions}', [
0 ignored issues
show
Documentation introduced by
array('extensions' => '.ogg') is of type array<string,string,{"extensions":"string"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
181
                    'extensions' => '.ogg',
182
                ])
183
            )
184
            ->setFolderName(
185
                sprintf('%s/Video-Sliders', BaseBlock::config()->upload_directory)
186
            );
187
188
        $uploadFieldContainer->displayIf('Type')->isEqualTo('File');
189
        $urlAddressField->displayIf('Type')->isNotEqualTo('File');
190
191
        $this->extend('updateCMSFields', $fields);
192
193
        return $fields;
194
    }
195
196
    /**
197
     * @param bool $includeRelations
198
     *
199
     * @return array
200
     */
201
    public function fieldLabels($includeRelations = true) {
202
        return array_merge(parent::fieldLabels($includeRelations), static::labels());
203
    }
204
205
    /**
206
     * @return array
207
     */
208
    public static function labels() {
209
        return [
210
            'Type'               => _t('VideoSliderItem.TYPE', 'Type'),
211
            'Youtube'            => _t('VideoSliderItem.YOUTUBE', 'Youtube'),
212
            'Vimeo'              => _t('VideoSliderItem.VIMEO', 'Vimeo'),
213
            'File'               => _t('VideoSliderItem.FILE', 'File'),
214
            'URLAddress'         => _t('VideoSliderItem.URL_ADDRESS', 'URL address'),
215
            'SetVideoURLAddress' => _t('VideoSliderItem.SET_VIDEO_URL_ADDRESS', 'Set video URL address'),
216
            'VideoMp4'           => _t('SliderItem.VIDEO_MP4', 'Video Mp4'),
217
            'VideoWebM'          => _t('SliderItem.VIDEO_WEBM', 'Video WebM'),
218
            'VideoOgg'           => _t('SliderItem.VIDEO_OGG', 'Video Ogg'),
219
            'TurnOnAutoPlayMode' => _t('SliderItem.TURN_ON_AUTO_PLAY_MODE', 'Turn on auto play mode?'),
220
        ];
221
    }
222
223
    /**
224
     * This will get an id of the URL address or false
225
     * if can't parsed, object type not one of supported
226
     * providers or just empty url address field.
227
     *
228
     * @return string|false
229
     * @throws ProviderNotFound
230
     */
231 View Code Duplication
    public function getVideoId() {
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...
232
        if (! empty($this->URL) && $this->Type != 'File') {
233
            $videoId = BlocksUtility::parse_video_id($this->URL, $this->Type);
234
235
            return $videoId;
236
        }
237
238
        return false;
239
    }
240
241
    /**
242
     * Get embed link by the set of Type field. Method depends by
243
     * static::$embed_links property.
244
     *
245
     * @return bool|string
246
     */
247 View Code Duplication
    public function getEmbedLink() {
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...
248
        if (! empty($this->URL) && $this->Type != 'File') {
249
            try {
250
                $videoId = BlocksUtility::parse_video_id($this->URL, $this->Type);
251
            } catch (ProviderNotFound $ex) {
252
                return false;
253
            }
254
255
            if ($videoId && array_key_exists($this->Type, ($options = static::config()->embed_links))) {
256
                $options = $options[$this->Type];
257
                $autoPlay = array_key_exists("AutoPlay", $options) && ! empty($options["AutoPlay"]) ? $options["AutoPlay"] : '';
258
259
                return str_replace(
260
                    ['{VideoId}', '{AutoPlay}'],
261
                    [$videoId, $autoPlay],
262
                    $options["Link"]
263
                );
264
            }
265
        }
266
267
        return false;
268
    }
269
270
    /**
271
     * @return \ValidationResult
272
     */
273 View Code Duplication
    protected function validate() {
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...
274
        $validation = parent::validate();
275
276
        if (! empty($this->URL) && $this->Type != 'File') {
277
            try {
278
                $result = $this->getVideoId();
279
            } catch (ProviderNotFound $ex) {
280
                $validation->error($ex->getMessage());
281
282
                return $validation;
283
            }
284
285
            // if we can't parse url address, return an error with bad url address or
286
            // the type is not of the url address providers.
287
            if (! $result) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $result of type string|false is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
288
                $validation->error(_t('VideoSliderItem.INVALID_URL_ADDRESS_OR_THE_TYPE', 'Invalid URL address or the type'));
289
            }
290
        }
291
292
        return $validation;
293
    }
294
295
    /**
296
     * @return Image|false
297
     */
298
    public function getSliderImage() {
299
        if ($this->Cover()->exists()) {
0 ignored issues
show
Documentation Bug introduced by
The method Cover does not exist on object<VideoSliderItem>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
300
            return $this->Cover();
0 ignored issues
show
Documentation Bug introduced by
The method Cover does not exist on object<VideoSliderItem>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
301
        }
302
303
        return false;
304
    }
305
306
    /**
307
     * Creating a button to fetch videos picture if cover image not exists.
308
     *
309
     * @return FieldList
310
     */
311 View Code Duplication
    public function getBetterButtonsActions() {
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...
312
        $fields = parent::getBetterButtonsActions();
313
314
        if ($this->Type != 'File' && ! $this->Cover()->exists() && ! empty($this->URL)) {
0 ignored issues
show
Documentation Bug introduced by
The method Cover does not exist on object<VideoSliderItem>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
315
            $fields->push(BetterButtonCustomAction::create('fetchVideosPicture', _t('VideoSliderItem.FETCH_VIDEOS_PICTURE', 'Fetch videos picture')));
316
        }
317
318
        return $fields;
319
    }
320
321
    /**
322
     * Fetching/downloading picture from the providers url address and
323
     * saving as Image object.
324
     *
325
     * @return false
326
     */
327
    public function fetchVideosPicture() {
328
        try {
329
            $videoId = $this->getVideoId();
330
        } catch (ProviderNotFound $ex) {
331
            return false;
332
        }
333
334
        $directoryPath = sprintf("%s/Sliders", BaseBlock::config()->upload_directory);
335
        $folder = Folder::find_or_make($directoryPath);
336
337
        if (empty($this->URL)) {
338
            return false;
339
        }
340
341
        $title = ! empty($this->Title) ? FileNameFilter::create()->filter($this->Title)."-{$this->ID}" : "video-{$this->ID}";
342
        $fileName = strtolower(sprintf("%s.jpg", $title));
343
        $baseFolder = Director::baseFolder()."/".$folder->getFilename();
344
        $type = strtolower($this->Type);
345
        $fileContent = file_get_contents(str_replace('{VideoId}', $videoId, static::config()->thumbnail_links[$type]));
346
347
        if ($type == 'vimeo') {
348
            $fileContent = file_get_contents($fileContent[0]['thumbnail_large']);
349
        }
350
351 View Code Duplication
        if ($fileContent) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
352
            if (file_put_contents($absoluteFileName = ($baseFolder.$fileName), $fileContent)) {
353
                $image = Image::create([
354
                    "Filename" => $folder->getFilename().$fileName,
355
                    "Title"    => $this->Title,
356
                    "Name"     => $fileName,
357
                    "ParentID" => $folder->ID,
358
                    "OwnerID"  => Member::currentUserID(),
359
                ]);
360
361
                if ($image->write()) {
362
                    $this->CoverID = $image->ID;
363
                    $this->write();
364
                }
365
            }
366
        }
367
    }
368
369
}