xref: /webtrees/app/Factories/ElementFactory.php (revision 9d74ed0ab3ae61aa8ae07578e026f14020844ce9)
1<?php
2
3/**
4 * webtrees: online genealogy
5 * Copyright (C) 2023 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\Factories;
21
22use Fisharebest\Webtrees\Contracts\ElementFactoryInterface;
23use Fisharebest\Webtrees\Contracts\ElementInterface;
24use Fisharebest\Webtrees\Elements\UnknownElement;
25
26use function preg_match;
27
28/**
29 * Make a GEDCOM element.
30 */
31class ElementFactory implements ElementFactoryInterface
32{
33    /** @var array<string,ElementInterface> */
34    private array $elements = [];
35
36    /**
37     * Create a GEDCOM element that corresponds to a GEDCOM tag.
38     * Finds the correct element for all valid tags.
39     * Finds a likely element for custom tags.
40     *
41     * @param string $tag Colon delimited hierarchy, e.g. 'INDI:BIRT:PLAC'
42     *
43     * @return ElementInterface
44     */
45    public function make(string $tag): ElementInterface
46    {
47        return $this->elements[$tag] ?? $this->findElementByWildcard($tag) ?? new UnknownElement($tag);
48    }
49
50    /**
51     * Register GEDCOM tags.
52     *
53     * @param array<string,ElementInterface> $elements
54     */
55    public function registerTags(array $elements): void
56    {
57        $this->elements = $elements + $this->elements;
58    }
59
60    /**
61     * Register more subtags.
62     *
63     * @param array<string,array<int,array<int,string>>> $subtags
64     */
65    public function registerSubTags(array $subtags): void
66    {
67        foreach ($subtags as $tag => $children) {
68            foreach ($children as $child) {
69                $this->make($tag)->subtag(...$child);
70            }
71        }
72    }
73
74    private function findElementByWildcard(string $tag): ElementInterface|null
75    {
76        foreach ($this->elements as $tags => $element) {
77            if (str_contains($tags, '*')) {
78                $regex = '/^' . strtr($tags, ['*' => '[^:]+']) . '$/';
79
80                if (preg_match($regex, $tag)) {
81                    return $element;
82                }
83            }
84        }
85
86        return null;
87    }
88}
89