Skip to content

Commit 1c5bce4

Browse files
committed
Add AssetExtension
1 parent c82a522 commit 1c5bce4

File tree

2 files changed

+145
-0
lines changed

2 files changed

+145
-0
lines changed

src/Extension/AssetExtension.php

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Devanych\View\Extension;
6+
7+
use RuntimeException;
8+
9+
use function file_exists;
10+
use function filemtime;
11+
use function ltrim;
12+
use function rtrim;
13+
use function sprintf;
14+
15+
final class AssetExtension implements ExtensionInterface
16+
{
17+
/**
18+
* @var string root directory storing the published asset files.
19+
*/
20+
private string $basePath;
21+
22+
/**
23+
* @var string base URL through which the published asset files can be accessed.
24+
*/
25+
private string $baseUrl;
26+
27+
/**
28+
* @var bool whether to append a timestamp to the URL of every published asset.
29+
*/
30+
private bool $appendTimestamp;
31+
32+
/**
33+
* @param string $basePath root directory storing the published asset files.
34+
* @param string $baseUrl base URL through which the published asset files can be accessed.
35+
* @param bool $appendTimestamp whether to append a timestamp to the URL of every published asset.
36+
*/
37+
public function __construct(string $basePath, string $baseUrl = '', bool $appendTimestamp = false)
38+
{
39+
$this->basePath = rtrim($basePath, '\/');
40+
$this->baseUrl = rtrim($baseUrl, '/');
41+
$this->appendTimestamp = $appendTimestamp;
42+
}
43+
44+
/**
45+
* {@inheritDoc}
46+
*/
47+
public function getFunctions(): array
48+
{
49+
return [
50+
'asset' => [$this, 'assetFile'],
51+
];
52+
}
53+
54+
/**
55+
* Includes the asset file and appends a timestamp with the last modification of that file.
56+
*
57+
* @param string $file
58+
* @return string
59+
*/
60+
public function assetFile(string $file): string
61+
{
62+
$url = $this->baseUrl . '/' . ltrim($file, '/');
63+
$path = $this->basePath . '/' . ltrim($file, '/');
64+
65+
if (!file_exists($path)) {
66+
throw new RuntimeException(sprintf(
67+
'Asset file "%s" does not exist.',
68+
$path
69+
));
70+
}
71+
72+
if ($this->appendTimestamp) {
73+
return $url . '?v=' . filemtime($path);
74+
}
75+
76+
return $url;
77+
}
78+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Devanych\Tests\View\Extension;
6+
7+
use Devanych\View\Extension\AssetExtension;
8+
use PHPUnit\Framework\TestCase;
9+
use RuntimeException;
10+
11+
use function filemtime;
12+
use function realpath;
13+
14+
class AssetExtensionTest extends TestCase
15+
{
16+
/**
17+
* @var string
18+
*/
19+
private string $baseUrl;
20+
21+
/**
22+
* @var string
23+
*/
24+
private string $basePath;
25+
26+
public function setUp(): void
27+
{
28+
$this->baseUrl = 'https://example.com/assets';
29+
$this->basePath = realpath(__DIR__ . '/../TestAsset/assets');
30+
}
31+
32+
public function testConstructorTrimsTrailingSlash(): void
33+
{
34+
$extension = new AssetExtension($this->basePath . '////', $this->baseUrl);
35+
$this->assertSame($this->baseUrl . '/style.css', $extension->assetFile('style.css'));
36+
37+
$extension = new AssetExtension($this->basePath . '\\\\', $this->baseUrl);
38+
$this->assertSame($this->baseUrl . '/style.css', $extension->assetFile('style.css'));
39+
40+
$extension = new AssetExtension($this->basePath . '\/\/', $this->baseUrl . '///');
41+
$this->assertSame($this->baseUrl . '/style.css', $extension->assetFile('style.css'));
42+
}
43+
44+
public function testAssetFileWithTrueAppendTimestampFlag(): void
45+
{
46+
$extension = $extension = new AssetExtension($this->basePath, $this->baseUrl, true);
47+
$expected = $this->baseUrl . '/style.css?v=' . filemtime($this->basePath . '/style.css');
48+
$this->assertSame($expected, $extension->assetFile('style.css'));
49+
}
50+
51+
public function testAssetFileTrimsLeadingSlash(): void
52+
{
53+
$extension = $extension = new AssetExtension($this->basePath, $this->baseUrl);
54+
$this->assertSame($this->baseUrl . '/style.css', $extension->assetFile('/style.css'));
55+
56+
$extension = $extension = new AssetExtension($this->basePath, $this->baseUrl, true);
57+
$expected = $this->baseUrl . '/style.css?v=' . filemtime($this->basePath . '/style.css');
58+
$this->assertSame($expected, $extension->assetFile('///style.css'));
59+
}
60+
61+
public function testAssetFileThrowRuntimeExceptionForNonExistAssetFile(): void
62+
{
63+
$extension = $extension = new AssetExtension($this->basePath, $this->baseUrl);
64+
$this->expectException(RuntimeException::class);
65+
$extension->assetFile('asset/file/not/exist');
66+
}
67+
}

0 commit comments

Comments
 (0)