AssetManager::applyCss()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 6
nc 3
nop 0
dl 0
loc 10
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace WebComplete\mvc\assets;
4
5
use Symfony\Component\Filesystem\Filesystem;
6
use WebComplete\mvc\exception\Exception;
7
8
class AssetManager
9
{
10
11
    const PRODUCTION_JS = 'asset.min.js';
12
    const PRODUCTION_CSS = 'asset.min.css';
13
14
    /**
15
     * @var AbstractAsset[]
16
     */
17
    protected $assets = [];
18
    /**
19
     * @var string
20
     */
21
    protected $webRoot;
22
    /**
23
     * @var string
24
     */
25
    protected $assetDirName;
26
    /**
27
     * @var Filesystem
28
     */
29
    protected $filesystem;
30
    protected $isProduction = false;
31
32
    /**
33
     * @param Filesystem $filesystem
34
     * @param string $webRoot
35
     * @param string $assetDirName
36
     * @param bool $isProduction
37
     */
38
    public function __construct(
39
        Filesystem $filesystem,
40
        string $webRoot,
41
        string $assetDirName,
42
        bool $isProduction = false
43
    ) {
44
        $this->filesystem = $filesystem;
45
        $this->webRoot = \rtrim($webRoot, '/');
46
        $this->assetDirName = $assetDirName;
47
        $this->isProduction = $isProduction;
48
    }
49
50
    /**
51
     * @param AbstractAsset $asset
52
     *
53
     * @throws \Symfony\Component\Filesystem\Exception\IOException
54
     */
55
    public function registerAsset(AbstractAsset $asset)
56
    {
57
        $assetClass = \get_class($asset);
58
        if (!isset($this->assets[$assetClass])) {
59
            foreach ($asset->getAssetsBefore() as $assetBefore) {
60
                $this->registerAsset($assetBefore);
61
            }
62
63
            if ($asset->publish) {
64
                $this->publishAsset($asset);
65
            }
66
            $this->assets[$assetClass] = $asset;
67
            foreach ($asset->getAssetsAfter() as $assetAfter) {
68
                $this->registerAsset($assetAfter);
69
            }
70
        }
71
    }
72
73
    /**
74
     * @param string $assetClass
75
     * @param $file
76
     *
77
     * @param bool $absolute
78
     *
79
     * @return string
80
     * @throws Exception
81
     */
82
    public function getPath(string $assetClass, $file, bool $absolute = false): string
83
    {
84
        if (!isset($this->assets[$assetClass])) {
85
            throw new Exception('Asset ' . $assetClass . ' is not registered');
86
        }
87
88
        return $absolute
89
            ? $this->webRoot . $this->getWebDir($this->assets[$assetClass]) . \ltrim($file, '/')
90
            : $this->getWebDir($this->assets[$assetClass]) . \ltrim($file, '/');
91
    }
92
93
    /**
94
     * @return string
95
     */
96
    public function applyCss(): string
97
    {
98
        $result = [];
99
        foreach ($this->assets as $asset) {
100
            $links = $this->getLinks($asset, $asset->css());
101
            foreach ($links as $link) {
102
                $result[] = '<link rel="stylesheet" href="' . $link . '">';
103
            }
104
        }
105
        return \implode('', $result);
106
    }
107
108
    /**
109
     * @return string
110
     */
111
    public function applyJs(): string
112
    {
113
        $result = [];
114
        foreach ($this->assets as $asset) {
115
            $productionJs = $this->getWebDir($asset) . self::PRODUCTION_JS;
116
            $productionJsFile = $this->webRoot . $productionJs;
117
            if ($this->isProduction() && \file_exists($productionJsFile)) {
118
                $links = $this->getLinks($asset, $asset->externalJs());
119
                $links[] = $productionJs . '?' . \filemtime($productionJsFile);
120
            } else {
121
                $links = $this->getLinks($asset, $asset->js());
122
            }
123
            foreach ($links as $link) {
124
                $result[] = '<script src="' . $link . '"></script>';
125
            }
126
        }
127
        return \implode('', $result);
128
    }
129
130
    /**
131
     * @return bool
132
     */
133
    public function isProduction(): bool
134
    {
135
        return $this->isProduction;
136
    }
137
138
    /**
139
     * @param bool $isProduction
140
     */
141
    public function setIsProduction(bool $isProduction)
142
    {
143
        $this->isProduction = $isProduction;
144
    }
145
146
    /**
147
     * @param AbstractAsset $asset
148
     *
149
     * @throws \Symfony\Component\Filesystem\Exception\IOException
150
     */
151
    protected function publishAsset(AbstractAsset $asset)
152
    {
153
        $hash = $asset->getHash();
154
        $dir = $this->webRoot . '/' . $this->assetDirName . '/' . $hash;
155
        if ($asset->useLinks) {
156
            if (!$this->filesystem->exists($dir)) {
157
                $this->filesystem->symlink($asset->getBasePath(), $dir, true);
158
            }
159
        } else {
160
            if ($this->filesystem->exists($dir)) {
161
                $this->filesystem->remove($dir);
162
            }
163
            $this->filesystem->mirror($asset->getBasePath(), $dir);
164
            $this->filesystem->chmod($dir, 0755, 000, true);
165
        }
166
    }
167
168
    /**
169
     * @param AbstractAsset $asset
170
     *
171
     * @return string
172
     */
173
    private function getWebDir(AbstractAsset $asset): string
174
    {
175
        return $asset->publish
176
            ? '/' . $this->assetDirName . '/' . $asset->getHash() . '/'
177
            : '/';
178
    }
179
180
    /**
181
     * @param AbstractAsset $asset
182
     * @param array $files
183
     *
184
     * @return array
185
     */
186
    private function getLinks(AbstractAsset $asset, array $files): array
187
    {
188
        $result = [];
189
        $dir = $this->getWebDir($asset);
190
        foreach ($files as $file) {
191
            $result[] = $this->getLink($file, $dir);
192
        }
193
        return $result;
194
    }
195
196
    /**
197
     * @param $file
198
     * @param $dir
199
     *
200
     * @return string
201
     */
202
    private function getLink($file, $dir): string
203
    {
204
        $link = $file;
205
        if (false === \strpos($file, 'http') && false === \strpos($file, '//')) {
206
            $filePath = $dir . \ltrim($file, '/');
207
            $timestamp = \filemtime($this->webRoot . $filePath);
208
            $link = $filePath . '?' . $timestamp;
209
        }
210
211
        return $link;
212
    }
213
}
214