Completed
Push — master ( 98cc09...f90658 )
by Johannes
04:44
created

ImageRenderer::getCaptionRenderer()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
/**
3
 * Lichtenwallner  (https://lichtenwallner.at)
4
 *
5
 * @see https://github.com/jolicht/markdown-cms for the canonical source repository
6
 * @license https://github.com/jolicht/markdown-cms/blob/master/LICENSE MIT
7
 * @copyright Copyright (c) Johannes Lichtenwallner
8
 */
9
declare(strict_types = 1);
10
namespace Jolicht\MarkdownCms\Markdown\Renderer;
11
12
use League\CommonMark\ElementRendererInterface;
13
use League\CommonMark\HtmlElement;
14
use League\CommonMark\Inline\Renderer\InlineRendererInterface;
15
use League\CommonMark\Inline\Element\AbstractInline;
16
17
class ImageRenderer implements InlineRendererInterface
18
{
19
    /**
20
     * Image caption renderer
21
     *
22
     * @var ImageCaptionRenderer
23
     */
24
    private $captionRenderer;
25
26
    /**
27
     * Url Translation
28
     *
29
     * @var array
30
     */
31
    private $urlTranslation;
32
33
    /**
34
     * Images base url
35
     *
36
     * @var string
37
     */
38
    private $imagesBaseUrl;
39
40
    /**
41
     * Images config
42
     *
43
     * @var array
44
     */
45
    private $imagesConfig;
46
47
    /**
48
     * Constructor
49
     *
50
     * @param ImageCaptionRenderer $imageCaptionRenderer
0 ignored issues
show
Documentation introduced by
There is no parameter named $imageCaptionRenderer. Did you maybe mean $captionRenderer?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
51
     * @param array $urlTranslation
52
     * @param string $imagesBaseUrl
53
     * @param array $imagesConfig
54
     */
55
    public function __construct(ImageCaptionRenderer $captionRenderer, array $urlTranslation, string $imagesBaseUrl,
56
        array $imagesConfig)
57
    {
58
        $this->captionRenderer = $captionRenderer;
59
        $this->urlTranslation = $urlTranslation;
60
        $this->imagesBaseUrl = rtrim($imagesBaseUrl, '/');
61
        $this->imagesConfig = $imagesConfig;
62
    }
63
64
    /**
65
     * Get caption renderer
66
     *
67
     * @return ImageCaptionRenderer
68
     */
69
    public function getCaptionRenderer() : ImageCaptionRenderer
70
    {
71
        return $this->captionRenderer;
72
    }
73
74
    /**
75
     * Get url translation
76
     *
77
     * @return array
78
     */
79
    public function getUrlTranslation() : array
80
    {
81
        return $this->urlTranslation;
82
    }
83
84
    /**
85
     * Get images base url
86
     *
87
     * @return string
88
     */
89
    public function getImagesBaseUrl() : string
90
    {
91
        return $this->imagesBaseUrl;
92
    }
93
94
    /**
95
     * Get images config
96
     *
97
     * @return array
98
     */
99
    public function getImagesConfig() : array
100
    {
101
        return $this->imagesConfig;
102
    }
103
104
    /**
105
     * Render image
106
     *
107
     * {@inheritDoc}
108
     * @see \League\CommonMark\Inline\Renderer\InlineRendererInterface::render()
109
     */
110
    public function render(AbstractInline $inline, ElementRendererInterface $htmlRenderer)
111
    {
112
        $src = $inline->getUrl();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class League\CommonMark\Inline\Element\AbstractInline as the method getUrl() does only exist in the following sub-classes of League\CommonMark\Inline\Element\AbstractInline: League\CommonMark\Inline...ent\AbstractWebResource, League\CommonMark\Inline\Element\Image, League\CommonMark\Inline\Element\Link. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
113
        $id = substr($src, strlen($this->getImagesBaseUrl()) + 1);
114
115
        $imagesConfig = $this->getImagesConfig();
116
        $params = $imagesConfig[$id];
117
118
119
        $imgAttributes = [
120
            'src' => strtr($inline->getUrl(), $this->getUrlTranslation()),
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class League\CommonMark\Inline\Element\AbstractInline as the method getUrl() does only exist in the following sub-classes of League\CommonMark\Inline\Element\AbstractInline: League\CommonMark\Inline...ent\AbstractWebResource, League\CommonMark\Inline\Element\Image, League\CommonMark\Inline\Element\Link. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
121
            'layout' => 'responsive',
122
            'alt' => $inline->firstChild()->getContent(),
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class League\CommonMark\Node\Node as the method getContent() does only exist in the following sub-classes of League\CommonMark\Node\Node: League\CommonMark\Inline...AbstractStringContainer, League\CommonMark\Inline\Element\Code, League\CommonMark\Inline\Element\HtmlInline, League\CommonMark\Inline\Element\Text. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
123
            'width' => $params['width'],
124
            'height' => $params['height']
125
        ];
126
127
        $figureContents = [];
128
        $figureContents[] = new HtmlElement('amp-img', $imgAttributes);
129
130
        if (isset($params['caption'])) {
131
//             $figureContents[] = new HtmlElement('figcaption', [], $params['caption']);
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
132
            $figureContents[] = $this->getCaptionRenderer()->__invoke($params);
133
        }
134
135
        $figure = new HtmlElement('figure', [], $figureContents);
136
        return $figure;
137
    }
138
139
    /**
140
     * Render image
141
     *
142
     * {@inheritDoc}
143
     * @see \League\CommonMark\Inline\Renderer\InlineRendererInterface::render()
144
     */
145
    public function renderOld(AbstractInline $inline, ElementRendererInterface $htmlRenderer)
0 ignored issues
show
Unused Code introduced by
The parameter $htmlRenderer is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
146
    {
147
        $altContent = $inline->firstChild()->getContent();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class League\CommonMark\Node\Node as the method getContent() does only exist in the following sub-classes of League\CommonMark\Node\Node: League\CommonMark\Inline...AbstractStringContainer, League\CommonMark\Inline\Element\Code, League\CommonMark\Inline\Element\HtmlInline, League\CommonMark\Inline\Element\Text. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
148
        $attributes = [
149
            'src' => strtr($inline->getUrl(), $this->getUrlTranslation()),
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class League\CommonMark\Inline\Element\AbstractInline as the method getUrl() does only exist in the following sub-classes of League\CommonMark\Inline\Element\AbstractInline: League\CommonMark\Inline...ent\AbstractWebResource, League\CommonMark\Inline\Element\Image, League\CommonMark\Inline\Element\Link. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
150
            'alt' => $altContent,
151
        ];
152
153
        $caption = null;
154
155
        $posJsonOpen = strpos($altContent, '{');
156
        $posJsonClose = strpos($altContent, '}');
157
        if ((false !== $posJsonOpen) and (false !== $posJsonClose)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
158
            $json = substr($altContent, $posJsonOpen, $posJsonClose);
159
            $data = json_decode($json, true);
160
            if (is_array($data)) {
161
                if (isset($data['caption'])) {
162
                    $caption = $data['caption'];
163
                    unset($data['caption']);
164
                }
165
                $attributes = array_merge($attributes, $data);
166
            }
167
            $attributes['alt'] = substr($altContent, 0, $posJsonOpen);
168
        }
169
170
        if (isset($attributes['id'])) {
171
            $imagesConfig = $this->getImagesConfig();
172
            $config = $imagesConfig[$attributes['id']];
173
            if (isset($config['width'])) {
174
                $attributes['width'] = $config['width'];
175
            }
176
            if (isset($config['height'])) {
177
                $attributes['height'] = $config['height'];
178
            }
179
            if (isset($config['caption'])) {
180
                $caption = $config['caption'];
181
            }
182
        }
183
184
        if (!isset($attributes['layout'])) {
185
            $attributes['layout'] = 'responsive';
186
        }
187
188
        $figureContents = [];
189
        $figure = new HtmlElement('figure');
0 ignored issues
show
Unused Code introduced by
$figure is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
190
        $figureContents[] = new HtmlElement('amp-img', $attributes);
191
        if (null !== $caption) {
192
            $figureContents[] = new HtmlElement('figcaption', [], $caption);
193
        }
194
        return new HtmlElement('figure', [], $figureContents);
195
    }
196
}