Completed
Push — master ( bd4416...d1266d )
by Eugene
29s
created

Processor::compileLESS()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 8
rs 9.4285
cc 2
eloc 5
nc 2
nop 1
1
<?php
2
3
namespace EM\CssCompiler\Processor;
4
5
use Composer\IO\IOInterface;
6
use EM\CssCompiler\Container\FileContainer;
7
use EM\CssCompiler\Exception\CompilerException;
8
use EM\CssCompiler\Exception\FileException;
9
use Leafo\ScssPhp\Compiler as SASSCompiler;
10
use Leafo\ScssPhp\Exception\ParserException;
11
use lessc as LESSCompiler;
12
use scss_compass as CompassCompiler;
13
14
/**
15
 * @see   ProcessorTest
16
 *
17
 * @since 0.1
18
 */
19
class Processor
20
{
21
    const FORMATTER_COMPRESSED = 'compressed';
22
    const FORMATTER_CRUNCHED   = 'crunched';
23
    const FORMATTER_EXPANDED   = 'expanded';
24
    const FORMATTER_NESTED     = 'nested';
25
    const FORMATTER_COMPACT    = 'compact';
26
    public static $supportedFormatters = [
27
        self::FORMATTER_COMPRESSED,
28
        self::FORMATTER_CRUNCHED,
29
        self::FORMATTER_EXPANDED,
30
        self::FORMATTER_NESTED,
31
        self::FORMATTER_COMPACT
32
    ];
33
    /**
34
     * @var IOInterface
35
     */
36
    private $io;
37
    /**
38
     * @var FileContainer[]
39
     */
40
    private $files = [];
41
    /**
42
     * @var SASSCompiler
43
     */
44
    private $sass;
45
    /**
46
     * @var LESSCompiler
47
     */
48
    private $less;
49
50
    public function __construct(IOInterface $io)
51
    {
52
        $this->io = $io;
53
        $this->initCompilers();
54
    }
55
56
    protected function initCompilers()
57
    {
58
        $this->less = new LESSCompiler();
59
        $this->sass = new SASSCompiler();
60
        /** attaches compass functionality to the SASS compiler */
61
        new CompassCompiler($this->sass);
62
    }
63
64
    /**
65
     * @param string $inputPath
66
     * @param string $outputPath
67
     *
68
     * @throws \Exception
69
     */
70
    public function attachFiles($inputPath, $outputPath)
71
    {
72
        if (is_dir($inputPath)) {
73
            $files = scandir($inputPath);
74
            unset($files[0], $files[1]);
75
76
            foreach ($files as $file) {
77
                $this->attachFiles("$inputPath/$file", $outputPath);
78
            }
79
        } else if (is_file($inputPath)) {
80
            $this->files[] = new FileContainer($inputPath, $outputPath);
81
        } else {
82
            throw new \Exception("file doesn't exists");
83
        }
84
    }
85
86
    /**
87
     * @return FileContainer[]
88
     */
89
    public function getFiles()
90
    {
91
        return $this->files;
92
    }
93
94
    /**
95
     * @return string[]
96
     */
97
    protected function concatOutput()
98
    {
99
        $outputMap = [];
100
        foreach ($this->files as $file) {
101
            if (!isset($outputMap[$file->getOutputPath()])) {
102
                $outputMap[$file->getOutputPath()] = '';
103
            }
104
105
            $outputMap[$file->getOutputPath()] .= $file->getOutputContent();
106
        }
107
108
        return $outputMap;
109
    }
110
111
    /**
112
     * save output into file
113
     */
114
    public function saveOutput()
115
    {
116
        foreach ($this->concatOutput() as $path => $content) {
117
            $directory = dirname($path);
118
            if (!is_dir($directory)) {
119
                $this->io->write("<info>creating directory</info>: {$directory}");
120
                mkdir($directory, 0755, true);
121
            }
122
123
            $this->io->write("<info>save output into</info>: {$path}");
124
            file_put_contents($path, $content);
125
        }
126
    }
127
128
    /**
129
     * @param string $formatter
130
     *
131
     * @throws CompilerException
132
     */
133
    public function processFiles($formatter)
134
    {
135
        $this->sass->setFormatter($this->getFormatterClass($formatter));
136
        $this->io->write("<info>use '{$formatter}' formatting</info>");
137
138
        foreach ($this->files as $file) {
139
            $this->io->write("<info>processing</info>: {$file->getInputPath()}");
140
            $this->fetchInputContextIntoFile($file);
141
142
            try {
143
                $this->processFile($file);
144
            } catch (CompilerException $e) {
145
                $this->io->writeError("<error>failed to process: {$file->getOutputPath()}</error>");
146
            }
147
        }
148
    }
149
150
    /**
151
     * @param FileContainer $file
152
     *
153
     * @return FileContainer
154
     * @throws CompilerException
155
     */
156
    public function processFile(FileContainer $file)
157
    {
158
        switch ($file->getType()) {
159
            case FileContainer::TYPE_SCSS:
160
                return $this->compileSCSS($file);
161
            case FileContainer::TYPE_LESS:
162
                return $this->compileLESS($file);
163
        }
164
165
        throw new CompilerException('unknown compiler');
166
    }
167
168
    /**
169
     * @param FileContainer $file
170
     *
171
     * @return $this
172
     * @throws CompilerException
173
     */
174
    protected function compileSCSS(FileContainer $file)
175
    {
176
        try {
177
            $this->sass->addImportPath(dirname($file->getInputPath()));
178
            $content = $this->sass->compile($file->getInputContent());
179
180
            return $file->setOutputContent($content);
181
        } catch (ParserException $e) {
182
            throw new CompilerException($e->getMessage(), 1, $e);
183
        }
184
    }
185
186
    /**
187
     * @param FileContainer $file
188
     *
189
     * @return $this
190
     * @throws CompilerException
191
     */
192
    protected function compileLESS(FileContainer $file)
193
    {
194
        try {
195
            return $file->setOutputContent($this->less->compileFile($file->getInputPath()));
196
        } catch (\Exception $e) {
197
            throw new CompilerException($e->getMessage(), 1, $e);
198
        }
199
    }
200
201
    /**
202
     * @param string $formatter
203
     *
204
     * @return string
205
     */
206
    protected function getFormatterClass($formatter)
207
    {
208
        if (!in_array($formatter, static::$supportedFormatters)) {
209
            throw new \InvalidArgumentException('unknown formatter, available options are: ' . print_r(static::$supportedFormatters, true));
210
        }
211
212
        return 'Leafo\\ScssPhp\\Formatter\\' . ucfirst($formatter);
213
    }
214
215
    /**
216
     * @param FileContainer $file
217
     *
218
     * @throws FileException
219
     */
220
    protected function fetchInputContextIntoFile(FileContainer $file)
221
    {
222
        if (!file_exists($file->getInputPath())) {
223
            throw new FileException("file: {$file->getInputPath()} doesn't exists");
224
        }
225
226
        $file->setInputContent(file_get_contents($file->getInputPath()));
227
    }
228
}
229