Passed
Pull Request — master (#4)
by halfpastfour
03:26
created

HeadScript::isUseCdata()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

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