Completed
Pull Request — master (#1163)
by Grégoire
02:51
created

YouTubeProvider::getReferenceUrl()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
/*
4
 * This file is part of the Sonata Project package.
5
 *
6
 * (c) Thomas Rabaix <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Sonata\MediaBundle\Provider;
13
14
use Buzz\Browser;
15
use Gaufrette\Filesystem;
16
use Sonata\CoreBundle\Model\Metadata;
17
use Sonata\MediaBundle\CDN\CDNInterface;
18
use Sonata\MediaBundle\Generator\GeneratorInterface;
19
use Sonata\MediaBundle\Metadata\MetadataBuilderInterface;
20
use Sonata\MediaBundle\Model\MediaInterface;
21
use Sonata\MediaBundle\Thumbnail\ThumbnailInterface;
22
use Symfony\Component\HttpFoundation\RedirectResponse;
23
24
class YouTubeProvider extends BaseVideoProvider
25
{
26
    /**
27
     * @var bool
28
     */
29
    protected $html5;
30
31
    /**
32
     * @param string                   $name
33
     * @param Filesystem               $filesystem
34
     * @param CDNInterface             $cdn
35
     * @param GeneratorInterface       $pathGenerator
36
     * @param ThumbnailInterface       $thumbnail
37
     * @param Browser                  $browser
38
     * @param MetadataBuilderInterface $metadata
39
     * @param bool                     $html5
40
     */
41
    public function __construct($name, Filesystem $filesystem, CDNInterface $cdn, GeneratorInterface $pathGenerator, ThumbnailInterface $thumbnail, Browser $browser, MetadataBuilderInterface $metadata = null, $html5 = false)
42
    {
43
        parent::__construct($name, $filesystem, $cdn, $pathGenerator, $thumbnail, $browser, $metadata);
44
        $this->html5 = $html5;
45
    }
46
47
    /**
48
     * {@inheritdoc}
49
     */
50
    public function getProviderMetadata()
51
    {
52
        return new Metadata($this->getName(), $this->getName().'.description', false, 'SonataMediaBundle', array('class' => 'fa fa-youtube'));
53
    }
54
55
    /**
56
     * {@inheritdoc}
57
     */
58
    public function getHelperProperties(MediaInterface $media, $format, $options = array())
59
    {
60
        // Override html5 value if $options['html5'] is a boolean
61
        if (!isset($options['html5'])) {
62
            $options['html5'] = $this->html5;
63
        }
64
65
        // documentation : http://code.google.com/apis/youtube/player_parameters.html
66
67
        $default_player_url_parameters = array(
68
            //Values: 0 or 1. Default is 1. Sets whether the player should load related
69
            // videos once playback of the initial video starts. Related videos are
70
            // displayed in the "genie menu" when the menu button is pressed. The player
71
            // search functionality will be disabled if rel is set to 0.
72
            'rel' => 0,
73
74
            // Values: 0 or 1. Default is 0. Sets whether or not the initial video will autoplay
75
            // when the player loads.
76
            'autoplay' => 0,
77
78
            // Values: 0 or 1. Default is 0. In the case of a single video player, a setting of 1
79
            // will cause the player to play the initial video again and again. In the case of a
80
            // playlist player (or custom player), the player will play the entire playlist and
81
            // then start again at the first video.
82
            'loop' => 0,
83
84
            // Values: 0 or 1. Default is 0. Setting this to 1 will enable the Javascript API.
85
            // For more information on the Javascript API and how to use it, see the JavaScript
86
            // API documentation.
87
            'enablejsapi' => 0,
88
89
            // Value can be any alphanumeric string. This setting is used in conjunction with the
90
            // JavaScript API. See the JavaScript API documentation for details.
91
            'playerapiid' => null,
92
93
            // Values: 0 or 1. Default is 0. Setting to 1 will disable the player keyboard controls.
94
            // Keyboard controls are as follows:
95
            //      Spacebar: Play / Pause
96
            //      Arrow Left: Jump back 10% in the current video
97
            //      Arrow Right: Jump ahead 10% in the current video
98
            //      Arrow Up: Volume up
99
            //      Arrow Down: Volume Down
100
            'disablekb' => 0,
101
102
            // Values: 0 or 1. Default is 0. Setting to 1 enables the "Enhanced Genie Menu". This
103
            // behavior causes the genie menu (if present) to appear when the user's mouse enters
104
            // the video display area, as opposed to only appearing when the menu button is pressed.
105
            'egm' => 0,
106
107
            // Values: 0 or 1. Default is 0. Setting to 1 enables a border around the entire video
108
            // player. The border's primary color can be set via the color1 parameter, and a
109
            // secondary color can be set by the color2 parameter.
110
            'border' => 0,
111
112
            // Values: Any RGB value in hexadecimal format. color1 is the primary border color, and
113
            // color2 is the video control bar background color and secondary border color.
114
            'color1' => null,
115
            'color2' => null,
116
117
            // Values: 0 or 1. Default is 0. Setting to 1 enables the fullscreen button. This has no
118
            // effect on the Chromeless Player. Note that you must include some extra arguments to
119
           // your embed code for this to work.
120
            'fs' => 1,
121
122
            // Values: A positive integer. This parameter causes the player to begin playing the video
123
            // at the given number of seconds from the start of the video. Note that similar to the
124
            // seekTo function, the player will look for the closest keyframe to the time you specify.
125
            // This means sometimes the play head may seek to just before the requested time, usually
126
            // no more than ~2 seconds
127
            'start' => 0,
128
129
            // Values: 0 or 1. Default is 0. Setting to 1 enables HD playback by default. This has no
130
            // effect on the Chromeless Player. This also has no effect if an HD version of the video
131
            // is not available. If you enable this option, keep in mind that users with a slower
132
            // connection may have an sub-optimal experience unless they turn off HD. You should ensure
133
            // your player is large enough to display the video in its native resolution.
134
            'hd' => 1,
135
136
            // Values: 0 or 1. Default is 1. Setting to 0 disables the search box from displaying when
137
            // the video is minimized. Note that if the rel parameter is set to 0 then the search box
138
            // will also be disabled, regardless of the value of showsearch.
139
            'showsearch' => 0,
140
141
            // Values: 0 or 1. Default is 1. Setting to 0 causes the player to not display information
142
            // like the video title and rating before the video starts playing.
143
            'showinfo' => 0,
144
145
            // Values: 1 or 3. Default is 1. Setting to 1 will cause video annotations to be shown by
146
            // default, whereas setting to 3 will cause video annotation to not be shown by default.
147
            'iv_load_policy' => 1,
148
149
            // Values: 1. Default is based on user preference. Setting to 1 will cause closed captions
150
            // to be shown by default, even if the user has turned captions off.
151
            'cc_load_policy' => 1,
152
153
            // Values: 'window' or 'opaque' or 'transparent'.
154
            // When wmode=window, the Flash movie is not rendered in the page.
155
            // When wmode=opaque, the Flash movie is rendered as part of the page.
156
            // When wmode=transparent, the Flash movie is rendered as part of the page.
157
            'wmode' => 'window',
158
        );
159
160
        $default_player_parameters = array(
161
            // Values: 0 or 1. Default is 0. Setting to 1 enables a border around the entire video
162
            // player. The border's primary color can be set via the color1 parameter, and a
163
            // secondary color can be set by the color2 parameter.
164
            'border' => $default_player_url_parameters['border'],
165
166
            // Values: 'allowfullscreen' or empty. Default is 'allowfullscreen'. Setting to empty value disables
167
            //  the fullscreen button.
168
            'allowFullScreen' => $default_player_url_parameters['fs'] == '1' ? true : false,
169
170
            // The allowScriptAccess parameter in the code is needed to allow the player SWF to call
171
            // functions on the containing HTML page, since the player is hosted on a different domain
172
            // from the HTML page.
173
            'allowScriptAccess' => isset($options['allowScriptAccess']) ? $options['allowScriptAccess'] : 'always',
174
175
            // Values: 'window' or 'opaque' or 'transparent'.
176
            // When wmode=window, the Flash movie is not rendered in the page.
177
            // When wmode=opaque, the Flash movie is rendered as part of the page.
178
            // When wmode=transparent, the Flash movie is rendered as part of the page.
179
            'wmode' => $default_player_url_parameters['wmode'],
180
        );
181
182
        $player_url_parameters = array_merge($default_player_url_parameters, isset($options['player_url_parameters']) ? $options['player_url_parameters'] : array());
183
184
        $box = $this->getBoxHelperProperties($media, $format, $options);
185
186
        $player_parameters = array_merge($default_player_parameters, isset($options['player_parameters']) ? $options['player_parameters'] : array(), array(
187
            'width' => $box->getWidth(),
188
            'height' => $box->getHeight(),
189
        ));
190
191
        $params = array(
192
            'html5' => $options['html5'],
193
            'player_url_parameters' => http_build_query($player_url_parameters),
194
            'player_parameters' => $player_parameters,
195
        );
196
197
        return $params;
198
    }
199
200
    /**
201
     * {@inheritdoc}
202
     */
203
    public function updateMetadata(MediaInterface $media, $force = false)
204
    {
205
        $url = sprintf('http://www.youtube.com/oembed?url=%s&format=json', $this->getReferenceUrl($media));
206
207
        try {
208
            $metadata = $this->getMetadata($media, $url);
209
        } catch (\RuntimeException $e) {
210
            $media->setEnabled(false);
211
            $media->setProviderStatus(MediaInterface::STATUS_ERROR);
212
213
            return;
214
        }
215
216
        $media->setProviderMetadata($metadata);
217
218
        if ($force) {
219
            $media->setName($metadata['title']);
220
            $media->setAuthorName($metadata['author_name']);
221
        }
222
223
        $media->setHeight($metadata['height']);
224
        $media->setWidth($metadata['width']);
225
        $media->setContentType('video/x-flv');
226
    }
227
228
    /**
229
     * {@inheritdoc}
230
     */
231
    public function getDownloadResponse(MediaInterface $media, $format, $mode, array $headers = array())
232
    {
233
        return new RedirectResponse($this->getReferenceUrl($media), 302, $headers);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return new \Symfony\Comp...media), 302, $headers); (Symfony\Component\HttpFoundation\RedirectResponse) is incompatible with the return type declared by the interface Sonata\MediaBundle\Provi...ce::getDownloadResponse of type Sonata\MediaBundle\Provider\Response.

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...
234
    }
235
236
    /**
237
     * Get provider reference url.
238
     *
239
     * @param MediaInterface $media
240
     *
241
     * @return string
242
     */
243
    public function getReferenceUrl(MediaInterface $media)
244
    {
245
        return sprintf('http://www.youtube.com/watch?v=%s', $media->getProviderReference());
246
    }
247
248
    /**
249
     * @param MediaInterface $media
250
     */
251
    protected function fixBinaryContent(MediaInterface $media)
252
    {
253
        if (!$media->getBinaryContent()) {
254
            return;
255
        }
256
257
        if (strlen($media->getBinaryContent()) === 11) {
258
            return;
259
        }
260
261
        if (preg_match("/^(?:http(?:s)?:\/\/)?(?:www\.)?(?:m\.)?(?:youtu\.be\/|youtube\.com\/(?:(?:watch)?\?(?:.*&)?v(?:i)?=|(?:embed|v|vi|user)\/))([^\#\?&\"'>]+)/", $media->getBinaryContent(), $matches)) {
262
            $media->setBinaryContent($matches[1]);
263
        }
264
    }
265
266
    /**
267
     * {@inheritdoc}
268
     */
269
    protected function doTransform(MediaInterface $media)
270
    {
271
        $this->fixBinaryContent($media);
272
273
        if (!$media->getBinaryContent()) {
274
            return;
275
        }
276
277
        $media->setProviderName($this->name);
278
        $media->setProviderStatus(MediaInterface::STATUS_OK);
279
        $media->setProviderReference($media->getBinaryContent());
280
281
        $this->updateMetadata($media, true);
282
    }
283
}
284