Completed
Pull Request — master (#12)
by Albert
02:29
created

ScssAssetConverter::createDistFolderIfNotExists()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 7
ccs 5
cts 5
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 4
nc 2
nop 1
crap 2
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\helpers\FileHelper;
12
use yii\web\AssetConverterInterface;
13
14
class ScssAssetConverter extends Component implements AssetConverterInterface
15
{
16
    /**
17
     * @var Storage
18
     */
19
    public $storage;
20
21
    /**
22
     * @var boolean whether the source asset file should be converted even if
23
     * its result already exists. You may want to set this to be `true` during
24
     * the development stage to make sure the converted assets are always up-to-
25
     * date. Do not set this to true on production servers as it will
26
     * significantly degrade the performance.
27
     */
28
    public $forceConvert = false;
29
30
    private $compiler;
31
32
    /**
33
     * Set the destination folder where to copy the compiled css file.
34
     * If the value is null, then it will be generated into the sourcePath of the asset bundle.
35
     *
36
     * ```
37
     * 'assetManager' => [
38
     *     'converter' => [
39
     *         'class' => \lucidtaz\yii2scssphp\ScssAssetConverter::class,
40
     *         'distFolder' => 'css',
41
     *     ],
42
     * ],
43
     * ```
44
     *
45
     * @var string|null
46
     */
47
    public $distFolder;
48
49
    /**
50
     * @throws \yii\base\InvalidConfigException
51
     */
52 11
    public function init()
53
    {
54 11
        parent::init();
55 11
        if (!isset($this->storage)) {
56 1
            $this->storage = new FsStorage;
57
        }
58 11
        $this->compiler = Yii::createObject(Compiler::class);
59 11
    }
60
61
    /**
62
     * Converts a given SCSS asset file into a CSS file.
63
     * @param string $asset the asset file path, relative to $basePath
64
     * @param string $basePath the directory the $asset is relative to.
65
     * @return string the converted asset file path, relative to $basePath.
66
     * @throws \yii\base\Exception
67
     */
68 10
    public function convert($asset, $basePath)
69
    {
70 10
        $extension = $this->getExtension($asset);
71 10
        if ($extension !== 'scss') {
72 2
            return $asset;
73
        }
74 8
        $cssAsset = $this->replaceExtension($asset, 'css');
75
76 8
        $inFile = "$basePath/$asset";
77 8
        $outFile = $this->distFolder ? "$basePath/$this->distFolder/$cssAsset" : "$basePath/$cssAsset";
78
        
79 8
        $this->compiler->setImportPaths(dirname($inFile));
80
81 8
        if (!$this->storage->exists($inFile)) {
82 1
            Yii::error("Input file $inFile not found.", __METHOD__);
83 1
            return $asset;
84
        }
85
86 7
        $this->createDistFolderIfNotExists($outFile);
87 7
        $this->convertAndSaveIfNeeded($inFile, $outFile);
88
89 7
        return $this->distFolder ? $this->distFolder . '/' . $cssAsset : $cssAsset;
90
    }
91
92 10
    private function getExtension(string $filename): string
93
    {
94 10
        return pathinfo($filename, PATHINFO_EXTENSION);
95
    }
96
97 8
    private function replaceExtension(string $filename, string $newExtension): string
98
    {
99 8
        $extensionlessFilename = pathinfo($filename, PATHINFO_FILENAME);
100 8
        return "$extensionlessFilename.$newExtension";
101
    }
102
103 7
    private function convertAndSaveIfNeeded(string $inFile, string $outFile)
104
    {
105 7
        if ($this->shouldConvert($inFile, $outFile)) {
106 6
            $css = $this->compiler->compile($this->storage->get($inFile), $inFile);
107 6
            $this->storage->put($outFile, $css);
108
        }
109 7
    }
110
111 7
    private function shouldConvert(string $inFile, string $outFile): bool
112
    {
113 7
        if (!$this->storage->exists($outFile)) {
114 3
            return true;
115
        }
116 4
        if ($this->forceConvert) {
117 1
            return true;
118
        }
119
        try {
120 3
            return $this->isOlder($outFile, $inFile);
121 1
        } catch (RuntimeException $e) {
122 1
            Yii::warning('Encountered RuntimeException message "' . $e->getMessage() . '", going to convert.', __METHOD__);
123 1
            return true;
124
        }
125
    }
126
127 3
    private function isOlder(string $fileA, string $fileB): bool
128
    {
129 3
        return $this->storage->getMtime($fileA) < $this->storage->getMtime($fileB);
130
    }
131
132
    /**
133
     * @param string $outFile
134
     * @throws \yii\base\Exception
135
     */
136 7
    private function createDistFolderIfNotExists($outFile)
137
    {
138 7
        $dir = dirname($outFile);
139 7
        if (!is_dir($dir)) {
140 1
            FileHelper::createDirectory($dir);
141
        }
142 7
    }
143
}
144