xref: /webtrees/app/Factories/ElementFactory.php (revision 09523927627d8824ee0799f8137d6de75b8b7921)
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    /**
75     * @param string $tag
76     *
77     * @return ElementInterface|null
78     */
79    private function findElementByWildcard(string $tag): ?ElementInterface
80    {
81        foreach ($this->elements as $tags => $element) {
82            if (str_contains($tags, '*')) {
83                $regex = '/^' . strtr($tags, ['*' => '[^:]+']) . '$/';
84
85                if (preg_match($regex, $tag)) {
86                    return $element;
87                }
88            }
89        }
90
91        return null;
92    }
93}
94