Completed
Push — master ( afd04b...3b4c22 )
by Colin
10s
created

src/Block/Element/ListBlock.php (3 issues)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/*
4
 * This file is part of the league/commonmark package.
5
 *
6
 * (c) Colin O'Dell <[email protected]>
7
 *
8
 * Original code based on the CommonMark JS reference parser (https://bitly.com/commonmark-js)
9
 *  - (c) John MacFarlane
10
 *
11
 * For the full copyright and license information, please view the LICENSE
12
 * file that was distributed with this source code.
13
 */
14
15
namespace League\CommonMark\Block\Element;
16
17
use League\CommonMark\ContextInterface;
18
use League\CommonMark\Cursor;
19
20
class ListBlock extends AbstractBlock
21
{
22
    const TYPE_UNORDERED = 'Bullet';
23
    const TYPE_ORDERED = 'Ordered';
24
25
    /**
26
     * @var bool
27
     */
28
    protected $tight = false;
29
30
    /**
31
     * @var ListData
32
     */
33
    protected $listData;
34
35 255
    public function __construct(ListData $listData)
36
    {
37 255
        parent::__construct();
38
39 255
        $this->listData = $listData;
40 255
    }
41
42
    /**
43
     * @return ListData
44
     */
45 255
    public function getListData()
46
    {
47 255
        return $this->listData;
48
    }
49
50
    /**
51
     * @return bool
52
     */
53 30
    public function endsWithBlankLine()
54
    {
55 30
        if ($this->lastLineBlank) {
56 3
            return true;
57
        }
58
59 30
        if ($this->hasChildren()) {
60 30
            return $this->lastChild()->endsWithBlankLine();
0 ignored issues
show
It seems like you code against a specific sub-type and not the parent class League\CommonMark\Node\Node as the method endsWithBlankLine() does only exist in the following sub-classes of League\CommonMark\Node\Node: League\CommonMark\Block\Element\AbstractBlock, League\CommonMark\Block\Element\BlockQuote, League\CommonMark\Block\Element\Document, League\CommonMark\Block\Element\FencedCode, League\CommonMark\Block\Element\Heading, League\CommonMark\Block\Element\HtmlBlock, League\CommonMark\Block\Element\IndentedCode, League\CommonMark\Block\Element\ListBlock, League\CommonMark\Block\Element\ListItem, League\CommonMark\Block\Element\Paragraph, League\CommonMark\Block\Element\ThematicBreak. 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...
61
        }
62
63
        return false;
64
    }
65
66
    /**
67
     * Returns true if this block can contain the given block as a child node
68
     *
69
     * @param AbstractBlock $block
70
     *
71
     * @return bool
72
     */
73 237
    public function canContain(AbstractBlock $block)
74
    {
75 237
        return $block instanceof ListItem;
76
    }
77
78
    /**
79
     * Returns true if block type can accept lines of text
80
     *
81
     * @return bool
82
     */
83 21
    public function acceptsLines()
84
    {
85 21
        return false;
86
    }
87
88
    /**
89
     * Whether this is a code block
90
     *
91
     * @return bool
92
     */
93 123
    public function isCode()
94
    {
95 123
        return false;
96
    }
97
98 204
    public function matchesNextLine(Cursor $cursor)
99
    {
100 204
        return true;
101
    }
102
103 237
    public function finalize(ContextInterface $context, $endLineNumber)
104
    {
105 237
        parent::finalize($context, $endLineNumber);
106
107 237
        $this->tight = true; // tight by default
108
109 237
        foreach ($this->children() as $item) {
110
            // check for non-final list item ending with blank line:
111 237
            if ($item->endsWithBlankLine() && $item !== $this->lastChild()) {
0 ignored issues
show
It seems like you code against a specific sub-type and not the parent class League\CommonMark\Node\Node as the method endsWithBlankLine() does only exist in the following sub-classes of League\CommonMark\Node\Node: League\CommonMark\Block\Element\AbstractBlock, League\CommonMark\Block\Element\BlockQuote, League\CommonMark\Block\Element\Document, League\CommonMark\Block\Element\FencedCode, League\CommonMark\Block\Element\Heading, League\CommonMark\Block\Element\HtmlBlock, League\CommonMark\Block\Element\IndentedCode, League\CommonMark\Block\Element\ListBlock, League\CommonMark\Block\Element\ListItem, League\CommonMark\Block\Element\Paragraph, League\CommonMark\Block\Element\ThematicBreak. 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...
112 18
                $this->tight = false;
113 18
                break;
114
            }
115
116
            // Recurse into children of list item, to see if there are
117
            // spaces between any of them:
118 228
            foreach ($item->children() as $subItem) {
119 222
                if ($subItem->endsWithBlankLine() && ($item !== $this->lastChild() || $subItem !== $item->lastChild())) {
0 ignored issues
show
It seems like you code against a specific sub-type and not the parent class League\CommonMark\Node\Node as the method endsWithBlankLine() does only exist in the following sub-classes of League\CommonMark\Node\Node: League\CommonMark\Block\Element\AbstractBlock, League\CommonMark\Block\Element\BlockQuote, League\CommonMark\Block\Element\Document, League\CommonMark\Block\Element\FencedCode, League\CommonMark\Block\Element\Heading, League\CommonMark\Block\Element\HtmlBlock, League\CommonMark\Block\Element\IndentedCode, League\CommonMark\Block\Element\ListBlock, League\CommonMark\Block\Element\ListItem, League\CommonMark\Block\Element\Paragraph, League\CommonMark\Block\Element\ThematicBreak. 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...
120 81
                    $this->tight = false;
121 179
                    break;
122
                }
123 76
            }
124 79
        }
125 237
    }
126
127
    /**
128
     * @return bool
129
     */
130 255
    public function isTight()
131
    {
132 255
        return $this->tight;
133
    }
134
}
135