Completed
Push — master ( afe412...5fedd9 )
by Robbie
37s queued 21s
created

src/View/Shortcodes/EmbedShortcodeProvider.php (1 issue)

Severity
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
$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) {
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()) {
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']),
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']),
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']),
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