Passed
Push — latest ( ba39d8...ca9086 )
by Colin
08:23
created

GatherFootnotesListener::onDocumentParsed()   B

Complexity

Conditions 7
Paths 15

Size

Total Lines 43
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 23
CRAP Score 7.0035

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 23
dl 0
loc 43
ccs 23
cts 24
cp 0.9583
c 1
b 0
f 0
rs 8.6186
cc 7
nc 15
nop 1
crap 7.0035
1
<?php
2
3
/*
4
 * This file is part of the league/commonmark package.
5
 *
6
 * (c) Colin O'Dell <[email protected]>
7
 * (c) Rezo Zero / Ambroise Maupate
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
declare(strict_types=1);
14
15
namespace League\CommonMark\Extension\Footnote\Event;
16
17
use League\CommonMark\Configuration\ConfigurationAwareInterface;
18
use League\CommonMark\Configuration\ConfigurationInterface;
19
use League\CommonMark\Event\DocumentParsedEvent;
20
use League\CommonMark\Extension\Footnote\Node\Footnote;
21
use League\CommonMark\Extension\Footnote\Node\FootnoteBackref;
22
use League\CommonMark\Extension\Footnote\Node\FootnoteContainer;
23
use League\CommonMark\Node\Block\Document;
24
use League\CommonMark\Reference\Reference;
25
26
final class GatherFootnotesListener implements ConfigurationAwareInterface
27
{
28
    /** @var ConfigurationInterface */
29
    private $config;
30
31 96
    public function onDocumentParsed(DocumentParsedEvent $event): void
32
    {
33 96
        $document = $event->getDocument();
34 96
        $walker   = $document->walker();
35
36 96
        $footnotes = [];
37 96
        while ($event = $walker->next()) {
38 96
            if (! $event->isEntering()) {
39 96
                continue;
40
            }
41
42 96
            $node = $event->getNode();
43 96
            if (! $node instanceof Footnote) {
44 96
                continue;
45
            }
46
47
            // Look for existing reference with footnote label
48 87
            $ref = $document->getReferenceMap()->get($node->getReference()->getLabel());
49 87
            if ($ref !== null) {
50
                // Use numeric title to get footnotes order
51 87
                $footnotes[\intval($ref->getTitle())] = $node;
52
            } else {
53
                // Footnote call is missing, append footnote at the end
54
                $footnotes[\PHP_INT_MAX] = $node;
55
            }
56
57 87
            $backrefs = $document->getData(
58 87
                '#' . $this->config->get('footnote/footnote_id_prefix', 'fn:') . $node->getReference()->getDestination(),
59 87
                []
60
            );
61 87
            $this->createBackrefs($node, $backrefs);
62
        }
63
64
        // Only add a footnote container if there are any
65 96
        if (\count($footnotes) === 0) {
66 9
            return;
67
        }
68
69 87
        $container = $this->getFootnotesContainer($document);
70
71 87
        \ksort($footnotes);
72 87
        foreach ($footnotes as $footnote) {
73 87
            $container->appendChild($footnote);
74
        }
75 87
    }
76
77 87
    private function getFootnotesContainer(Document $document): FootnoteContainer
78
    {
79 87
        $footnoteContainer = new FootnoteContainer();
80 87
        $document->appendChild($footnoteContainer);
81
82 87
        return $footnoteContainer;
83
    }
84
85
    /**
86
     * Look for all footnote refs pointing to this footnote and create each footnote backrefs.
87
     *
88
     * @param Footnote    $node     The target footnote
89
     * @param Reference[] $backrefs References to create backrefs for
90
     */
91 87
    private function createBackrefs(Footnote $node, array $backrefs): void
92
    {
93
        // Backrefs should be added to the child paragraph
94 87
        $target = $node->lastChild();
95 87
        if ($target === null) {
96
            // This should never happen, but you never know
97 9
            $target = $node;
98
        }
99
100 87
        foreach ($backrefs as $backref) {
101 66
            $target->appendChild(new FootnoteBackref(new Reference(
102 66
                $backref->getLabel(),
103 66
                '#' . $this->config->get('footnote/ref_id_prefix', 'fnref:') . $backref->getLabel(),
104 66
                $backref->getTitle()
105
            )));
106
        }
107 87
    }
108
109 96
    public function setConfiguration(ConfigurationInterface $config): void
110
    {
111 96
        $this->config = $config;
112 96
    }
113
}
114