Completed
Push — master ( 65f918...0273ce )
by Martin
05:12
created

TableParser   A

Complexity

Total Complexity 29

Size/Duplication

Total Lines 123
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 9

Test Coverage

Coverage 96.88%

Importance

Changes 0
Metric Value
wmc 29
c 0
b 0
f 0
lcom 1
cbo 9
dl 0
loc 123
ccs 62
cts 64
cp 0.9688
rs 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
A parseCaption() 0 10 2
C parse() 0 63 10
B parseColumns() 0 17 10
C parseRow() 0 23 7
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 17
    public function parse(ContextInterface $context, Cursor $cursor)
28
    {
29 17
        $container = $context->getContainer();
30
31 17
        if (!$container instanceof Paragraph) {
32 17
            return false;
33
        }
34
35 17
        $lines = $container->getStrings();
36 17
        if (count($lines) < 1) {
37
            return false;
38
        }
39
40 17
        $expressionOffset = $cursor->getNextNonSpacePosition();
41
42 17
        $match = RegexHelper::matchAll(self::REGEXP_DEFINITION, $cursor->getLine(), $expressionOffset);
43 17
        if (null === $match) {
44 2
            return false;
45
        }
46
47 17
        $columns = $this->parseColumns($match);
48 17
        $head = $this->parseRow(trim(array_pop($lines)), $columns, TableCell::TYPE_HEAD);
49 17
        if (null === $head) {
50
            return false;
51
        }
52
53 17
        $table = new Table(function (Cursor $cursor) use (&$table, $columns) {
54 17
            $row = $this->parseRow($cursor->getLine(), $columns);
55 17
            if (null === $row) {
56 6
                if (null !== $table->getCaption()) {
57 2
                    return false;
58
                }
59
60 6
                if (null !== ($caption = $this->parseCaption($cursor->getLine()))) {
61 2
                    $table->setCaption($caption);
62
63 2
                    return true;
64
                }
65
66 4
                return false;
67
            }
68
69 17
            $table->getBody()->appendChild($row);
70
71 17
            return true;
72 17
        });
73
74 17
        $table->getHead()->appendChild($head);
75
76 17
        if (count($lines) >= 1) {
77 2
            $paragraph = new Paragraph();
78 2
            foreach ($lines as $line) {
79 2
                $paragraph->addLine($line);
80
            }
81
82 2
            $context->replaceContainerBlock($paragraph);
83 2
            $context->addBlock($table);
84
        } else {
85 16
            $context->replaceContainerBlock($table);
86
        }
87
88 17
        return true;
89
    }
90
91 17
    private function parseColumns(array $match)
92
    {
93 17
        $columns = [];
94 17
        foreach ((array) $match[0] as $i => $column) {
95 17
            if (isset($match[1][$i]) && $match[1][$i] && isset($match[2][$i]) && $match[2][$i]) {
96 3
                $columns[] = TableCell::ALIGN_CENTER;
97 17
            } elseif (isset($match[1][$i]) && $match[1][$i]) {
98 3
                $columns[] = TableCell::ALIGN_LEFT;
99 17
            } elseif (isset($match[2][$i]) && $match[2][$i]) {
100 3
                $columns[] = TableCell::ALIGN_RIGHT;
101
            } else {
102 17
                $columns[] = '';
103
            }
104
        }
105
106 17
        return $columns;
107
    }
108
109 17
    private function parseRow($line, array $columns, $type = TableCell::TYPE_BODY)
110
    {
111 17
        $cells = RegexHelper::matchAll(self::REGEXP_CELLS, $line);
112
113 17
        if (null === $cells || $line === $cells[0]) {
114 6
            return;
115
        }
116
117 17
        $row = new TableRow();
118 17
        foreach ((array) $cells[0] as $i => $cell) {
119 17
            if (!isset($columns[$i])) {
120 1
                return $row;
121
            }
122
123 17
            $row->appendChild(new TableCell(trim($cell), $type, isset($columns[$i]) ? $columns[$i] : null));
124
        }
125
126 17
        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 118. 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 17
        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