Completed
Push — master ( 103c69...214519 )
by Colin
35:28 queued 34:02
created

GatherFootnotesListener   A

Complexity

Total Complexity 11

Size/Duplication

Total Lines 77
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 11

Test Coverage

Coverage 94.59%

Importance

Changes 0
Metric Value
wmc 11
lcom 0
cbo 11
dl 0
loc 77
ccs 35
cts 37
cp 0.9459
rs 10
c 0
b 0
f 0

3 Methods

Rating   Name   Duplication   Size   Complexity  
B onDocumentParsed() 0 42 7
A getFootnotesContainer() 0 7 1
A createBackrefs() 0 17 3
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\Event\DocumentParsedEvent;
18
use League\CommonMark\Extension\Footnote\Node\Footnote;
19
use League\CommonMark\Extension\Footnote\Node\FootnoteBackref;
20
use League\CommonMark\Extension\Footnote\Node\FootnoteContainer;
21
use League\CommonMark\Node\Block\Document;
22
use League\CommonMark\Reference\Reference;
23
24
final class GatherFootnotesListener
25
{
26 42
    public function onDocumentParsed(DocumentParsedEvent $event): void
27
    {
28 42
        $document = $event->getDocument();
29 42
        $walker   = $document->walker();
30
31 42
        $footnotes = [];
32 42
        while ($event = $walker->next()) {
33 42
            if (! $event->isEntering()) {
34 42
                continue;
35
            }
36
37 42
            $node = $event->getNode();
38 42
            if (! $node instanceof Footnote) {
39 42
                continue;
40
            }
41
42
            // Look for existing reference with footnote label
43 36
            $ref = $document->getReferenceMap()->get($node->getReference()->getLabel());
44 36
            if ($ref !== null) {
45
                // Use numeric title to get footnotes order
46 36
                $footnotes[\intval($ref->getTitle())] = $node;
47
            } else {
48
                // Footnote call is missing, append footnote at the end
49
                $footnotes[\PHP_INT_MAX] = $node;
50
            }
51
52 36
            $backrefs = $document->getData('#fn:' . $node->getReference()->getDestination(), []);
53 36
            $this->createBackrefs($node, $backrefs);
54
        }
55
56
        // Only add a footnote container if there are any
57 42
        if (\count($footnotes) === 0) {
58 6
            return;
59
        }
60
61 36
        $container = $this->getFootnotesContainer($document);
62
63 36
        \ksort($footnotes);
64 36
        foreach ($footnotes as $footnote) {
65 36
            $container->appendChild($footnote);
66
        }
67 36
    }
68
69 36
    private function getFootnotesContainer(Document $document): FootnoteContainer
70
    {
71 36
        $footnoteContainer = new FootnoteContainer();
72 36
        $document->appendChild($footnoteContainer);
73
74 36
        return $footnoteContainer;
75
    }
76
77
    /**
78
     * Look for all footnote refs pointing to this footnote and create each footnote backrefs.
79
     *
80
     * @param Footnote    $node     The target footnote
81
     * @param Reference[] $backrefs References to create backrefs for
82
     */
83 36
    private function createBackrefs(Footnote $node, array $backrefs): void
84
    {
85
        // Backrefs should be added to the child paragraph
86 36
        $target = $node->lastChild();
87 36
        if ($target === null) {
88
            // This should never happen, but you never know
89
            $target = $node;
90
        }
91
92 36
        foreach ($backrefs as $backref) {
93 18
            $target->appendChild(new FootnoteBackref(new Reference(
94 18
                $backref->getLabel(),
95 18
                '#fnref:' . $backref->getLabel(),
96 18
                $backref->getTitle()
97
            )));
98
        }
99 36
    }
100
}
101