Passed
Push — master ( d27d35...6e254a )
by Kane
02:55
created

Embed::getOptions()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 0
1
<?php
2
namespace Cohensive\OEmbed;
3
4
use Cohensive\OEmbed\Exceptions\HtmlParsingException;
5
use DOMDocument;
6
7
class Embed
8
{
9
    const TYPE_OEMBED = 0;
10
11
    const TYPE_REGEX = 1;
12
13
    /**
14
     * Type of an Embed object source data - OEmbed or Regex-based.
15
     */
16
    protected int $type;
17
18
    /**
19
     * Array of global options applied to embed objects.
20
     */
21
    protected array $options;
22
23
    /**
24
     * Original media URL.
25
     */
26
    protected string $url;
27
28
    /**
29
     * Embed data extracted via OEmbed or Regex extractors.
30
     */
31
    protected array $data;
32
33
    /**
34
     * Class containing Embed HTML code.
35
     */
36
    protected HtmlBuilder $html;
37
38
    /**
39
     * Thumbnail data if available.
40
     */
41
    protected ?array $thumbnail;
42
43
    /**
44
     * Creates Embed instance.
45
     */
46
    public function __construct(
47
        string $type,
48
        string $url,
49
        array $data,
50
        array $options = [],
51
        bool $amp = false
52
    ) {
53
        $this->type = $type;
54
        $this->url = $url;
55
        $this->data = $data;
56
        $this->options = $options;
57
        $this->amp = $amp;
0 ignored issues
show
Bug Best Practice introduced by
The property amp does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
58
59
        $this->initData($data);
60
    }
61
62
    /**
63
     * Initializer for the Embed object filling thumbnail, html and type based
64
     * on a given media provider data.
65
     */
66
    public function initData(array $data): self
67
    {
68
        if (isset($data['thumbnail_url'])) {
69
            $this->thumbnail = [
70
                'url' => $data['thumbnail_url'],
71
                'width' => $data['thumbnail_width'] ?? null,
72
                'height' => $data['thumbnail_height'] ?? null,
73
            ];
74
        }
75
76
        if ($this->type == self::TYPE_OEMBED) {
77
            $this->html = $this->extractOEmbedHtml($data['html']);
78
        } else {
79
            $this->html = $this->extractRegexHtml($data['html']);
80
        }
81
82
        return $this;
83
    }
84
85
    /**
86
     * Returns mbed options.
87
     */
88
    public function getOptions(): array
89
    {
90
        return $this->options;
91
    }
92
93
    /**
94
     * Sets new embed options. See config file 'options' key.
95
     */
96
    public function setOptions(array $options): self
97
    {
98
        $this->options = $options;
99
        return $this;
100
    }
101
102
    /**
103
     * Sets AMP mode.
104
     */
105
    public function setAmp(bool $amp): self
106
    {
107
        $this->amp = $amp;
0 ignored issues
show
Bug Best Practice introduced by
The property amp does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
108
        return $this;
109
    }
110
111
    /**
112
     * Returns current HtmlBuilder instance.
113
     */
114
    public function htmlBuilder(): HtmlBuilder
115
    {
116
        return $this->html;
117
    }
118
119
    /**
120
     * Returns string with HTML to embed in application. Will return AMP-friendly
121
     * HTML if global amp mode is enabled and not overwitten.
122
     */
123
    public function html(array $options = null, ?bool $amp = null): string
124
    {
125
        if (is_null($options)) {
126
            $options = $this->options;
127
        } else {
128
            $options = array_merge($this->options, $options);
129
        }
130
131
        if (is_null($amp)) {
132
            $amp = $this->amp;
133
        }
134
135
        return $this->html->html($options, $amp);
136
    }
137
138
    /**
139
     * Returns string with AMP-friendly HTML to embed in an application.
140
     */
141
    public function ampHtml(array $options = null): string
142
    {
143
        return $this->html($options, true);
144
    }
145
146
    /**
147
     * Return script source if available in embed html.
148
     */
149
    public function script(): ?string
150
    {
151
        return $this->html->script();
152
    }
153
154
    /**
155
     * Returns embed provider type.
156
     */
157
    public function type(): int
158
    {
159
        return $this->type;
160
    }
161
162
    /**
163
     * Returns embed html type.
164
     */
165
    public function htmlType(): string
166
    {
167
        return $this->html->type();
168
    }
169
170
    /**
171
     * Returns media provider data.
172
     */
173
    public function url(): string
174
    {
175
        return $this->url;
176
    }
177
178
    /**
179
     * Returns media provider data.
180
     */
181
    public function data(): array
182
    {
183
        return $this->data;
184
    }
185
186
    /**
187
     * Returns string describing media type. According to OEmbed spec it could be:
188
     * one of these: photo, video, link, rich
189
     */
190
    public function mediaType(): string
191
    {
192
        return $this->data['type'];
193
    }
194
195
    /**
196
     * Returns boolean flag telling if given embed data has a thumbnail.
197
     */
198
    public function hasThumbnail(): bool
199
    {
200
        return is_array($this->thumbnail);
201
    }
202
203
    /**
204
     * Returns thumbnail data in an array form containing url and its dimensions.
205
     *
206
     */
207
    public function thumbnail(): ?array
208
    {
209
        return $this->thumbnail;
210
    }
211
212
    /**
213
     * Reutrns string for thumbnail or null if it's not set.
214
     */
215
    public function thumbnailUrl(): ?string
216
    {
217
        return $this->hasThumbnail() ? $this->thumbnail['url'] : null;
218
    }
219
220
    /**
221
     * Return thumbnail width or 0 if not set.
222
     */
223
    public function thumbnailWidth(): int
224
    {
225
        return $this->hasThumbnail() ? $this->thumbnail['width'] : 0;
226
    }
227
228
    /**
229
     * Return thumbnail height or 0 if not set.
230
     */
231
    public function thumbnailHeight(): int
232
    {
233
        return $this->hasThumbnail() ? $this->thumbnail['height'] : 0;
234
    }
235
236
    /**
237
     * Converts Embed instance into an array for caching.
238
     */
239
    public function toArray(): array
240
    {
241
        return [
242
            'type' => $this->type,
243
            'url' => $this->url,
244
            'data' => $this->data,
245
        ];
246
    }
247
248
    /**
249
     * Converts Embed instance into json string.
250
     */
251
    public function toJson(): string
252
    {
253
        return json_encode($this->toArray());
254
    }
255
256
    /**
257
     * Returns HtmlBuilder instance of OEmbed media provider HTML string.
258
     */
259
    protected function extractOEmbedHtml(string $html): HtmlBuilder
260
    {
261
        $script = null;
262
        $doc = new DOMDocument();
263
        $doc->loadHTML("<html><body>$html</body></html>", LIBXML_NOERROR);
264
        $body = $doc->documentElement->lastChild;
265
266
        $scripts = $body->getElementsByTagName('script');
0 ignored issues
show
Bug introduced by
The method getElementsByTagName() does not exist on null. ( Ignorable by Annotation )

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

266
        /** @scrutinizer ignore-call */ 
267
        $scripts = $body->getElementsByTagName('script');

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
267
        foreach ($scripts as $node) {
268
            $script = $node->getAttribute('src');
269
            break;
270
        }
271
272
        if (!$body->firstChild) {
273
            throw new HtmlParsingException();
274
        }
275
276
        if ($body->firstChild && $body->firstChild->nodeName === 'iframe') {
277
            $attrs = [];
278
279
            foreach ($body->firstChild->attributes as $attribute) {
280
                $attrs[$attribute->name] = $attribute->value;
281
            }
282
283
            return new HtmlBuilder(HtmlBuilder::TYPE_IFRAME, $attrs, $script);
284
        }
285
286
        return new HtmlBuilder(HtmlBuilder::TYPE_RAW, $html, $script);
287
    }
288
289
    /**
290
     * Returns HtmlBuilder instance of Regex media provider HTML string.
291
     */
292
    protected function extractRegexHtml(array $html): HtmlBuilder
293
    {
294
        $type = array_key_first($html);
295
        return new HtmlBuilder($type, $html[$type]);
296
    }
297
}
298