xref: /webtrees/app/CommonMark/XrefParser.php (revision 56d475424b46df195a76f2a149ee5a07327497e8)
1<?php
2
3/**
4 * webtrees: online genealogy
5 * Copyright (C) 2021 webtrees development team
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17
18declare(strict_types=1);
19
20namespace Fisharebest\Webtrees\CommonMark;
21
22use Fisharebest\Webtrees\Gedcom;
23use Fisharebest\Webtrees\GedcomRecord;
24use Fisharebest\Webtrees\Registry;
25use Fisharebest\Webtrees\Tree;
26use League\CommonMark\Inline\Parser\InlineParserInterface;
27use League\CommonMark\InlineParserContext;
28
29use function is_string;
30use function trim;
31
32/**
33 * Convert XREFs within markdown text to links
34 */
35class XrefParser implements InlineParserInterface
36{
37    /** @var Tree - match XREFs in this tree */
38    private $tree;
39
40    /**
41     * MarkdownXrefParser constructor.
42     *
43     * @param Tree $tree
44     */
45    public function __construct(Tree $tree)
46    {
47        $this->tree = $tree;
48    }
49
50    /**
51     * We are only interested in text that begins with '@'.
52     *
53     * @return array<string>
54     */
55    public function getCharacters(): array
56    {
57        return ['@'];
58    }
59
60    /**
61     * @param InlineParserContext $inlineContext
62     *
63     * @return bool
64     */
65    public function parse(InlineParserContext $inlineContext): bool
66    {
67        // The cursor should be positioned on the opening '@'.
68        $cursor = $inlineContext->getCursor();
69
70        // If this isn't the start of an XREF, we'll need to rewind to here.
71        $previous_state = $cursor->saveState();
72
73        $xref = $cursor->match('/@' . Gedcom::REGEX_XREF . '@/');
74
75        if (is_string($xref)) {
76            $xref   = trim($xref, '@');
77            $record = Registry::gedcomRecordFactory()->make($xref, $this->tree);
78
79            if ($record instanceof GedcomRecord) {
80                $inlineContext->getContainer()->appendChild(new XrefNode($record));
81
82                return true;
83            }
84        }
85
86        // Not an XREF? Linked record does not exist?
87        $cursor->restoreState($previous_state);
88
89        return false;
90    }
91}
92