xref: /webtrees/app/CommonMark/XrefParser.php (revision 30e63383b10bafff54347985dcdbd10c40c33f62)
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    private Tree $tree;
38
39    /**
40     * MarkdownXrefParser constructor.
41     *
42     * @param Tree $tree Match XREFs in this tree
43     */
44    public function __construct(Tree $tree)
45    {
46        $this->tree = $tree;
47    }
48
49    /**
50     * We are only interested in text that begins with '@'.
51     *
52     * @return array<string>
53     */
54    public function getCharacters(): array
55    {
56        return ['@'];
57    }
58
59    /**
60     * @param InlineParserContext $inlineContext
61     *
62     * @return bool
63     */
64    public function parse(InlineParserContext $inlineContext): bool
65    {
66        // The cursor should be positioned on the opening '@'.
67        $cursor = $inlineContext->getCursor();
68
69        // If this isn't the start of an XREF, we'll need to rewind to here.
70        $previous_state = $cursor->saveState();
71
72        $xref = $cursor->match('/@' . Gedcom::REGEX_XREF . '@/');
73
74        if (is_string($xref)) {
75            $xref   = trim($xref, '@');
76            $record = Registry::gedcomRecordFactory()->make($xref, $this->tree);
77
78            if ($record instanceof GedcomRecord) {
79                $inlineContext->getContainer()->appendChild(new XrefNode($record));
80
81                return true;
82            }
83        }
84
85        // Not an XREF? Linked record does not exist?
86        $cursor->restoreState($previous_state);
87
88        return false;
89    }
90}
91