Passed
Push — 4 ( 233e0e...9a76d4 )
by Robbie
07:47 queued 11s
created

EmbedShortcodeProvider   A

Complexity

Total Complexity 28

Size/Duplication

Total Lines 190
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 70
dl 0
loc 190
rs 10
c 1
b 0
f 0
wmc 28

7 Methods

Rating   Name   Duplication   Size   Complexity  
C handle_shortcode() 0 55 12
A buildAttributeListFromArguments() 0 15 3
A photoEmbed() 0 9 1
B embedForTemplate() 0 16 7
A get_shortcodes() 0 3 1
A linkEmbed() 0 10 2
A videoEmbed() 0 14 2
1
<?php
2
3
namespace SilverStripe\View\Shortcodes;
4
5
use Embed\Http\DispatcherInterface;
6
use SilverStripe\Core\Convert;
7
use SilverStripe\Core\Injector\Injector;
8
use SilverStripe\ORM\ArrayList;
9
use SilverStripe\ORM\FieldType\DBField;
10
use SilverStripe\View\ArrayData;
11
use SilverStripe\View\Embed\Embeddable;
12
use SilverStripe\View\Embed\EmbedResource;
13
use SilverStripe\View\HTML;
14
use SilverStripe\View\Parsers\ShortcodeHandler;
15
use Embed\Adapters\Adapter;
16
use Embed\Embed;
17
use SilverStripe\View\Parsers\ShortcodeParser;
18
19
/**
20
 * Provider for the [embed] shortcode tag used by the embedding service
21
 * in the HTML Editor field.
22
 * Provides the html needed for the frontend and the editor field itself.
23
 */
24
class EmbedShortcodeProvider implements ShortcodeHandler
25
{
26
27
    /**
28
     * Gets the list of shortcodes provided by this handler
29
     *
30
     * @return mixed
31
     */
32
    public static function get_shortcodes()
33
    {
34
        return array('embed');
35
    }
36
37
    /**
38
     * Embed shortcode parser from Oembed. This is a temporary workaround.
39
     * Oembed class has been replaced with the Embed external service.
40
     *
41
     * @param array $arguments
42
     * @param string $content
43
     * @param ShortcodeParser $parser
44
     * @param string $shortcode
45
     * @param array $extra
46
     *
47
     * @return string
48
     */
49
    public static function handle_shortcode($arguments, $content, $parser, $shortcode, $extra = array())
50
    {
51
        // Get service URL
52
        if (!empty($content)) {
53
            $serviceURL = $content;
54
        } elseif (!empty($arguments['url'])) {
55
            $serviceURL = $arguments['url'];
56
        } else {
57
            return '';
58
        }
59
60
        // See https://github.com/oscarotero/Embed#example-with-all-options for service arguments
61
        $serviceArguments = [];
62
        if (!empty($arguments['width'])) {
63
            $serviceArguments['min_image_width'] = $arguments['width'];
64
        }
65
        if (!empty($arguments['height'])) {
66
            $serviceArguments['min_image_height'] = $arguments['height'];
67
        }
68
69
        /** @var EmbedResource $embed */
70
        $embed = Injector::inst()->create(Embeddable::class, $serviceURL);
71
        if (!empty($serviceArguments)) {
72
            $embed->setOptions(array_merge($serviceArguments, (array) $embed->getOptions()));
73
        }
74
75
        // Allow resolver to be mocked
76
        $dispatcher = null;
77
        if (isset($extra['resolver'])) {
78
            $dispatcher = Injector::inst()->create(
79
                $extra['resolver']['class'],
80
                $serviceURL,
81
                $extra['resolver']['config']
82
            );
83
        } elseif (Injector::inst()->has(DispatcherInterface::class)) {
84
            $dispatcher = Injector::inst()->get(DispatcherInterface::class);
85
        }
86
87
        if ($dispatcher) {
0 ignored issues
show
introduced by
$dispatcher is of type null, thus it always evaluated to false.
Loading history...
88
            $embed->setDispatcher($dispatcher);
89
        }
90
91
        // Process embed
92
        $embed = $embed->getEmbed();
93
94
        // Convert embed object into HTML
95
        if ($embed && $embed instanceof Adapter) {
0 ignored issues
show
introduced by
$embed is always a sub-type of Embed\Adapters\Adapter.
Loading history...
96
            $result = static::embedForTemplate($embed, $arguments);
97
            if ($result) {
98
                return $result;
99
            }
100
        }
101
102
        // Fallback to link to service
103
        return static::linkEmbed($arguments, $serviceURL, $serviceURL);
104
    }
105
106
    /**
107
     * @param Adapter $embed
108
     * @param array $arguments Additional shortcode params
109
     * @return string
110
     */
111
    public static function embedForTemplate($embed, $arguments)
112
    {
113
        switch ($embed->getType()) {
114
            case 'video':
115
            case 'rich':
116
                // Attempt to inherit width (but leave height auto)
117
                if (empty($arguments['width']) && $embed->getWidth()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $embed->getWidth() of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

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

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
118
                    $arguments['width'] = $embed->getWidth();
119
                }
120
                return static::videoEmbed($arguments, $embed->getCode());
121
            case 'link':
122
                return static::linkEmbed($arguments, $embed->getUrl(), $embed->getTitle());
123
            case 'photo':
124
                return static::photoEmbed($arguments, $embed->getUrl());
125
            default:
126
                return null;
127
        }
128
    }
129
130
    /**
131
     * Build video embed tag
132
     *
133
     * @param array $arguments
134
     * @param string $content Raw HTML content
135
     * @return string
136
     */
137
    protected static function videoEmbed($arguments, $content)
138
    {
139
        // Ensure outer div has given width (but leave height auto)
140
        if (!empty($arguments['width'])) {
141
            $arguments['style'] = 'width: ' . intval($arguments['width']) . 'px;';
142
        }
143
144
        $data = [
145
            'Arguments' => $arguments,
146
            'Attributes' => static::buildAttributeListFromArguments($arguments, ['width', 'height', 'url', 'caption']),
0 ignored issues
show
Deprecated Code introduced by
The function SilverStripe\View\Shortc...buteListFromArguments() has been deprecated: 4.5.0 Use {$Arguments.name} directly in shortcode templates to access argument values ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

146
            'Attributes' => /** @scrutinizer ignore-deprecated */ static::buildAttributeListFromArguments($arguments, ['width', 'height', 'url', 'caption']),

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
147
            'Content' => DBField::create_field('HTMLFragment', $content)
148
        ];
149
150
        return ArrayData::create($data)->renderWith(self::class . '_video')->forTemplate();
151
    }
152
153
    /**
154
     * Build <a> embed tag
155
     *
156
     * @param array $arguments
157
     * @param string $href
158
     * @param string $title Default title
159
     * @return string
160
     */
161
    protected static function linkEmbed($arguments, $href, $title)
162
    {
163
        $data = [
164
            'Arguments' => $arguments,
165
            'Attributes' => static::buildAttributeListFromArguments($arguments, ['width', 'height', 'url', 'caption']),
0 ignored issues
show
Deprecated Code introduced by
The function SilverStripe\View\Shortc...buteListFromArguments() has been deprecated: 4.5.0 Use {$Arguments.name} directly in shortcode templates to access argument values ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

165
            'Attributes' => /** @scrutinizer ignore-deprecated */ static::buildAttributeListFromArguments($arguments, ['width', 'height', 'url', 'caption']),

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
166
            'Href' => $href,
167
            'Title' => !empty($arguments['caption']) ? ($arguments['caption']) : $title
168
        ];
169
170
        return ArrayData::create($data)->renderWith(self::class . '_link')->forTemplate();
171
    }
172
173
    /**
174
     * Build img embed tag
175
     *
176
     * @param array $arguments
177
     * @param string $src
178
     * @return string
179
     */
180
    protected static function photoEmbed($arguments, $src)
181
    {
182
        $data = [
183
            'Arguments' => $arguments,
184
            'Attributes' => static::buildAttributeListFromArguments($arguments, ['url']),
0 ignored issues
show
Deprecated Code introduced by
The function SilverStripe\View\Shortc...buteListFromArguments() has been deprecated: 4.5.0 Use {$Arguments.name} directly in shortcode templates to access argument values ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

184
            'Attributes' => /** @scrutinizer ignore-deprecated */ static::buildAttributeListFromArguments($arguments, ['url']),

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
185
            'Src' => $src
186
        ];
187
188
        return ArrayData::create($data)->renderWith(self::class . '_photo')->forTemplate();
189
    }
190
191
    /**
192
     * Build a list of HTML attributes from embed arguments - used to preserve backward compatibility
193
     *
194
     * @deprecated 4.5.0 Use {$Arguments.name} directly in shortcode templates to access argument values
195
     * @param array $arguments List of embed arguments
196
     * @param array $exclude List of attribute names to exclude from the resulting list
197
     * @return ArrayList
198
     */
199
    private static function buildAttributeListFromArguments(array $arguments, array $exclude = []): ArrayList
200
    {
201
        $attributes = ArrayList::create();
202
        foreach ($arguments as $key => $value) {
203
            if (in_array($key, $exclude)) {
204
                continue;
205
            }
206
207
            $attributes->push(ArrayData::create([
208
                'Name' => $key,
209
                'Value' => Convert::raw2att($value)
210
            ]));
211
        }
212
213
        return $attributes;
214
    }
215
}
216