Passed
Push — webp ( af5ea3 )
by Arnaud
03:08
created

Parsedown::inlineImage()   C

Complexity

Conditions 12
Paths 52

Size

Total Lines 64
Code Lines 34

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 29
CRAP Score 12.4583

Importance

Changes 3
Bugs 1 Features 0
Metric Value
cc 12
eloc 34
c 3
b 1
f 0
nc 52
nop 1
dl 0
loc 64
ccs 29
cts 34
cp 0.8529
crap 12.4583
rs 6.9666

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * This file is part of the Cecil/Cecil package.
4
 *
5
 * Copyright (c) Arnaud Ligny <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace Cecil\Converter;
12
13
use Cecil\Assets\Asset;
14
use Cecil\Assets\Image;
15
use Cecil\Builder;
16
17
class Parsedown extends \ParsedownToC
18
{
19
    /** @var Builder */
20
    protected $builder;
21
22
    /** {@inheritdoc} */
23
    protected $regexAttribute = '(?:[#.][-\w:\\\]+[ ]*|[-\w:\\\]+(?:=(?:["\'][^\n]*?["\']|[^\s]+)?)?[ ]*)';
24
25
    /** Regex to verify there is an image in <figure> block */
26
    private $MarkdownImageRegex = "~^!\[.*?\]\(.*?\)~";
27
28 1
    public function __construct(Builder $builder)
29
    {
30 1
        $this->builder = $builder;
31 1
        if ($this->builder->getConfig()->get('body.images.caption.enabled')) {
32
            $this->BlockTypes['!'][] = 'Image';
33
        }
34 1
        parent::__construct(['selectors' => $this->builder->getConfig()->get('body.toc')]);
35 1
    }
36
37
    /**
38
     * {@inheritdoc}
39
     */
40 1
    protected function inlineImage($excerpt)
41
    {
42 1
        $image = parent::inlineImage($excerpt);
43 1
        if (!isset($image)) {
44
            return null;
45
        }
46
        // clean source path / URL
47 1
        $image['element']['attributes']['src'] = trim($this->removeQuery($image['element']['attributes']['src']));
48
        // create asset
49 1
        $asset = new Asset($this->builder, $image['element']['attributes']['src']);
50
        // is asset is valid? (if yes get width)
51 1
        if (false === $width = $asset->getWidth()) {
52
            return $image;
53
        }
54 1
        $image['element']['attributes']['src'] = $asset;
55
        /**
56
         * Should be lazy loaded?
57
         */
58 1
        if ($this->builder->getConfig()->get('body.images.lazy.enabled')) {
59 1
            $image['element']['attributes']['loading'] = 'lazy';
60
        }
61
        /**
62
         * Should be resized?
63
         */
64 1
        $assetResized = null;
65 1
        if (array_key_exists('width', $image['element']['attributes'])
66 1
            && (int) $image['element']['attributes']['width'] < $width
67 1
            && $this->builder->getConfig()->get('body.images.resize.enabled')
68
        ) {
69 1
            $width = (int) $image['element']['attributes']['width'];
70
71
            try {
72 1
                $assetResized = $asset->resize($width);
73
            } catch (\Exception $e) {
74
                $this->builder->getLogger()->debug($e->getMessage());
75
76
                return $image;
77
            }
78 1
            $image['element']['attributes']['src'] = $assetResized;
79
        }
80
        // set width
81 1
        if (!array_key_exists('width', $image['element']['attributes'])) {
82 1
            $image['element']['attributes']['width'] = $width;
83
        }
84
        // set height
85 1
        if (!array_key_exists('height', $image['element']['attributes'])) {
86 1
            $image['element']['attributes']['height'] = $asset->getHeight();
87
        }
88
        /**
89
         * Should be responsive?
90
         */
91 1
        if ($this->builder->getConfig()->get('body.images.responsive.enabled')) {
92 1
            if ($srcset = Image::getSrcset(
93 1
                $assetResized ?? $asset,
94 1
                $this->builder->getConfig()->get('assets.images.responsive.width.steps') ?? 5,
95 1
                $this->builder->getConfig()->get('assets.images.responsive.width.min') ?? 320,
96 1
                $this->builder->getConfig()->get('assets.images.responsive.width.max') ?? 1280
97
            )) {
98 1
                $image['element']['attributes']['srcset'] = $srcset;
99 1
                $image['element']['attributes']['sizes'] = $this->builder->getConfig()->get('assets.images.responsive.sizes.default');
100
            }
101
        }
102
103 1
        return $image;
104
    }
105
106
    /**
107
     * {@inheritdoc}
108
     */
109 1
    protected function parseAttributeData($attributeString)
110
    {
111 1
        $attributes = preg_split('/[ ]+/', $attributeString, -1, PREG_SPLIT_NO_EMPTY);
112 1
        $Data = [];
113 1
        $HtmlAtt = [];
114
115 1
        foreach ($attributes as $attribute) {
116 1
            switch ($attribute[0]) {
117 1
                case '#': // ID
118
                    $Data['id'] = substr($attribute, 1);
119
                    break;
120 1
                case '.': // Classes
121
                    $classes[] = substr($attribute, 1);
122
                    break;
123
                default:  // Attributes
124 1
                    parse_str($attribute, $parsed);
125 1
                    $HtmlAtt = array_merge($HtmlAtt, $parsed);
126
            }
127
        }
128
129 1
        if (isset($classes)) {
130
            $Data['class'] = implode(' ', $classes);
131
        }
132 1
        if (!empty($HtmlAtt)) {
133 1
            foreach ($HtmlAtt as $a => $v) {
134 1
                $Data[$a] = trim($v, '"');
135
            }
136
        }
137
138 1
        return $Data;
139
    }
140
141
    /**
142
     * Enhanced image block with <figure>/<figcaption>.
143
     */
144
    protected function blockImage($Line)
145
    {
146
        if (1 !== preg_match($this->MarkdownImageRegex, $Line['text'])) {
147
            return;
148
        }
149
150
        $InlineImage = $this->inlineImage($Line);
151
        if (!isset($InlineImage)) {
152
            return;
153
        }
154
155
        $block = $InlineImage;
156
157
        /*
158
        <figure>
159
            <picture>
160
                <source type="image/webp"
161
                    srcset="..."
162
                    sizes="..."
163
                >
164
                <img src="..."
165
                    srcset="..."
166
                    sizes="..."
167
                >
168
            </picture>
169
            <figcaption>...</figcaption>
170
        </figure>
171
        */
172
173
        // creates a <picture> element with <source> and <img> elements
174
        if ($this->builder->getConfig()->get('body.images.webp.enabled') ?? false) {
175
            $assetWebp = Image::convertTopWebp($InlineImage['element']['attributes']['src'], $this->builder->getConfig()->get('assets.images.quality') ?? 85);
176
            $srcset = Image::getSrcset(
177
                $assetWebp,
178
                $this->builder->getConfig()->get('assets.images.responsive.width.steps') ?? 5,
179
                $this->builder->getConfig()->get('assets.images.responsive.width.min') ?? 320,
180
                $this->builder->getConfig()->get('assets.images.responsive.width.max') ?? 1280
181
            );
182
            if (empty($srcset)) {
183
                $srcset = (string) $assetWebp;
184
            }
185
            $PictureBlock = [
186
                'element' => [
187
                    'name'    => 'picture',
188
                    'handler' => 'elements',
189
                ],
190
            ];
191
            $source = [
192
                'element' => [
193
                    'name'       => 'source',
194
                    'attributes' => [
195
                        'type'   => 'image/webp',
196
                        'srcset' => $srcset,
197
                        'sizes'  => $this->builder->getConfig()->get('assets.images.responsive.sizes.default'),
198
                    ],
199
                ],
200
            ];
201
            $PictureBlock['element']['text'][] = $source['element'];
202
            $PictureBlock['element']['text'][] = $InlineImage['element'];
203
            $block = $PictureBlock;
204
        }
205
206
        // put <img> or <picture> in a <figure> element if there is a title
207
        if (!empty($InlineImage['element']['attributes']['title'])) {
208
            $FigureBlock = [
209
                'element' => [
210
                    'name'    => 'figure',
211
                    'handler' => 'elements',
212
                    'text'    => [
213
                        $block['element'],
214
                    ],
215
                ],
216
            ];
217
            $InlineFigcaption = [
218
                'element' => [
219
                    'name' => 'figcaption',
220
                    'text' => $InlineImage['element']['attributes']['title'],
221
                ],
222
            ];
223
            $FigureBlock['element']['text'][] = $InlineFigcaption['element'];
224
225
            return $FigureBlock;
226
        }
227
228
        return $block;
229
    }
230
231
    /**
232
     * Removes query string from URL.
233
     */
234
    private function removeQuery(string $path): string
235
    {
236 1
        return strtok($path, '?');
237
    }
238
}
239