1<?php 2 3/* 4 * This file is part of the league/commonmark package. 5 * 6 * (c) Colin O'Dell <colinodell@gmail.com> 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 13declare(strict_types=1); 14 15namespace League\CommonMark\Extension\Footnote\Event; 16 17use League\CommonMark\Block\Element\Document; 18use League\CommonMark\Event\DocumentParsedEvent; 19use League\CommonMark\Extension\Footnote\Node\Footnote; 20use League\CommonMark\Extension\Footnote\Node\FootnoteBackref; 21use League\CommonMark\Extension\Footnote\Node\FootnoteContainer; 22use League\CommonMark\Reference\Reference; 23use League\CommonMark\Util\ConfigurationAwareInterface; 24use League\CommonMark\Util\ConfigurationInterface; 25 26final class GatherFootnotesListener implements ConfigurationAwareInterface 27{ 28 /** @var ConfigurationInterface */ 29 private $config; 30 31 public function onDocumentParsed(DocumentParsedEvent $event): void 32 { 33 $document = $event->getDocument(); 34 $walker = $document->walker(); 35 36 $footnotes = []; 37 while ($event = $walker->next()) { 38 if (!$event->isEntering()) { 39 continue; 40 } 41 42 $node = $event->getNode(); 43 if (!$node instanceof Footnote) { 44 continue; 45 } 46 47 // Look for existing reference with footnote label 48 $ref = $document->getReferenceMap()->getReference($node->getReference()->getLabel()); 49 if ($ref !== null) { 50 // Use numeric title to get footnotes order 51 $footnotes[\intval($ref->getTitle())] = $node; 52 } else { 53 // Footnote call is missing, append footnote at the end 54 $footnotes[INF] = $node; 55 } 56 57 /* 58 * Look for all footnote refs pointing to this footnote 59 * and create each footnote backrefs. 60 */ 61 $backrefs = $document->getData( 62 '#' . $this->config->get('footnote/footnote_id_prefix', 'fn:') . $node->getReference()->getDestination(), 63 [] 64 ); 65 /** @var Reference $backref */ 66 foreach ($backrefs as $backref) { 67 $node->addBackref(new FootnoteBackref(new Reference( 68 $backref->getLabel(), 69 '#' . $this->config->get('footnote/ref_id_prefix', 'fnref:') . $backref->getLabel(), 70 $backref->getTitle() 71 ))); 72 } 73 } 74 75 // Only add a footnote container if there are any 76 if (\count($footnotes) === 0) { 77 return; 78 } 79 80 $container = $this->getFootnotesContainer($document); 81 82 \ksort($footnotes); 83 foreach ($footnotes as $footnote) { 84 $container->appendChild($footnote); 85 } 86 } 87 88 private function getFootnotesContainer(Document $document): FootnoteContainer 89 { 90 $footnoteContainer = new FootnoteContainer(); 91 $document->appendChild($footnoteContainer); 92 93 return $footnoteContainer; 94 } 95 96 public function setConfiguration(ConfigurationInterface $config): void 97 { 98 $this->config = $config; 99 } 100} 101