Completed
Push — master ( dc2700...65f918 )
by Martin
22:42 queued 16:21
created

TableParser::parse()   C

Complexity

Conditions 11
Paths 10

Size

Total Lines 67
Code Lines 39

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 35
CRAP Score 11.0594

Importance

Changes 0
Metric Value
dl 0
loc 67
ccs 35
cts 38
cp 0.9211
rs 5.8904
c 0
b 0
f 0
cc 11
eloc 39
nc 10
nop 2
crap 11.0594

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
/*
4
 * This is part of the webuni/commonmark-table-extension package.
5
 *
6
 * (c) Martin Hasoň <[email protected]>
7
 * (c) Webuni s.r.o. <[email protected]>
8
 *
9
 * For the full copyright and license information, please view the LICENSE
10
 * file that was distributed with this source code.
11
 */
12
13
namespace Webuni\CommonMark\TableExtension;
14
15
use League\CommonMark\Block\Element\Paragraph;
16
use League\CommonMark\Block\Parser\AbstractBlockParser;
17
use League\CommonMark\ContextInterface;
18
use League\CommonMark\Cursor;
19
use League\CommonMark\Util\RegexHelper;
20
21
class TableParser extends AbstractBlockParser
22
{
23
    const REGEXP_DEFINITION = '/(?: *(:?) *-+ *(:?) *)+(?=\||$)/';
24
    const REGEXP_CELLS = '/(?:`[^`]*`|\\\\\||\\\\|[^|`\\\\]+)+(?=\||$)/';
25
    const REGEXP_CAPTION = '/^\[(.+?)\](?:\[(.+)\])?\s*$/';
26
27 16
    public function parse(ContextInterface $context, Cursor $cursor)
28
    {
29 16
        $container = $context->getContainer();
30
31 16
        if (!$container instanceof Paragraph) {
32 16
            return false;
33
        }
34
35 16
        $lines = $container->getStrings();
36 16
        if (count($lines) < 1) {
37
            return false;
38
        }
39
40 16
        if (method_exists($cursor, 'getNextNonSpacePosition')) {
41 16
            $expressionOffset = $cursor->getNextNonSpacePosition();
42
        } else {
43
            $expressionOffset = $cursor->getFirstNonSpacePosition();
0 ignored issues
show
Deprecated Code introduced by
The method League\CommonMark\Cursor...FirstNonSpacePosition() has been deprecated with message: Use getNextNonSpacePosition() instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
44
        }
45
46 16
        $match = RegexHelper::matchAll(self::REGEXP_DEFINITION, $cursor->getLine(), $expressionOffset);
47 16
        if (null === $match) {
48 2
            return false;
49
        }
50
51 16
        $columns = $this->parseColumns($match);
52 16
        $head = $this->parseRow(trim(array_pop($lines)), $columns, TableCell::TYPE_HEAD);
53 16
        if (null === $head) {
54
            return false;
55
        }
56
57 16
        $table = new Table(function (Cursor $cursor) use (&$table, $columns) {
58 16
            $row = $this->parseRow($cursor->getLine(), $columns);
59 16
            if (null === $row) {
60 6
                if (null !== $table->getCaption()) {
61 2
                    return false;
62
                }
63
64 6
                if (null !== ($caption = $this->parseCaption($cursor->getLine()))) {
65 2
                    $table->setCaption($caption);
66
67 2
                    return true;
68
                }
69
70 4
                return false;
71
            }
72
73 16
            $table->getBody()->appendChild($row);
74
75 16
            return true;
76 16
        });
77
78 16
        $table->getHead()->appendChild($head);
79
80 16
        if (count($lines) >= 1) {
81 2
            $paragraph = new Paragraph();
82 2
            foreach ($lines as $line) {
83 2
                $paragraph->addLine($line);
84
            }
85
86 2
            $context->replaceContainerBlock($paragraph);
87 2
            $context->addBlock($table);
88
        } else {
89 15
            $context->replaceContainerBlock($table);
90
        }
91
92 16
        return true;
93
    }
94
95 16
    private function parseColumns(array $match)
96
    {
97 16
        $columns = [];
98 16
        foreach ((array) $match[0] as $i => $column) {
99 16
            if (isset($match[1][$i]) && $match[1][$i] && isset($match[2][$i]) && $match[2][$i]) {
100 3
                $columns[] = TableCell::ALIGN_CENTER;
101 16
            } elseif (isset($match[1][$i]) && $match[1][$i]) {
102 3
                $columns[] = TableCell::ALIGN_LEFT;
103 16
            } elseif (isset($match[2][$i]) && $match[2][$i]) {
104 3
                $columns[] = TableCell::ALIGN_RIGHT;
105
            } else {
106 16
                $columns[] = null;
107
            }
108
        }
109
110 16
        return $columns;
111
    }
112
113 16
    private function parseRow($line, array $columns, $type = TableCell::TYPE_BODY)
114
    {
115 16
        $cells = RegexHelper::matchAll(self::REGEXP_CELLS, $line);
116
117 16
        if (null === $cells || $line === $cells[0]) {
118 6
            return;
119
        }
120
121 16
        $row = new TableRow();
122 16
        foreach ((array) $cells[0] as $i => $cell) {
123 16
            $row->appendChild(new TableCell(trim($cell), $type, isset($columns[$i]) ? $columns[$i] : null));
124
        }
125
126 16
        for ($j = count($columns) - 1; $j > $i; --$j) {
0 ignored issues
show
Bug introduced by
The variable $i seems to be defined by a foreach iteration on line 122. Are you sure the iterator is never empty, otherwise this variable is not defined?

It seems like you are relying on a variable being defined by an iteration:

foreach ($a as $b) {
}

// $b is defined here only if $a has elements, for example if $a is array()
// then $b would not be defined here. To avoid that, we recommend to set a
// default value for $b.


// Better
$b = 0; // or whatever default makes sense in your context
foreach ($a as $b) {
}

// $b is now guaranteed to be defined here.
Loading history...
127 1
            $row->appendChild(new TableCell('', $type, null));
128
        }
129
130 16
        return $row;
131
    }
132
133 6
    private function parseCaption($line)
134
    {
135 6
        $caption = RegexHelper::matchAll(self::REGEXP_CAPTION, $line);
136
137 6
        if (null === $caption) {
138 4
            return;
139
        }
140
141 2
        return new TableCaption($caption[1], $caption[2]);
142
    }
143
}
144