HeadLink::generateMinifiedFilePath()   A
last analyzed

Complexity

Conditions 3
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 4
nc 2
nop 1
dl 0
loc 8
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Halfpastfour\HeadMinifier\View\Helper;
4
5
use MatthiasMullie\Minify;
6
7
/**
8
 * Class HeadLink
9
 *
10
 * @package Halfpastfour\HeadMinifier\View\Helper
11
 *
12
 * Proxies to container methods:
13
 * @method string|int getWhitespace(string | int $indent)
14
 * @method string|int getIndent()
15
 * @method string getSeparator()
16
 */
17
class HeadLink extends \Zend\View\Helper\HeadLink
18
{
19
    /**
20
     * @var array
21
     */
22
    private $options = [];
23
24
    /**
25
     * @var string
26
     */
27
    private $publicDir = '';
28
29
    /**
30
     * @var string
31
     */
32
    private $cacheDir = '';
33
34
    /**
35
     * @var string
36
     */
37
    private $baseUrl = '';
38
39
    /**
40
     * HeadLink constructor.
41
     *
42
     * @param array  $config
43
     * @param string $baseUrl
44
     */
45
    public function __construct(array $config, string $baseUrl)
46
    {
47
        $this->options   = $config;
48
        $this->publicDir = $this->options['directories']['public'];
49
        $this->cacheDir  = $this->options['directories']['cache'];
50
        $this->baseUrl   = $baseUrl;
51
52
        parent::__construct();
53
    }
54
55
    /**
56
     * @param string|int $indent
57
     *
58
     * @return string
59
     */
60
    public function toString($indent = null): string
61
    {
62
        // If configuration tells us minifying is not enabled, use the default view helper.
63
        if (! $this->options['enabled']) {
64
            return parent::toString($indent);
65
        }
66
67
        $cacheItems = [];
68
        // Process all items. The items that don't require any changes will be returned in $items. The items that will
69
        // be cached will be returned in $cacheItems.
70
        $items = $this->processItems($cacheItems);
71
72
        $indent = (null !== $indent)
73
            ? $this->getWhitespace($indent)
74
            : $this->getIndent();
75
76
        $identifier   = sha1(implode($cacheItems));
77
        $minifiedFile = "/{$identifier}.min.css";
78
79
        // Create a minified file containing all cache items. Return the name of the minified file as the last item in
80
        // returned in $items.
81
        $links = $this->minifyFile($minifiedFile, $cacheItems, $items)
82
            // Generate the links
83
                      ->generateLinks($items);
84
85
        return $indent . implode($this->escape($this->getSeparator()) . $indent, $links);
86
    }
87
88
    /**
89
     * @param array $cacheItems
90
     *
91
     * @return array
92
     */
93
    private function processItems(array &$cacheItems): array
94
    {
95
        $items = [];
96
        foreach ($this as $index => $item) {
97
            if (! $item->href || $item->type != 'text/css') {
98
                continue;
99
            }
100
            $localUri  = str_replace($this->baseUrl, '', preg_replace('/\?.*/', '', $this->publicDir . $item->href));
101
            $remoteUri = $item->href;
102
            $handle    = curl_init($remoteUri);
103
            curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
104
105
            if (is_file($localUri)) {
106
                $cacheItems[$index] = $localUri;
107
                continue;
108
            }
109
110
            if (curl_exec($handle) !== false) {
111
                $cacheItems[$index] = $remoteUri;
112
                continue;
113
            }
114
115
            $items[$index] = $item;
116
        }
117
118
        return $items;
119
    }
120
121
    /**
122
     * @param string $minifiedFileName
123
     *
124
     * @return string
125
     */
126
    private function generateMinifiedFilePath($minifiedFileName): string
127
    {
128
        $minifiedFilePath = $this->cacheDir . $minifiedFileName;
129
        if (strpos($minifiedFilePath, $this->publicDir) === 0) {
130
            $minifiedFilePath = substr($minifiedFilePath, strlen($this->publicDir)) ?: $minifiedFilePath;
131
        }
132
133
        return $this->baseUrl . $minifiedFilePath;
134
    }
135
136
    /**
137
     * @param string $minifiedFileName
138
     * @param array  $cacheItems
139
     * @param array  $items
140
     *
141
     * @return $this
142
     */
143
    private function minifyFile(string $minifiedFileName, array $cacheItems, array &$items): HeadLink
144
    {
145
        if (! empty($cacheItems)) {
146
            if (! is_file($this->cacheDir . $minifiedFileName)) {
147
                $minifier = new Minify\CSS();
148
                array_map(function ($uri) use ($minifier) {
149
                    $minifier->add($uri);
150
                }, $cacheItems);
151
                $minifier->minify($this->cacheDir . $minifiedFileName);
152
            }
153
154
            // Add the minified file tot the list of items.
155
            $items[] = $this->createData([
156
                'type'                  => 'text/css',
157
                'rel'                   => 'stylesheet',
158
                'href'                  => $this->generateMinifiedFilePath($minifiedFileName),
159
                'conditionalStylesheet' => false,
160
            ]);
161
        }
162
163
        return $this;
164
    }
165
166
    /**
167
     * @param array $items
168
     *
169
     * @return array
170
     */
171
    private function generateLinks(array $items): array
172
    {
173
        if (empty($items)) {
174
            return [];
175
        }
176
177
        $links = [];
178
        foreach ($items as $item) {
179
            $links[] = $this->itemToString($item);
180
        }
181
182
        return $links;
183
    }
184
}
185