Passed
Pull Request — master (#15)
by Thijs
01:48
created

ScssAssetConverter::convert()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 22
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 22
ccs 13
cts 13
cp 1
rs 9.2
c 0
b 0
f 0
cc 3
eloc 13
nc 3
nop 2
crap 3
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
31
     */
32
    private $compiler;
33
34 14
    public function init()
35
    {
36 14
        parent::init();
37 14
        if (!isset($this->storage)) {
38 1
            $this->storage = new FsStorage;
39
        }
40 14
        $this->compiler = Yii::createObject(Compiler::class);
41 14
    }
42
43
    /**
44
     * Converts a given SCSS asset file into a CSS file.
45
     * @param string $asset the asset file path, relative to $basePath
46
     * @param string $basePath the directory the $asset is relative to.
47
     * @return string the converted asset file path, relative to $basePath.
48
     */
49 13
    public function convert($asset, $basePath)
50
    {
51 13
        $extension = $this->getExtension($asset);
52 13
        if ($extension !== 'scss') {
53 2
            return $asset;
54
        }
55 11
        $cssAsset = $this->getCssAsset($asset, 'css');
56
57 11
        $inFile = "$basePath/$asset";
58 11
        $outFile = "$basePath/$cssAsset";
59
        
60 11
        $this->compiler->setImportPaths(dirname($inFile));
61
62 11
        if (!$this->storage->exists($inFile)) {
63 1
            Yii::error("Input file $inFile not found.", __METHOD__);
64 1
            return $asset;
65
        }
66
67 10
        $this->convertAndSaveIfNeeded($inFile, $outFile);
68
69 10
        return $cssAsset;
70
    }
71
72 13
    private function getExtension(string $filename): string
73
    {
74 13
        return pathinfo($filename, PATHINFO_EXTENSION);
75
    }
76
77
    /**
78
     * Get the relative path and filename of the asset
79
     * @param string $filename e.g. path/asset.css
80
     * @param string $newExtension e.g. scss
81
     * @return string e.g. path/asset.scss
82
     */
83 9
    protected function getCssAsset(string $filename, string $newExtension): string
84
    {
85 9
        $extensionlessFilename = pathinfo($filename, PATHINFO_FILENAME);
86 9
        $filenamePosition = strrpos($filename, $extensionlessFilename);
87 9
        $relativePath = substr($filename, 0, $filenamePosition);
88 9
        return "$relativePath$extensionlessFilename.$newExtension";
89
    }
90
91 10
    private function convertAndSaveIfNeeded(string $inFile, string $outFile)
92
    {
93 10
        if ($this->shouldConvert($inFile, $outFile)) {
94 9
            $css = $this->compiler->compile($this->storage->get($inFile), $inFile);
95 9
            $this->storage->put($outFile, $css);
96
        }
97 10
    }
98
99 10
    private function shouldConvert(string $inFile, string $outFile): bool
100
    {
101 10
        if (!$this->storage->exists($outFile)) {
102 6
            return true;
103
        }
104 4
        if ($this->forceConvert) {
105 1
            return true;
106
        }
107
        try {
108 3
            return $this->isOlder($outFile, $inFile);
109 1
        } catch (RuntimeException $e) {
110 1
            Yii::warning('Encountered RuntimeException message "' . $e->getMessage() . '", going to convert.', __METHOD__);
111 1
            return true;
112
        }
113
    }
114
115 3
    private function isOlder(string $fileA, string $fileB): bool
116
    {
117 3
        return $this->storage->getMtime($fileA) < $this->storage->getMtime($fileB);
118
    }
119
}
120