Completed
Push — master ( ed7f79...6ebeeb )
by Donata
02:21
created

VideoSliderItem::getVideoType()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
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 = [
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
    public function getCMSFields() {
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), [
203
            'Type'               => _t('VideoSliderItem.TYPE', 'Type'),
204
            'Youtube'            => _t('VideoSliderItem.YOUTUBE', 'Youtube'),
205
            'Vimeo'              => _t('VideoSliderItem.VIMEO', 'Vimeo'),
206
            'File'               => _t('VideoSliderItem.FILE', 'File'),
207
            'URLAddress'         => _t('VideoSliderItem.URL_ADDRESS', 'URL address'),
208
            'SetVideoURLAddress' => _t('VideoSliderItem.SET_VIDEO_URL_ADDRESS', 'Set video URL address'),
209
            'VideoMp4'           => _t('SliderItem.VIDEO_MP4', 'Video Mp4'),
210
            'VideoWebM'          => _t('SliderItem.VIDEO_WEBM', 'Video WebM'),
211
            'VideoOgg'           => _t('SliderItem.VIDEO_OGG', 'Video Ogg'),
212
            'TurnOnAutoPlayMode' => _t('SliderItem.TURN_ON_AUTO_PLAY_MODE', 'Turn on auto play mode?'),
213
        ]);
214
    }
215
216
    /**
217
     * This will get an id of the URL address or false
218
     * if can't parsed, object type not one of supported
219
     * providers or just empty url address field.
220
     *
221
     * @return string|false
222
     * @throws ProviderNotFound
223
     */
224
    public function getVideoId() {
225
        if (! empty($this->URL) && $this->Type != 'File') {
226
            $videoId = BlocksUtility::parse_video_id($this->URL, $this->Type);
227
228
            return $videoId;
229
        }
230
231
        return false;
232
    }
233
234
    /**
235
     * Get embed link by the set of Type field. Method depends by
236
     * static::$embed_links property.
237
     *
238
     * @return bool|string
239
     */
240
    public function getEmbedLink() {
241
        if (! empty($this->URL) && $this->Type != 'File') {
242
            try {
243
                $videoId = BlocksUtility::parse_video_id($this->URL, $this->Type);
244
            } catch (ProviderNotFound $ex) {
245
                return false;
246
            }
247
248
            if ($videoId && array_key_exists($this->Type, ($options = static::config()->embed_links))) {
249
                $options = $options[$this->Type];
250
                $autoPlay = array_key_exists("AutoPlay", $options) && ! empty($options["AutoPlay"]) ? $options["AutoPlay"] : '';
251
252
                return str_replace(
253
                    ['{VideoId}', '{AutoPlay}'],
254
                    [$videoId, $autoPlay],
255
                    $options["Link"]
256
                );
257
            }
258
        }
259
260
        return false;
261
    }
262
263
    /**
264
     * @return \ValidationResult
265
     */
266
    protected function validate() {
267
        $validation = parent::validate();
268
269
        if (! empty($this->URL) && $this->Type != 'File') {
270
            try {
271
                $result = $this->getVideoId();
272
            } catch (ProviderNotFound $ex) {
273
                $validation->error($ex->getMessage());
274
275
                return $validation;
276
            }
277
278
            // if we can't parse url address, return an error with bad url address or
279
            // the type is not of the url address providers.
280
            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...
281
                $validation->error(_t('VideoSliderItem.INVALID_URL_ADDRESS_OR_THE_TYPE', 'Invalid URL address or the type'));
282
            }
283
        }
284
285
        return $validation;
286
    }
287
288
    /**
289
     * @return Image|false
290
     */
291
    public function getSliderImage() {
292
        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...
293
            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...
294
        }
295
296
        return false;
297
    }
298
299
    /**
300
     * Creating a button to fetch videos picture if cover image not exists.
301
     *
302
     * @return FieldList
303
     */
304
    public function getBetterButtonsActions() {
305
        $fields = parent::getBetterButtonsActions();
306
307
        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...
308
            $fields->push(BetterButtonCustomAction::create('fetchVideosPicture', _t('VideoSliderItem.FETCH_VIDEOS_PICTURE', 'Fetch videos picture')));
309
        }
310
311
        return $fields;
312
    }
313
314
    /**
315
     * Fetching/downloading picture from the providers url address and
316
     * saving as Image object.
317
     *
318
     * @return false
319
     */
320
    public function fetchVideosPicture() {
321
        try {
322
            $videoId = $this->getVideoId();
323
        } catch (ProviderNotFound $ex) {
324
            return false;
325
        }
326
327
        $directoryPath = sprintf("%s/Sliders", BaseBlock::config()->upload_directory);
328
        $folder = Folder::find_or_make($directoryPath);
329
330
        if (empty($this->URL)) {
331
            return false;
332
        }
333
334
        $title = ! empty($this->Title) ? FileNameFilter::create()->filter($this->Title)."-{$this->ID}" : "video-{$this->ID}";
335
        $fileName = strtolower(sprintf("%s.jpg", $title));
336
        $baseFolder = Director::baseFolder()."/".$folder->getFilename();
337
        $type = strtolower($this->Type);
338
        $fileContent = file_get_contents(str_replace('{VideoId}', $videoId, static::config()->thumbnail_links[$type]));
339
340
        if ($type == 'vimeo') {
341
            $fileContent = file_get_contents($fileContent[0]['thumbnail_large']);
342
        }
343
344
        if ($fileContent) {
345
            if (file_put_contents($absoluteFileName = ($baseFolder.$fileName), $fileContent)) {
346
                $image = Image::create([
347
                    "Filename" => $folder->getFilename().$fileName,
348
                    "Title"    => $this->Title,
349
                    "Name"     => $fileName,
350
                    "ParentID" => $folder->ID,
351
                    "OwnerID"  => Member::currentUserID(),
352
                ]);
353
354
                if ($image->write()) {
355
                    $this->CoverID = $image->ID;
356
                    $this->write();
357
                }
358
            }
359
        }
360
    }
361
362
}