Passed
Push — master ( 091505...2927d0 )
by zyt
02:52 queued 01:13
created

GoogleFontsCollection::addFontFromString()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 23
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 10
nc 2
nop 2
dl 0
loc 23
ccs 11
cts 11
cp 1
crap 2
rs 9.0856
c 0
b 0
f 0
1
<?php
2
3
namespace ZWF;
4
5
use ZWF\GoogleFontsOptimizerUtils as Utils;
6
7
class GoogleFontsCollection
8
{
9
10
    protected $links = [];
11
12
    protected $texts = [];
13
14
    protected $complete = [];
15
16
    protected $fonts = [];
17
18
    protected $subsetsMap = [];
19
20
    protected $namedSizes = [];
21
22 5
    public function __construct(array $urls = [])
23 5
    {
24 5
        if (! empty($urls)) {
25 5
            foreach ($urls as $url) {
26 5
                $this->add($url);
27
            }
28
        }
29 5
    }
30
31 5
    public function add($url)
32 5
    {
33 5
        $this->addLink($url);
34
35 5
        $params = [];
36 5
        parse_str(parse_url($url, PHP_URL_QUERY), $params);
37
38 5
        $bucket = isset($params['text']) ? 'text' : 'complete';
39
40 5
        $fontstrings = $this->buildFontStringsFromQueryParams($params);
41 5
        foreach ($fontstrings as $font) {
42 5
            $this->addFontFromString($font, $bucket);
43 5
            if ('text' === $bucket) {
44 3
                $font_family = explode(':', $font);
45 3
                $this->addTextFont($font_family[0], Utils::httpsify($url));
46
            } else {
47 5
                $this->addComplete($font);
48
            }
49
        }
50 5
    }
51
52
    /**
53
     * Returns an array of data needed to generated webfontloader script markup.
54
     *
55
     * @return array
56
     */
57 2
    public function getScriptData()
58 2
    {
59
        return [
60 2
            $this->getNamedSizesMap(),
61 2
            $this->getSubsetsMap()
62
        ];
63
    }
64
65 5
    protected function addFontFromString($fontstring, $bucket = 'complete')
66 5
    {
67 5
        $font    = GoogleFont::fromString($fontstring);
68 5
        $name    = $font->getName();
69 5
        $subsets = $font->getSubsetsString();
70
71
        // Add to bucket list
72 5
        $this->fonts[$bucket][] = $font;
73
74
        // Keeping a separate map of names => subsets for webfontloader purposes
75 5
        if (! array_key_exists($name, $this->subsetsMap)) {
76
            // Nothing found yet, create a new key
77 5
            $this->subsetsMap[$name] = $subsets;
78
        } else {
79
            // Something is in there already, merge
80 1
            $this->subsetsMap[$name] = array_merge($this->subsetsMap[$name], (array) $subsets);
81
        }
82
83
        // Deduplicate values and don't sort the subsets map
84 5
        $this->subsetsMap = Utils::dedupValues($this->subsetsMap, false); // no sort
85
86
        // Maintain the list/hash of name => sizes when adding a new one too
87 5
        $this->namedSizes = $this->buildNamedsizesMap();
88 5
    }
89
90
    /**
91
     * @return array
92
     */
93 2
    protected function getSubsetsMap()
94 2
    {
95 2
        return $this->subsetsMap;
96
    }
97
98 3
    protected function addTextFont($name, $url)
99 3
    {
100 3
        $this->texts['name'][] = $name;
101 3
        $this->texts['url'][]  = $url;
102 3
    }
103
104 5
    protected function addComplete($fontstring)
105 5
    {
106 5
        $this->complete[] = $fontstring;
107 5
    }
108
109 5
    protected function addLink($url)
110 5
    {
111 5
        $this->links[] = $url;
112 5
    }
113
114 4
    public function getOriginalLinks()
115 4
    {
116 4
        return $this->links;
117
    }
118
119 5
    public function hasText()
120 5
    {
121 5
        return (! empty($this->texts));
122
    }
123
124
    /**
125
     * @return array
126
     */
127 4
    public function getTextUrls()
128 4
    {
129 4
        $urls = [];
130
131 4
        if ($this->hasText()) {
132 3
            $urls = $this->texts['url'];
133
        }
134
135 4
        return $urls;
136
    }
137
138
    /**
139
     * @return array
140
     */
141 1
    public function getTextNames()
142 1
    {
143 1
        return $this->texts['name'];
144
    }
145
146 5
    public function getFonts()
147 5
    {
148 5
        return $this->fonts['complete'];
149
    }
150
151
    public function getFontsText()
152
    {
153
        return $this->fonts['text'];
154
    }
155
156 3
    public function getCombinedUrl()
157 3
    {
158 3
        return Utils::buildGoogleFontsUrl($this->getNamedSizesMap(), $this->getSubsets());
159
    }
160
161 5
    public function getNamedSizesMap()
162 5
    {
163 5
        return $this->namedSizes;
164
    }
165
166 3
    public function getSubsets()
167 3
    {
168 3
        $subsets = [];
169
170 3
        $fonts = $this->getFonts();
171 3
        foreach ($fonts as $font) {
172 3
            $subsets[] = $font->getSubsets();
173
        }
174
175 3
        $subsets = Utils::arrayFlattenIterative($subsets);
176
177 3
        return array_unique($subsets);
178
    }
179
180
    /**
181
     * @return array
182
     */
183 5
    protected function buildNamedsizesMap()
184 5
    {
185 5
        $fonts = [];
186
187 5
        foreach ($this->getFonts() as $font) {
188 5
            $name = $font->getName();
189 5
            if (! array_key_exists($name, $fonts)) {
190 5
                $fonts[$name] = $font->getSizes();
191
            } else {
192 5
                $fonts[$name] = array_merge($fonts[$name], $font->getSizes());
193
            }
194
        }
195
196
        // Sanitize and de-dup
197 5
        $fonts = Utils::dedupValues($fonts, SORT_REGULAR); // sorts values (sizes)
198
199
        // Sorts by font names alphabetically
200 5
        ksort($fonts);
201
202 5
        return $fonts;
203
    }
204
205
    /**
206
     * Looks for and parses the `family` query string value into a string
207
     * that Google Fonts expects (family, weights and subsets separated by
208
     * a semicolon).
209
     *
210
     * @param array $params
211
     *
212
     * @return array
213
     */
214 5
    protected function buildFontStringsFromQueryParams(array $params)
215 5
    {
216 5
        $fonts = [];
217
218 5
        foreach (explode('|', $params['family']) as $family) {
219 5
            $font = $this->parseFontStringName($family, $params);
220 5
            if (! empty($font)) {
221 5
                $fonts[] = $font;
222
            }
223
        }
224
225 5
        return $fonts;
226
    }
227
228
    /**
229
     * @param string $family
230
     * @param array $params
231
     *
232
     * @return string
233
     */
234 5
    protected function parseFontStringName($family, array $params)
235 5
    {
236 5
        $subset = false;
237 5
        $family = explode(':', $family);
238
239 5
        if (isset($params['subset'])) {
240
            // Use the found subset query parameter
241 4
            $subset = $params['subset'];
242 4
        } elseif (isset($family[2])) {
243
            // Use the subset in the family string if present
244 1
            $subset = $family[2];
245
        }
246
247
        // $family can have a lot of thing specified with separators etc.
248 5
        $parts = $this->validateFontStringParts($family, $subset);
249 5
        $font  = implode(':', $parts);
250
251 5
        return $font;
252
    }
253
254
    /**
255
     * Validate and return desired font name/size/subset parts.
256
     *
257
     * @param array $family
258
     * @param bool $subset
259
     *
260
     * @return array
261
     */
262 5
    protected function validateFontStringParts(array $family, $subset = false)
263 5
    {
264 5
        $parts = [];
265
266
        // First part is the font name, which should always be present
267 5
        $parts[] = $family[0];
268
269
        // Check if sizes are specified
270 5
        if (isset($family[1]) && strlen($family[1]) > 0) {
271 4
            $parts[] = $family[1];
272
        }
273
274
        // Add the subset if specified
275 5
        if ($subset) {
276 4
            $parts[] = $subset;
277
        }
278
279 5
        return $parts;
280
    }
281
}
282