1c2ed51d1SGreg Roach<?php 2c2ed51d1SGreg Roach 3c2ed51d1SGreg Roach/** 4c2ed51d1SGreg Roach * webtrees: online genealogy 55bfc6897SGreg Roach * Copyright (C) 2022 webtrees development team 6c2ed51d1SGreg Roach * This program is free software: you can redistribute it and/or modify 7c2ed51d1SGreg Roach * it under the terms of the GNU General Public License as published by 8c2ed51d1SGreg Roach * the Free Software Foundation, either version 3 of the License, or 9c2ed51d1SGreg Roach * (at your option) any later version. 10c2ed51d1SGreg Roach * This program is distributed in the hope that it will be useful, 11c2ed51d1SGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of 12c2ed51d1SGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13c2ed51d1SGreg Roach * GNU General Public License for more details. 14c2ed51d1SGreg Roach * You should have received a copy of the GNU General Public License 15c2ed51d1SGreg Roach * along with this program. If not, see <https://www.gnu.org/licenses/>. 16c2ed51d1SGreg Roach */ 17c2ed51d1SGreg Roach 18c2ed51d1SGreg Roachdeclare(strict_types=1); 19c2ed51d1SGreg Roach 20c2ed51d1SGreg Roachnamespace Fisharebest\Webtrees\Factories; 21c2ed51d1SGreg Roach 22c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Contracts\ElementFactoryInterface; 23c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Contracts\ElementInterface; 24c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\AddressCity; 25c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\AddressCountry; 26c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\AddressEmail; 27c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\AddressFax; 28c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\AddressLine; 29c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\AddressLine1; 30c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\AddressLine2; 31c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\AddressLine3; 32c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\AddressPostalCode; 33c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\AddressState; 34c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\AddressWebPage; 35c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\AdoptedByWhichParent; 36c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\Adoption; 37c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\AdultChristening; 38c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\AgeAtEvent; 39c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\AncestralFileNumber; 40c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\Annulment; 41c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\ApprovedSystemId; 42c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\AutomatedRecordId; 43c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\Baptism; 443eb619d2SGreg Roachuse Fisharebest\Webtrees\Elements\BarMitzvah; 45c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\BasMitzvah; 46c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\Birth; 47c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\Blessing; 48c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\Burial; 49c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\CasteName; 50c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\CauseOfEvent; 51c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\Census; 52c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\CertaintyAssessment; 53c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\Change; 54c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\ChangeDate; 55c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\CharacterSet; 56c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\ChildLinkageStatus; 57c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\Christening; 58c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\Confirmation; 59c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\ContentDescription; 60241d59e1SGreg Roachuse Fisharebest\Webtrees\Elements\Coordinates; 61c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\CopyrightFile; 62c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\CopyrightSourceData; 63c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\CountOfChildren; 64c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\CountOfMarriages; 65c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\Cremation; 668c21658eSGreg Roachuse Fisharebest\Webtrees\Elements\CustomElement; 67*00c92694SGreg Roachuse Fisharebest\Webtrees\Elements\CustomEvent; 6878fa3281SGreg Roachuse Fisharebest\Webtrees\Elements\CustomFact; 694c93bfa7SGreg Roachuse Fisharebest\Webtrees\Elements\CustomFamilyEvent; 704c93bfa7SGreg Roachuse Fisharebest\Webtrees\Elements\CustomIndividualEvent; 71c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\DateLdsOrd; 72c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\DateValue; 73c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\Death; 74c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\DescriptiveTitle; 75c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\Divorce; 76c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\DivorceFiled; 77c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\Emigration; 78c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\EmptyElement; 79c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\Engagement; 80c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\EntryRecordingDate; 81c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\EventAttributeType; 82c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\EventOrFactClassification; 83c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\EventsRecorded; 84c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\EventTypeCitedFrom; 8582e500efSGreg Roachuse Fisharebest\Webtrees\Elements\FamilyCensus; 86e7e5b015SGreg Roachuse Fisharebest\Webtrees\Elements\FamilyRecord; 87a6081838SGreg Roachuse Fisharebest\Webtrees\Elements\FamilyResidence; 88*00c92694SGreg Roachuse Fisharebest\Webtrees\Elements\FamilySearchFamilyTreeId; 89*00c92694SGreg Roachuse Fisharebest\Webtrees\Elements\FamilyStatusText; 90c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\FileName; 91c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\FirstCommunion; 92c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\Form; 9390288370SGreg Roachuse Fisharebest\Webtrees\Elements\GedcomElement; 94c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\GenerationsOfAncestors; 95c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\GenerationsOfDescendants; 96*00c92694SGreg Roachuse Fisharebest\Webtrees\Elements\GovIdentifier; 97c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\Graduation; 98e7e5b015SGreg Roachuse Fisharebest\Webtrees\Elements\HeaderRecord; 99*00c92694SGreg Roachuse Fisharebest\Webtrees\Elements\HierarchicalRelationship; 100c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\Immigration; 101e7e5b015SGreg Roachuse Fisharebest\Webtrees\Elements\IndividualRecord; 102c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\LanguageId; 103c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\LdsBaptism; 104c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\LdsBaptismDateStatus; 105c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\LdsChildSealing; 106c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\LdsChildSealingDateStatus; 107c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\LdsConfirmation; 108c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\LdsEndowment; 109c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\LdsEndowmentDateStatus; 110c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\LdsSpouseSealing; 111c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\LdsSpouseSealingDateStatus; 112*00c92694SGreg Roachuse Fisharebest\Webtrees\Elements\LocationRecord; 113*00c92694SGreg Roachuse Fisharebest\Webtrees\Elements\MaidenheadLocator; 114c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\Marriage; 115c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\MarriageBanns; 116c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\MarriageContract; 117c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\MarriageLicence; 118c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\MarriageSettlement; 119c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\MarriageType; 120c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\MediaRecord; 121c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\MultimediaFileReference; 122c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\MultimediaFormat; 123c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\NameOfBusiness; 124c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\NameOfFamilyFile; 125c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\NameOfProduct; 126c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\NameOfRepository; 127c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\NameOfSourceData; 128c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\NamePersonal; 129c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\NamePhoneticVariation; 130c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\NamePieceGiven; 131c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\NamePieceNickname; 132c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\NamePiecePrefix; 133c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\NamePieceSuffix; 134c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\NamePieceSurname; 135c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\NamePieceSurnamePrefix; 136c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\NameRomanizedVariation; 137c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\NameType; 138c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\NationalIdNumber; 139c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\NationOrTribalOrigin; 140c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\Naturalization; 141c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\NobilityTypeTitle; 142c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\NoteRecord; 143c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\NoteStructure; 144c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\Occupation; 145c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\OrdinanceProcessFlag; 146c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\Ordination; 147*00c92694SGreg Roachuse Fisharebest\Webtrees\Elements\PafUid; 148c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\PedigreeLinkageType; 149c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\PermanentRecordFileNumber; 150c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\PhoneNumber; 151c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\PhoneticType; 152c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\PhysicalDescription; 153c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\PlaceHierarchy; 154c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\PlaceLatitude; 155c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\PlaceLivingOrdinance; 156c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\PlaceLongtitude; 157c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\PlaceName; 158c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\PlacePhoneticVariation; 159c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\PlaceRomanizedVariation; 160c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\Possessions; 161c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\Probate; 162c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\PublicationDate; 163c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\ReceivingSystemName; 164c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\RelationIsDescriptor; 165c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\ReligiousAffiliation; 166c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\RepositoryRecord; 167*00c92694SGreg Roachuse Fisharebest\Webtrees\Elements\ResearchTask; 168*00c92694SGreg Roachuse Fisharebest\Webtrees\Elements\ResearchTaskPriority; 169*00c92694SGreg Roachuse Fisharebest\Webtrees\Elements\ResearchTaskStatus; 170*00c92694SGreg Roachuse Fisharebest\Webtrees\Elements\ResearchTaskType; 171c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\Residence; 172c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\ResponsibleAgency; 173c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\RestrictionNotice; 174c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\Retirement; 175c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\RoleInEvent; 176c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\RomanizedType; 177c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\ScholasticAchievement; 178c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\SexValue; 179*00c92694SGreg Roachuse Fisharebest\Webtrees\Elements\SexXValue; 180c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\SocialSecurityNumber; 181c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\SourceCallNumber; 182c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\SourceData; 183c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\SourceFiledByEntry; 184c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\SourceJurisdictionPlace; 185c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\SourceMediaType; 186c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\SourceOriginator; 187c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\SourcePublicationFacts; 188c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\SourceRecord; 189c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\SubmissionRecord; 190c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\SubmitterName; 191c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\SubmitterRecord; 192c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\SubmitterRegisteredRfn; 193c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\SubmitterText; 194c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\TempleCode; 195c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\TextFromSource; 196c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\TimeValue; 197c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\TransmissionDate; 198c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\UnknownElement; 199c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\UserReferenceNumber; 200c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\UserReferenceType; 201c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\VersionNumber; 202*00c92694SGreg Roachuse Fisharebest\Webtrees\Elements\WebtreesUser; 203c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\WhereWithinSource; 204c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\Will; 2057b542389SGreg Roachuse Fisharebest\Webtrees\Elements\XrefAssociate; 206c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\XrefFamily; 207c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\XrefIndividual; 208*00c92694SGreg Roachuse Fisharebest\Webtrees\Elements\XrefLocation; 209c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\XrefMedia; 210c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\XrefRepository; 211c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\XrefSource; 212c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\XrefSubmission; 213c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Elements\XrefSubmitter; 214c2ed51d1SGreg Roachuse Fisharebest\Webtrees\I18N; 215472ace44SGreg Roach 216dc6af6c2SGreg Roachuse function array_merge; 217c2ed51d1SGreg Roachuse function preg_match; 218*00c92694SGreg Roachuse function var_dump; 219c2ed51d1SGreg Roach 220c2ed51d1SGreg Roach/** 221c2ed51d1SGreg Roach * Make a GEDCOM element. 222c2ed51d1SGreg Roach */ 223c2ed51d1SGreg Roachclass ElementFactory implements ElementFactoryInterface 224c2ed51d1SGreg Roach{ 2253d2c98d1SGreg Roach /** @var array<string,ElementInterface> */ 2264dbb2a39SGreg Roach private array $elements = []; 227c2ed51d1SGreg Roach 228c2ed51d1SGreg Roach /** 229c2ed51d1SGreg Roach * Create a GEDCOM element that corresponds to a GEDCOM tag. 230c2ed51d1SGreg Roach * Finds the correct element for all valid tags. 231c2ed51d1SGreg Roach * Finds a likely element for custom tags. 232c2ed51d1SGreg Roach * 233c2ed51d1SGreg Roach * @param string $tag - Colon delimited hierarchy, e.g. 'INDI:BIRT:PLAC' 234c2ed51d1SGreg Roach * 235c2ed51d1SGreg Roach * @return ElementInterface 236c2ed51d1SGreg Roach */ 237c2ed51d1SGreg Roach public function make(string $tag): ElementInterface 238c2ed51d1SGreg Roach { 239*00c92694SGreg Roach return $this->elements[$tag] ?? $this->findElementByWildcard($tag) ?? new UnknownElement($tag); 240c2ed51d1SGreg Roach } 241c2ed51d1SGreg Roach 242c2ed51d1SGreg Roach /** 243*00c92694SGreg Roach * Register GEDCOM tags. 2444ab8e344SGreg Roach * 2454ab8e344SGreg Roach * @param array<string,ElementInterface> $elements 2464ab8e344SGreg Roach */ 247*00c92694SGreg Roach public function registerTags(array $elements): void 2484ab8e344SGreg Roach { 249*00c92694SGreg Roach $this->elements = $elements + $this->elements; 250*00c92694SGreg Roach } 251*00c92694SGreg Roach 252*00c92694SGreg Roach /** 253*00c92694SGreg Roach * Register more subtags. 254*00c92694SGreg Roach * 255*00c92694SGreg Roach * @param array<string,array<int,array<int,string>>> $subtags 256*00c92694SGreg Roach */ 257*00c92694SGreg Roach public function registerSubTags(array $subtags): void 258*00c92694SGreg Roach { 259*00c92694SGreg Roach foreach ($subtags as $tag => $children) { 260*00c92694SGreg Roach foreach ($children as $child) { 261*00c92694SGreg Roach $this->make($tag)->subtag(...$child); 262*00c92694SGreg Roach } 263*00c92694SGreg Roach } 2644ab8e344SGreg Roach } 2654ab8e344SGreg Roach 2664ab8e344SGreg Roach /** 2674ab8e344SGreg Roach * @param string $tag 2684ab8e344SGreg Roach * 2694ab8e344SGreg Roach * @return ElementInterface|null 2704ab8e344SGreg Roach */ 2714ab8e344SGreg Roach private function findElementByWildcard(string $tag): ?ElementInterface 2724ab8e344SGreg Roach { 273*00c92694SGreg Roach foreach ($this->elements as $tags => $element) { 274c5b48766SGreg Roach if (str_contains($tags, '*')) { 2754ab8e344SGreg Roach $regex = '/^' . strtr($tags, ['*' => '[^:]+']) . '$/'; 2764ab8e344SGreg Roach 2774ab8e344SGreg Roach if (preg_match($regex, $tag)) { 2784ab8e344SGreg Roach return $element; 2794ab8e344SGreg Roach } 2804ab8e344SGreg Roach } 2814ab8e344SGreg Roach } 2824ab8e344SGreg Roach 2834ab8e344SGreg Roach return null; 2844ab8e344SGreg Roach } 285c2ed51d1SGreg Roach} 286