Passed
Push — master ( 99159c...091505 )
by zyt
05:08
created

GoogleFontsCollection::addFontFromString()   B

Complexity

Conditions 3
Paths 3

Size

Total Lines 27
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 3.004

Importance

Changes 0
Metric Value
cc 3
eloc 12
nc 3
nop 2
dl 0
loc 27
ccs 12
cts 13
cp 0.9231
crap 3.004
rs 8.8571
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, append to that.
80
            // Existing subsetsMap[$name] might not be an array
81 1
            if (! is_array($this->subsetsMap[$name])) {
82
                $this->subsetsMap[$name] = (array) $this->subsetsMap[$name];
83
            }
84 1
            $this->subsetsMap[$name] = array_merge($this->subsetsMap[$name], (array) $subsets);
85
        }
86
87
        // Deduplicate values and don't sort the subsets map
88 5
        $this->subsetsMap = Utils::dedupValues($this->subsetsMap, false); // no sort
89
90
        // Maintain the list/hash of name => sizes when adding a new one too
91 5
        $this->namedSizes = $this->buildNamedsizesMap();
92 5
    }
93
94
    /**
95
     * @return array
96
     */
97 2
    protected function getSubsetsMap()
98 2
    {
99 2
        return $this->subsetsMap;
100
    }
101
102 3
    protected function addTextFont($name, $url)
103 3
    {
104 3
        $this->texts['name'][] = $name;
105 3
        $this->texts['url'][]  = $url;
106 3
    }
107
108 5
    protected function addComplete($fontstring)
109 5
    {
110 5
        $this->complete[] = $fontstring;
111 5
    }
112
113 5
    protected function addLink($url)
114 5
    {
115 5
        $this->links[] = $url;
116 5
    }
117
118 4
    public function getOriginalLinks()
119 4
    {
120 4
        return $this->links;
121
    }
122
123 5
    public function hasText()
124 5
    {
125 5
        return (! empty($this->texts));
126
    }
127
128
    /**
129
     * @return array
130
     */
131 4
    public function getTextUrls()
132 4
    {
133 4
        $urls = [];
134
135 4
        if ($this->hasText()) {
136 3
            $urls = $this->texts['url'];
137
        }
138
139 4
        return $urls;
140
    }
141
142
    /**
143
     * @return array
144
     */
145 1
    public function getTextNames()
146 1
    {
147 1
        return $this->texts['name'];
148
    }
149
150 5
    public function getFonts()
151 5
    {
152 5
        return $this->fonts['complete'];
153
    }
154
155
    public function getFontsText()
156
    {
157
        return $this->fonts['text'];
158
    }
159
160 3
    public function getCombinedUrl()
161 3
    {
162 3
        return Utils::buildGoogleFontsUrl($this->getNamedSizesMap(), $this->getSubsets());
163
    }
164
165 5
    public function getNamedSizesMap()
166 5
    {
167 5
        return $this->namedSizes;
168
    }
169
170 3
    public function getSubsets()
171 3
    {
172 3
        $subsets = [];
173
174 3
        $fonts = $this->getFonts();
175 3
        foreach ($fonts as $font) {
176 3
            $subsets[] = $font->getSubsets();
177
        }
178
179 3
        $subsets = Utils::arrayFlattenIterative($subsets);
180
181 3
        return array_unique($subsets);
182
    }
183
184
    /**
185
     * @return array
186
     */
187 5
    protected function buildNamedsizesMap()
188 5
    {
189 5
        $fonts = [];
190
191 5
        foreach ($this->getFonts() as $font) {
192 5
            $name = $font->getName();
193 5
            if (! array_key_exists($name, $fonts)) {
194 5
                $fonts[$name] = $font->getSizes();
195
            } else {
196 5
                $fonts[$name] = array_merge($fonts[$name], $font->getSizes());
197
            }
198
        }
199
200
        // Sanitize and de-dup
201 5
        $fonts = Utils::dedupValues($fonts, SORT_REGULAR); // sorts values (sizes)
202
203
        // Sorts by font names alphabetically
204 5
        ksort($fonts);
205
206 5
        return $fonts;
207
    }
208
209
    /**
210
     * Looks for and parses the `family` query string value into a string
211
     * that Google Fonts expects (family, weights and subsets separated by
212
     * a semicolon).
213
     *
214
     * @param array $params
215
     *
216
     * @return array
217
     */
218 5
    protected function buildFontStringsFromQueryParams(array $params)
219 5
    {
220 5
        $fonts = [];
221
222 5
        foreach (explode('|', $params['family']) as $family) {
223 5
            $font = $this->parseFontStringName($family, $params);
224 5
            if (! empty($font)) {
225 5
                $fonts[] = $font;
226
            }
227
        }
228
229 5
        return $fonts;
230
    }
231
232
    /**
233
     * @param string $family
234
     * @param array $params
235
     *
236
     * @return string
237
     */
238 5
    protected function parseFontStringName($family, array $params)
239 5
    {
240 5
        $subset = false;
241 5
        $family = explode(':', $family);
242
243 5
        if (isset($params['subset'])) {
244
            // Use the found subset query parameter
245 4
            $subset = $params['subset'];
246 4
        } elseif (isset($family[2])) {
247
            // Use the subset in the family string if present
248 1
            $subset = $family[2];
249
        }
250
251
        // $family can have a lot of thing specified with separators etc.
252 5
        $parts = $this->validateFontStringParts($family, $subset);
253 5
        $font  = implode(':', $parts);
254
255 5
        return $font;
256
    }
257
258
    /**
259
     * Validate and return desired font name/size/subset parts.
260
     *
261
     * @param array $family
262
     * @param bool $subset
263
     *
264
     * @return array
265
     */
266 5
    protected function validateFontStringParts(array $family, $subset = false)
267 5
    {
268 5
        $parts = [];
269
270
        // First part is the font name, which should always be present
271 5
        $parts[] = $family[0];
272
273
        // Check if sizes are specified
274 5
        if (isset($family[1]) && strlen($family[1]) > 0) {
275 4
            $parts[] = $family[1];
276
        }
277
278
        // Add the subset if specified
279 5
        if ($subset) {
280 4
            $parts[] = $subset;
281
        }
282
283 5
        return $parts;
284
    }
285
}
286