RemoteVideoHandler::createNew()   D
last analyzed

Complexity

Conditions 9
Paths 15

Size

Total Lines 45
Code Lines 39

Duplication

Lines 28
Ratio 62.22 %

Importance

Changes 0
Metric Value
dl 28
loc 45
rs 4.909
c 0
b 0
f 0
cc 9
eloc 39
nc 15
nop 1
1
<?php
2
3
namespace Victoire\Bundle\MediaBundle\Helper\RemoteVideo;
4
5
use Victoire\Bundle\MediaBundle\Entity\Media;
6
use Victoire\Bundle\MediaBundle\Form\RemoteVideo\RemoteVideoType;
7
use Victoire\Bundle\MediaBundle\Helper\Media\AbstractMediaHandler;
8
use Victoire\Bundle\MediaBundle\Helper\RemoteVideo\Exception\VideoException;
9
10
/**
11
 * RemoteVideoStrategy.
12
 */
13
class RemoteVideoHandler extends AbstractMediaHandler
14
{
15
    /**
16
     * @var string
17
     */
18
    const CONTENT_TYPE = 'remote/video';
19
20
    /**
21
     * @var string
22
     */
23
    const TYPE = 'video';
24
25
    /**
26
     * @return string
27
     */
28
    public function getName()
29
    {
30
        return 'Remote Video Handler';
31
    }
32
33
    /**
34
     * @return string
35
     */
36
    public function getType()
37
    {
38
        return self::TYPE;
39
    }
40
41
    /**
42
     * @return RemoteVideoType
43
     */
44
    public function getFormType()
45
    {
46
        return new RemoteVideoType();
47
    }
48
49
    /**
50
     * @param mixed $object
51
     *
52
     * @return bool
53
     */
54 View Code Duplication
    public function canHandle($object)
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...
55
    {
56
        if ((is_string($object)) || ($object instanceof Media && $object->getContentType() == self::CONTENT_TYPE)) {
57
            return true;
58
        }
59
60
        return false;
61
    }
62
63
    /**
64
     * @param Media $media
65
     *
66
     * @return RemoteVideoHelper
67
     */
68
    public function getFormHelper(Media $media)
69
    {
70
        return new RemoteVideoHelper($media);
71
    }
72
73
    /**
74
     * @param Media $media
75
     *
76
     * @throws \RuntimeException when the file does not exist
77
     */
78
    public function prepareMedia(Media $media)
79
    {
80
        if (null == $media->getUuid()) {
81
            $uuid = uniqid();
82
            $media->setUuid($uuid);
83
        }
84
        $video = new RemoteVideoHelper($media);
85
        $url = $video->getCode();
86
        //update thumbnail
87
        switch ($video->getType()) {
88
            case 'youtube':
89
                $code = $this->isolateYoutubeVideoCode($url);
90
                $video->setThumbnailUrl('http://img.youtube.com/vi/'.$code.'/0.jpg');
91
                break;
92
            case 'vimeo':
93
                $code = $this->isolateVimeoVideoCode($url);
94
                $xml = simplexml_load_file('http://vimeo.com/api/v2/video/'.$code.'.xml');
95
                $video->setThumbnailUrl((string) $xml->video->thumbnail_large);
96
                break;
97
            case 'dailymotion':
98
                $code = $this->isolateDailymotionVideoCode($url);
99
                $json = json_decode(file_get_contents('https://api.dailymotion.com/video/'.$code.'?fields=thumbnail_large_url'));
100
                $thumbnailUrl = $json->{'thumbnail_large_url'};
101
                /* dirty hack to fix urls for imagine */
102
                if (!$this->endsWith($thumbnailUrl, '.jpg') && !$this->endsWith($thumbnailUrl, '.png')) {
103
                    $thumbnailUrl = $thumbnailUrl.'&ext=.jpg';
104
                }
105
                $video->setThumbnailUrl($thumbnailUrl);
106
                break;
107
        }
108
    }
109
110
    /**
0 ignored issues
show
introduced by
Doc comment for parameter "$link" missing
Loading history...
111
     * @param $link
0 ignored issues
show
introduced by
Missing parameter name
Loading history...
112
     *
113
     * @throws VideoException
114
     *
115
     * @return mixed
116
     */
117 View Code Duplication
    public function isolateVimeoVideoCode($link)
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...
118
    {
119
        try {
120
            if (preg_match("/(https?:\/\/)?(www\.)?(player\.)?vimeo\.com\/([a-z]*\/)*([0-9]{6,11})[?]?.*/", $link, $output_array)) {
0 ignored issues
show
Coding Style introduced by
Variable "output_array" is not in valid camel caps format
Loading history...
121
                return $output_array[5];
0 ignored issues
show
Coding Style introduced by
Variable "output_array" is not in valid camel caps format
Loading history...
122
            }
123
        } catch (\Exception $e) {
124
            throw new VideoException("can't match vimeo code in given url", $e);
125
        }
126
    }
127
128
    /**
0 ignored issues
show
introduced by
Doc comment for parameter "$link" missing
Loading history...
129
     * @param $link
0 ignored issues
show
introduced by
Missing parameter name
Loading history...
130
     *
131
     * @throws VideoException
132
     *
133
     * @return mixed
134
     */
135 View Code Duplication
    public function isolateYoutubeVideoCode($link)
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...
136
    {
137
        try {
138
            if (preg_match("#(?<=v=)[a-zA-Z0-9-]+(?=&)|(?<=v\/)[^&\n]+(?=\?)|(?<=v=)[^&\n]+|(?<=youtu.be/)[^&\n]+#", $link, $matches)) {
139
                return $matches[0];
140
            }
141
        } catch (\Exception $e) {
142
            throw new VideoException("can't match youtube code in given url", $e);
143
        }
144
    }
145
146
    /**
0 ignored issues
show
introduced by
Doc comment for parameter "$link" missing
Loading history...
147
     * @param $link
0 ignored issues
show
introduced by
Missing parameter name
Loading history...
148
     *
149
     * @throws VideoException
150
     *
151
     * @return bool
152
     */
153
    public function isolateDailymotionVideoCode($link)
154
    {
155
        try {
156
            if (preg_match('!^.+dailymotion\.com/(video|hub)/([^_]+)[^#]*(#video=([^_&]+))?|(dai\.ly/([^_]+))!', $link, $matches)) {
157
                if (isset($matches[6])) {
158
                    return $matches[6];
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $matches[6]; (string) is incompatible with the return type documented by Victoire\Bundle\MediaBun...ateDailymotionVideoCode of type boolean.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
159
                }
160
                if (isset($matches[4])) {
161
                    return $matches[4];
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $matches[4]; (string) is incompatible with the return type documented by Victoire\Bundle\MediaBun...ateDailymotionVideoCode of type boolean.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
162
                }
163
164
                return $matches[2];
165
            }
166
167
            return false;
168
        } catch (\Exception $e) {
169
            throw new VideoException("can't match dailymotion code in given url", $e);
170
        }
171
    }
172
173
    /**
174
     * String helper.
175
     *
176
     * @param string $str string
177
     * @param string $sub substring
178
     *
179
     * @return bool
180
     */
181
    private function endsWith($str, $sub)
182
    {
183
        return substr($str, strlen($str) - strlen($sub)) === $sub;
184
    }
185
186
    /**
187
     * @param Media $media
188
     */
189
    public function saveMedia(Media $media)
0 ignored issues
show
introduced by
Declare public methods first,then protected ones and finally private ones
Loading history...
190
    {
191
    }
192
193
    /**
194
     * @param Media $media
195
     */
196
    public function removeMedia(Media $media)
197
    {
198
    }
199
200
    /**
201
     * {@inheritdoc}
202
     */
203
    public function updateMedia(Media $media)
204
    {
205
    }
206
207
    /**
208
     * @param array $params
209
     *
210
     * @return array
211
     */
212
    public function getAddUrlFor(array $params = [])
213
    {
214
        return [
215
            'video' => [
216
                'path'   => 'VictoireMediaBundle_folder_videocreate',
217
                'params' => [
218
                    'folderId' => $params['folderId'],
219
                ],
220
            ],
221
        ];
222
    }
223
224
    /**
225
     * @param mixed $data
226
     *
227
     * @return Media
228
     */
229
    public function createNew($data)
230
    {
231
        $result = null;
232
        if (is_string($data)) {
233
            if (strpos($data, 'http') !== 0) {
234
                $data = 'http://'.$data;
235
            }
236
            $parsedUrl = parse_url($data);
237
            switch ($parsedUrl['host']) {
238
                case 'www.youtube.com':
239 View Code Duplication
                case 'youtube.com':
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...
240
                    parse_str($parsedUrl['query'], $queryFields);
241
                    $code = $queryFields['v'];
242
                    $result = new Media();
243
                    $video = new RemoteVideoHelper($result);
244
                    $video->setType('youtube');
245
                    $video->setCode($code);
246
                    $result = $video->getMedia();
247
                    $result->setName('Youtube '.$code);
248
                    break;
249
                case 'www.vimeo.com':
250 View Code Duplication
                case 'vimeo.com':
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...
251
                    $code = substr($parsedUrl['path'], 1);
252
                    $result = new Media();
253
                    $video = new RemoteVideoHelper($result);
254
                    $video->setType('vimeo');
255
                    $video->setCode($code);
256
                    $result = $video->getMedia();
257
                    $result->setName('Vimeo '.$code);
258
                    break;
259
                case 'www.dailymotion.com':
260 View Code Duplication
                case 'dailymotion.com':
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...
261
                    $code = substr($parsedUrl['path'], 7);
262
                    $result = new Media();
263
                    $video = new RemoteVideoHelper($result);
264
                    $video->setType('dailymotion');
265
                    $video->setCode($code);
266
                    $result = $video->getMedia();
267
                    $result->setName('Dailymotion '.$code);
268
                    break;
269
            }
270
        }
271
272
        return $result;
273
    }
274
275
    /**
276
     * {@inheritdoc}
277
     */
278
    public function getShowTemplate(Media $media)
279
    {
280
        return 'VictoireMediaBundle:Media\RemoteVideo:show.html.twig';
281
    }
282
283
    /**
284
     * @param Media  $media    The media entity
285
     * @param string $basepath The base path
286
     *
287
     * @return string
288
     */
289
    public function getImageUrl(Media $media, $basepath)
290
    {
291
        $helper = new RemoteVideoHelper($media);
292
293
        return $helper->getThumbnailUrl();
294
    }
295
296
    /**
297
     * @return array
298
     */
299
    public function getAddFolderActions()
300
    {
301
        return [
302
            self::TYPE => [
303
                'type' => self::TYPE,
304
                'name' => 'media.video.add', ],
305
        ];
306
    }
307
}
308