Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
25 / 25
100.00% covered (success)
100.00%
5 / 5
CRAP
100.00% covered (success)
100.00%
1 / 1
DomainCatalogFileLoader
100.00% covered (success)
100.00%
25 / 25
100.00% covered (success)
100.00%
5 / 5
10
100.00% covered (success)
100.00%
1 / 1
 setDomainCatalogDirectory
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 getDomainCatalogDirectory
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getPossibleFilenamePartsFromLocale
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
3
 getCatalogFilePathFromDomainLocale
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
3
 loadCatalog
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getFileType
n/a
0 / 0
n/a
0 / 0
0
 parseDomainCatalogFile
n/a
0 / 0
n/a
0 / 0
0
1<?php
2
3/**
4 * @author: Doug Wilbourne (dougwilbourne@gmail.com)
5 */
6
7declare(strict_types=1);
8
9namespace pvc\msg;
10
11use Locale;
12use pvc\interfaces\msg\DomainCatalogLoaderInterface;
13use pvc\msg\err\NonExistentDomainCatalogDirectoryException;
14use pvc\msg\err\NonExistentDomainCatalogFileException;
15
16/**
17 * Class DomainCatalogFileLoader
18 */
19abstract class DomainCatalogFileLoader implements DomainCatalogLoaderInterface
20{
21    /**
22     * @var string
23     */
24    protected string $domainCatalogDirectory;
25
26    /**
27     * setDomainCatalogDirectory
28     * @param string $dirname
29     * @throws NonExistentDomainCatalogDirectoryException
30     */
31    public function setDomainCatalogDirectory(string $dirname): void
32    {
33        if (!is_dir($dirname)) {
34            throw new NonExistentDomainCatalogDirectoryException($dirname);
35        }
36        $this->domainCatalogDirectory = $dirname;
37    }
38
39    /**
40     * @return string
41     */
42    public function getDomainCatalogDirectory(): string
43    {
44        return $this->domainCatalogDirectory;
45    }
46
47    /**
48     * getPossibleFilenamePartsFromLocale
49     * @param string $locale
50     * @return array<string>
51     */
52    protected function getPossibleFilenamePartsFromLocale(string $locale): array
53    {
54        /**
55         * the order of this is important.  We want the more specific filename parts at the beginning and the most
56         * generalized (e.g. just a language) at the end.
57         *
58         * Symfony uses the concept of a 'parent locale', which is a more sophisticated approach.  It requires the
59         * construction of a set parent locales and their "children".  For example, Argentinian spanish would degrade
60         * to south american spanish.
61         *
62         * If there is no catalog that works for the locale specified, try english as the default.
63         */
64
65        /** array_filter removes any empty strings */
66        $localeArray = array_filter([
67                                        Locale::getPrimaryLanguage($locale),
68                                        Locale::getScript($locale),
69                                        Locale::getRegion($locale)
70                                    ]);
71        /** @var array<string> $result */
72        $result = [];
73        while (count($localeArray) > 0) {
74            $result[] = implode('_', $localeArray);
75            array_pop($localeArray);
76        }
77        if (!in_array('en', $result)) {
78            $result[] = 'en';
79        }
80        return $result;
81    }
82
83    /**
84     * getCatalogFilePathFromDomainLocale
85     * @param string $domain
86     * @param string $locale
87     * @return string
88     */
89    public function getCatalogFilePathFromDomainLocale(string $domain, string $locale = ''): string
90    {
91        /**
92         * construct catalog filename in the canonical form <domain>.<locale>.<filetype> where locale is either the
93         * language_script_region or language_region or language.
94         */
95
96        $possibleFilenameParts = $this->getPossibleFilenamePartsFromLocale($locale);
97
98        /**
99         * return the first (e.g. most specific) domain catalog file that exists
100         */
101        foreach ($possibleFilenameParts as $filenamePart) {
102            $filename = $domain . '.' . $filenamePart . '.' . $this->getFileType();
103            $filepath = $this->getDomainCatalogDirectory() . DIRECTORY_SEPARATOR . $filename;
104            if (file_exists($filepath)) {
105                return $filepath;
106            }
107        }
108        /**
109         * throw an exception if we were not able to find any files that match the domain / locale.
110         */
111        throw new NonExistentDomainCatalogFileException($domain, $locale);
112    }
113
114    /**
115     * loadCatalog
116     * @param string $domain
117     * @param string $locale
118     * @return string[]
119     * @throws NonExistentDomainCatalogFileException
120     */
121    public function loadCatalog(string $domain, string $locale): array
122    {
123        $catalogFilePath = $this->getCatalogFilePathFromDomainLocale($domain, $locale);
124        return $this->parseDomainCatalogFile($catalogFilePath);
125    }
126
127    /**
128     * getFileType
129     * @return string
130     * returns the file extension (type) that this loaderFactory can parse and load
131     */
132    abstract public function getFileType(): string;
133
134    /**
135     * parseDomainCatalogFile
136     * @return array<string, string>
137     */
138    abstract public function parseDomainCatalogFile(string $filepath): array;
139}