Completed
Push — master ( d49d53...b02bfc )
by Colin
03:37
created

ListBlock::setTight()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 6
ccs 0
cts 3
cp 0
rs 9.4285
cc 1
eloc 3
nc 1
nop 1
crap 2
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
Bug introduced by Sergey Protko
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
Bug introduced by Sergey Protko
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
Bug introduced by Sergey Protko
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
    /**
136
     * @param bool $tight
137
     *
138
     * @return $this
139
     */
140
    public function setTight($tight)
141
    {
142
        $this->tight = $tight;
143
144
        return $this;
145
    }
146
}
147