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

TableParser   A

Complexity

Total Complexity 29

Size/Duplication

Total Lines 123
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 9

Test Coverage

Coverage 95.31%

Importance

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

4 Methods

Rating   Name   Duplication   Size   Complexity  
C parse() 0 67 11
B parseColumns() 0 17 10
B parseRow() 0 19 6
A parseCaption() 0 10 2
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