<?php
declare(strict_types=1);
namespace League\CommonMark\Extension\Footnote\Event;
use League\CommonMark\Event\DocumentParsedEvent;
use League\CommonMark\Extension\Footnote\Node\Footnote;
use League\CommonMark\Extension\Footnote\Node\FootnoteBackref;
use League\CommonMark\Extension\Footnote\Node\FootnoteContainer;
use League\CommonMark\Node\Block\Document;
use League\CommonMark\Node\NodeIterator;
use League\CommonMark\Reference\Reference;
use League\Config\ConfigurationAwareInterface;
use League\Config\ConfigurationInterface;
final class GatherFootnotesListener implements ConfigurationAwareInterface
{
private ConfigurationInterface $config;
public function onDocumentParsed(DocumentParsedEvent $event): void
{
$document = $event->getDocument();
$footnotes = [];
foreach ($document->iterator(NodeIterator::FLAG_BLOCKS_ONLY) as $node) {
if (! $node instanceof Footnote) {
continue;
}
$ref = $document->getReferenceMap()->get($node->getReference()->getLabel());
if ($ref !== null) {
$footnotes[(int) $ref->getTitle()] = $node;
} else {
$footnotes[\PHP_INT_MAX] = $node;
}
$key = '#' . $this->config->get('footnote/footnote_id_prefix') . $node->getReference()->getDestination();
if ($document->data->has($key)) {
$this->createBackrefs($node, $document->data->get($key));
}
}
if (\count($footnotes) === 0) {
return;
}
$container = $this->getFootnotesContainer($document);
\ksort($footnotes);
foreach ($footnotes as $footnote) {
$container->appendChild($footnote);
}
}
private function getFootnotesContainer(Document $document): FootnoteContainer
{
$footnoteContainer = new FootnoteContainer();
$document->appendChild($footnoteContainer);
return $footnoteContainer;
}
private function createBackrefs(Footnote $node, array $backrefs): void
{
$target = $node->lastChild();
if ($target === null) {
$target = $node;
}
foreach ($backrefs as $backref) {
$target->appendChild(new FootnoteBackref(new Reference(
$backref->getLabel(),
'#' . $this->config->get('footnote/ref_id_prefix') . $backref->getLabel(),
$backref->getTitle()
)));
}
}
public function setConfiguration(ConfigurationInterface $configuration): void
{
$this->config = $configuration;
}
}