Passed
Push — master ( f3387c...ea897f )
by Thijs
55s
created

ScssAssetConverter::shouldConvert()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 15
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 15
ccs 9
cts 9
cp 1
rs 9.2
c 0
b 0
f 0
cc 4
eloc 10
nc 4
nop 2
crap 4
1
<?php
2
3
namespace lucidtaz\yii2scssphp;
4
5
use Leafo\ScssPhp\Compiler;
6
use lucidtaz\yii2scssphp\storage\FsStorage;
7
use lucidtaz\yii2scssphp\storage\Storage;
8
use RuntimeException;
9
use Yii;
10
use yii\base\Component;
11
use yii\web\AssetConverterInterface;
12
13
class ScssAssetConverter extends Component implements AssetConverterInterface
14
{
15
    /**
16
     * @var Storage
17
     */
18
    public $storage;
19
20
    /**
21
     * @var boolean whether the source asset file should be converted even if
22
     * its result already exists. You may want to set this to be `true` during
23
     * the development stage to make sure the converted assets are always up-to-
24
     * date. Do not set this to true on production servers as it will
25
     * significantly degrade the performance.
26
     */
27
    public $forceConvert = false;
28
29
    /**
30
     * @var Compiler|mixed The mixed type hint is added to keep PHPStan happy,
31
     * since Yii was annotated to return "object" which confuses PHPStan.
32
     */
33
    private $compiler;
34
35 14
    public function init()
36
    {
37 14
        parent::init();
38 14
        if (!isset($this->storage)) {
39 1
            $this->storage = new FsStorage;
40
        }
41 14
        $this->compiler = Yii::createObject(Compiler::class);
42 14
    }
43
44
    /**
45
     * Converts a given SCSS asset file into a CSS file.
46
     * @param string $asset the asset file path, relative to $basePath
47
     * @param string $basePath the directory the $asset is relative to.
48
     * @return string the converted asset file path, relative to $basePath.
49
     */
50 13
    public function convert($asset, $basePath)
51
    {
52 13
        $extension = $this->getExtension($asset);
53 13
        if ($extension !== 'scss') {
54 2
            return $asset;
55
        }
56 11
        $cssAsset = $this->getCssAsset($asset, 'css');
57
58 11
        $inFile = "$basePath/$asset";
59 11
        $outFile = "$basePath/$cssAsset";
60
        
61 11
        $this->compiler->setImportPaths(dirname($inFile));
62
63 11
        if (!$this->storage->exists($inFile)) {
64 1
            Yii::error("Input file $inFile not found.", __METHOD__);
65 1
            return $asset;
66
        }
67
68 10
        $this->convertAndSaveIfNeeded($inFile, $outFile);
69
70 10
        return $cssAsset;
71
    }
72
73 13
    private function getExtension(string $filename): string
74
    {
75 13
        return pathinfo($filename, PATHINFO_EXTENSION);
76
    }
77
78
    /**
79
     * Get the relative path and filename of the asset
80
     * @param string $filename e.g. path/asset.css
81
     * @param string $newExtension e.g. scss
82
     * @return string e.g. path/asset.scss
83
     */
84 9
    protected function getCssAsset(string $filename, string $newExtension): string
85
    {
86 9
        $extensionlessFilename = pathinfo($filename, PATHINFO_FILENAME);
87 9
        $filenamePosition = strrpos($filename, $extensionlessFilename);
88 9
        $relativePath = substr($filename, 0, $filenamePosition);
89 9
        return "$relativePath$extensionlessFilename.$newExtension";
90
    }
91
92 10
    private function convertAndSaveIfNeeded(string $inFile, string $outFile)
93
    {
94 10
        if ($this->shouldConvert($inFile, $outFile)) {
95 9
            $css = $this->compiler->compile($this->storage->get($inFile), $inFile);
96 9
            $this->storage->put($outFile, $css);
97
        }
98 10
    }
99
100 10
    private function shouldConvert(string $inFile, string $outFile): bool
101
    {
102 10
        if (!$this->storage->exists($outFile)) {
103 6
            return true;
104
        }
105 4
        if ($this->forceConvert) {
106 1
            return true;
107
        }
108
        try {
109 3
            return $this->isOlder($outFile, $inFile);
110 1
        } catch (RuntimeException $e) {
111 1
            Yii::warning('Encountered RuntimeException message "' . $e->getMessage() . '", going to convert.', __METHOD__);
112 1
            return true;
113
        }
114
    }
115
116 3
    private function isOlder(string $fileA, string $fileB): bool
117
    {
118 3
        return $this->storage->getMtime($fileA) < $this->storage->getMtime($fileB);
119
    }
120
}
121