-
Notifications
You must be signed in to change notification settings - Fork 611
/
AssetManager.php
175 lines (150 loc) · 5.09 KB
/
AssetManager.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
<?php
/**
* @link https://craftcms.com/
* @copyright Copyright (c) Pixel & Tonic, Inc.
* @license https://craftcms.github.io/license/
*/
namespace craft\web;
use Craft;
use craft\db\Table;
use craft\errors\DbConnectException;
use craft\helpers\App;
use craft\helpers\Db;
use craft\helpers\FileHelper;
use craft\helpers\UrlHelper;
use yii\caching\TagDependency;
use yii\db\Exception as DbException;
/**
* @inheritdoc
* @author Pixel & Tonic, Inc. <support@pixelandtonic.com>
* @since 3.0.0
*/
class AssetManager extends \yii\web\AssetManager
{
/**
* @var bool Whether asset source paths should be cached for subsequent requests.
* @see hash()
* @since 4.5.10
*/
public bool $cacheSourcePaths = true;
private const CACHE_TAG = 'assetmanager';
/**
* @inheritdoc
*/
public function publish($path, $options = []): array
{
if (App::isEphemeral()) {
return [$path, $this->getPublishedUrl($path)];
}
return parent::publish($path, $options);
}
/**
* Returns the URL of a published file/directory path.
*
* @param string $path directory or file path being published
* @param bool $publish whether the directory or file should be published, if not already
* @param string|null $filePath A file path, relative to $sourcePath if $sourcePath is a directory, that should be appended to the returned URL.
* @return string|false the published URL for the file or directory, or false if $publish is false and the file or directory does not exist
*/
public function getPublishedUrl($path, bool $publish = false, ?string $filePath = null): string|false
{
if ($publish === true && !App::isEphemeral()) {
[, $url] = $this->publish($path);
} else {
$url = parent::getPublishedUrl($path);
}
if ($filePath !== null) {
$url .= '/' . $filePath;
// Should we append a timestamp?
if ($this->appendTimestamp) {
$fullPath = FileHelper::normalizePath(Craft::getAlias($path) . DIRECTORY_SEPARATOR . $filePath);
if (($timestamp = @filemtime($fullPath)) > 0) {
$url .= '?v=' . $timestamp;
}
}
$url = $this->_addBuildIdParam($url);
}
return $url;
}
/**
* @inheritdoc
*/
protected function hash($path): string
{
if (is_callable($this->hashCallback)) {
return call_user_func($this->hashCallback, $path);
}
$dir = is_file($path) ? dirname($path) : $path;
$alias = Craft::alias($dir);
$hash = sprintf('%x', crc32($alias . '|' . FileHelper::lastModifiedTime($path) . '|' . $this->linkAssets));
if ($this->cacheSourcePaths) {
// Store the hash for later
Craft::$app->onAfterRequest(function() use ($hash, $alias) {
try {
Db::upsert(Table::RESOURCEPATHS, [
'hash' => $hash,
'path' => $alias,
]);
} catch (DbException|DbConnectException) {
// Craft is either not installed or not updated to 3.0.3+ yet,
// so cache the source path instead
Craft::$app->getCache()->set(
$this->getCacheKeyForPathHash($hash),
$alias,
dependency: new TagDependency(['tags' => [self::CACHE_TAG]]),
);
}
});
}
return $hash;
}
/**
* Get the cache key for a given asset hash
*
* @param string $hash
* @return string
*/
public function getCacheKeyForPathHash(string $hash): string
{
return implode(':', [self::CACHE_TAG, $hash]);
}
/**
* @inheritdoc
*/
protected function publishDirectory($src, $options): array
{
[$dir, $url] = parent::publishDirectory($src, $options);
// A backslash can cause issues on Windows here.
$url = str_replace('\\', '/', $url);
return [$dir, $url];
}
/**
* @inheritdoc
*/
protected function publishFile($src): array
{
[$file, $url] = parent::publishFile($src);
// A backslash can cause issues on Windows here.
$url = str_replace('\\', '/', $url);
if ($this->appendTimestamp && !str_contains($url, '?') && ($timestamp = @filemtime($src)) > 0) {
$url .= '?v=' . $timestamp;
}
return [$file, $this->_addBuildIdParam($url)];
}
public function getAssetUrl($bundle, $asset, $appendTimestamp = null): string
{
return $this->_addBuildIdParam(
parent::getAssetUrl($bundle, $asset, $appendTimestamp),
);
}
private function _addBuildIdParam($url): string
{
$generalConfig = Craft::$app->getConfig()->getGeneral();
if ($generalConfig->buildId) {
return UrlHelper::urlWithParams($url, [
'buildId' => $generalConfig->buildId,
]);
}
return $url;
}
}