Passed
Push — master ( b9b823...902e2b )
by Kane
11:52
created

HtmlBuilder::getTypeOptions()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 7
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 1
1
<?php
2
namespace Cohensive\OEmbed;
3
4
class HtmlBuilder
5
{
6
    const TYPE_RAW = 'raw';
7
    const TYPE_IFRAME = 'iframe';
8
    const TYPE_VIDEO = 'video';
9
10
    public function __construct(
11
        protected string $type,
12
        protected string|array $html,
13
        protected ?string $script = null
14
    ) {
15
    }
16
17
    /**
18
     * Returns current type.
19
     */
20
    public function type(): string
21
    {
22
        return $this->type;
23
    }
24
25
    /**
26
     * Returns HTML code for media provider.
27
     */
28
    public function html(array $options = [], bool $amp = false): string
29
    {
30
        if (is_array($this->html)) {
31
            $attrs = $this->applyOptions($this->html, $options);
32
33
            if ($this->type === self::TYPE_IFRAME) {
34
                return $this->iframe($attrs, $amp);
35
            }
36
37
            if ($this->type === self::TYPE_VIDEO) {
38
                return $this->video($attrs, $amp);
39
            }
40
41
            return '';
42
        } else {
43
            return $this->html;
44
        }
45
    }
46
47
    /**
48
     * Return AMP-friendly HTML for media provider.
49
     */
50
    public function ampHtml(array $options = []): string
51
    {
52
        return $this->html($options, true);
53
    }
54
55
    /**
56
     * Returns URL for a given media provider embed. Returned url type depends on embed type:
57
     * iframe - string
58
     * video - string[]
59
     * raw - null
60
     */
61
    public function src(array $options = []): string | array | null
0 ignored issues
show
Bug introduced by
The type Cohensive\OEmbed\null was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
62
    {
63
        if (is_array($this->html)) {
64
            $attrs = $this->applyOptions($this->html, $options);
65
66
            if ($this->type === self::TYPE_IFRAME) {
67
                return $attrs['src'] ?? null;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $attrs['src'] ?? null could return the type null which is incompatible with the type-hinted return Cohensive\OEmbed\null|array|string. Consider adding an additional type-check to rule them out.
Loading history...
68
            }
69
70
            if ($this->type === self::TYPE_VIDEO) {
71
                return array_map(function ($source) {
72
                    return $source['src'];
73
                }, $attrs['source']);
74
            }
75
        }
76
77
        return null;
0 ignored issues
show
Bug Best Practice introduced by
The expression return null returns the type null which is incompatible with the type-hinted return Cohensive\OEmbed\null|array|string.
Loading history...
78
    }
79
80
    /**
81
     * Constructs <iframe> HTML-element based on array of provider attributes.
82
     */
83
    protected function iframe(array $attrs, bool $amp = false): string
84
    {
85
        $tag = $amp ? 'amp-iframe' : 'iframe';
86
87
        $html = "<$tag";
88
        foreach ($attrs as $attr => $val) {
89
            $html .= sprintf(' %s="%s"', $attr, $val);
90
        }
91
        $html .= "></$tag>";
92
93
        return $html;
94
    }
95
96
    /**
97
     * Constructs <video> HTML-element based on an array of provider attributes.
98
     */
99
    protected function video(array $attrs, bool $amp = false): string
100
    {
101
        $tag = $amp ? 'amp-video' : 'video';
102
103
        $inner = '';
104
105
        $html = "<$tag";
106
        foreach ($attrs as $attr => $val) {
107
            if (is_array($val)) {
108
                foreach ($val as $child) {
109
                    $inner .= "<$attr";
110
                    foreach ($child as $iattr => $ival) {
111
                        $inner .= sprintf(' %s="%s"', $iattr, $ival);
112
                    }
113
                    $inner .= ">";
114
                }
115
            } else {
116
                $html .= sprintf(' %s="%s"', $attr, $val);
117
            }
118
        }
119
        $html .= ">";
120
121
        $html .= $inner;
122
123
        $html .= "</$tag>";
124
125
        return $html;
126
    }
127
128
    /**
129
     * Returns script source if available.
130
     */
131
    public function script(): ?string
132
    {
133
        return $this->script;
134
    }
135
136
    /**
137
     * Converts class to an array.
138
     */
139
    public function toArray(): array
140
    {
141
        return [
142
            'type' => $this->type,
143
            'html' => $this->html,
144
        ];
145
    }
146
147
    /**
148
     * Extracts and returns an array of options for a current HTML element type.
149
     */
150
    protected function getTypeOptions(array $options): array
151
    {
152
        if (isset($options['html'])) {
153
            return $options['html'][$this->type] ?? [];
154
        }
155
156
        return [];
157
    }
158
159
    /**
160
     * Merge and apply local and global options to the provider attributes.
161
     */
162
    protected function applyOptions(array $attrs, array $options): array
163
    {
164
        $width = $options['width'] ?? null;
165
        $height = $options['height'] ?? null;
166
167
        if (isset($attrs['width']) && isset($attrs['height'])) {
168
            $ratio = $attrs['width'] / $attrs['height'];
169
170
            if ($width) {
171
                $attrs['width'] = $width;
172
            } else {
173
                $attrs['width'] = round($attrs['height'] * $ratio);
174
            }
175
176
            if ($height) {
177
                $attrs['height'] = $height;
178
            } else {
179
                $attrs['height'] = round($attrs['width'] / $ratio);
180
            }
181
        }
182
183
        if (isset($options['autoplay']) && $options['autoplay']) {
184
            $attrs['autoplay'] = $options['autoplay'];
185
186
            // We can remove autoplay option if type is "iframe" after we change "src" attribute.
187
            if ($this->type === self::TYPE_IFRAME) {
188
                $attrs['src'] = $this->addUrlParam($attrs['src'], sprintf('%s=%s', 'autoplay', $attrs['autoplay']));
189
                unset($attrs['autoplay']);
190
            }
191
        }
192
193
        $typeOptions = $this->getTypeOptions($options);
194
        $attrs = array_merge($attrs, $typeOptions);
195
196
        return $attrs;
197
    }
198
199
    /**
200
     * Append custom parameter to the end of the url.
201
     */
202
    protected function addUrlParam(string $url, string $param): string
203
    {
204
        $operator = strpos($url, '?') >= 0 ? '&' : '?';
205
        return $url . $operator . $param;
206
    }
207
}
208