Completed
Push — master ( 63021f...d31a75 )
by Eugene
27s
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 SCSSCompiler;
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 SCSSCompiler
43
     */
44
    private $scss;
45
    /**
46
     * @var LESSCompiler
47
     */
48
    private $less;
49
50
    public function __construct(IOInterface $io)
51
    {
52
        $this->io = $io;
53
        $this->less = new LESSCompiler();
54
        $this->scss = new SCSSCompiler();
55
        /** attaches compass functionality to the SCSS compiler */
56
        new CompassCompiler($this->scss);
57
    }
58
59
    /**
60
     * @param string $inputPath
61
     * @param string $outputPath
62
     *
63
     * @throws \Exception
64
     */
65
    public function attachFiles($inputPath, $outputPath)
66
    {
67
        if (is_dir($inputPath)) {
68
            $files = scandir($inputPath);
69
            unset($files[0], $files[1]);
70
71
            foreach ($files as $file) {
72
                $this->attachFiles("$inputPath/$file", $outputPath);
73
            }
74
        } else if (is_file($inputPath)) {
75
            $this->files[] = new FileContainer($inputPath, $outputPath);
76
        } else {
77
            throw new \Exception("file doesn't exists");
78
        }
79
    }
80
81
    /**
82
     * @return FileContainer[]
83
     */
84
    public function getFiles()
85
    {
86
        return $this->files;
87
    }
88
89
    /**
90
     * @return string[]
91
     */
92
    protected function concatOutput()
93
    {
94
        $outputMap = [];
95
        foreach ($this->files as $file) {
96
            if (!isset($outputMap[$file->getOutputPath()])) {
97
                $outputMap[$file->getOutputPath()] = '';
98
            }
99
100
            $outputMap[$file->getOutputPath()] .= $file->getOutputContent();
101
        }
102
103
        return $outputMap;
104
    }
105
106
    /**
107
     * save output into file
108
     */
109
    public function saveOutput()
110
    {
111
        foreach ($this->concatOutput() as $path => $content) {
112
            $directory = dirname($path);
113
            if (!is_dir($directory)) {
114
                $this->io->write("<info>creating directory</info>: {$directory}");
115
                mkdir($directory, 0755, true);
116
            }
117
118
            $this->io->write("<info>save output into</info>: {$path}");
119
            file_put_contents($path, $content);
120
        }
121
    }
122
123
    /**
124
     * @param string $formatter
125
     *
126
     * @throws CompilerException
127
     */
128
    public function processFiles($formatter)
129
    {
130
        $this->scss->setFormatter($this->getFormatterClass($formatter));
131
        $this->io->write("<info>use '{$formatter}' formatting</info>");
132
133
        foreach ($this->files as $file) {
134
            $this->io->write("<info>processing</info>: {$file->getInputPath()}");
135
            $this->fetchInputContextIntoFile($file);
136
137
            try {
138
                $this->processFile($file);
139
            } catch (CompilerException $e) {
140
                $this->io->writeError("<error>failed to process: {$file->getOutputPath()}</error>");
141
            }
142
        }
143
    }
144
145
    /**
146
     * @param FileContainer $file
147
     *
148
     * @return FileContainer
149
     * @throws CompilerException
150
     */
151
    public function processFile(FileContainer $file)
152
    {
153
        switch ($file->getType()) {
154
            case FileContainer::TYPE_SCSS:
155
                return $this->compileSCSS($file);
156
            case FileContainer::TYPE_LESS:
157
                return $this->compileLESS($file);
158
        }
159
160
        throw new CompilerException('unknown compiler');
161
    }
162
163
    /**
164
     * @param FileContainer $file
165
     *
166
     * @return $this
167
     * @throws CompilerException
168
     */
169
    protected function compileSCSS(FileContainer $file)
170
    {
171
        try {
172
            $this->scss->addImportPath(dirname($file->getInputPath()));
173
            $content = $this->scss->compile($file->getInputContent());
174
175
            return $file->setOutputContent($content);
176
        } catch (ParserException $e) {
177
            throw new CompilerException($e->getMessage(), 1, $e);
178
        }
179
    }
180
181
    /**
182
     * @param FileContainer $file
183
     *
184
     * @return $this
185
     * @throws CompilerException
186
     */
187
    protected function compileLESS(FileContainer $file)
188
    {
189
        try {
190
            return $file->setOutputContent($this->less->compileFile($file->getInputPath()));
191
        } catch (\Exception $e) {
192
            throw new CompilerException($e->getMessage(), 1, $e);
193
        }
194
    }
195
196
    /**
197
     * @param string $formatter
198
     *
199
     * @return string
200
     */
201
    protected function getFormatterClass($formatter)
202
    {
203
        if (!in_array($formatter, static::$supportedFormatters)) {
204
            throw new \InvalidArgumentException('unknown formatter, available options are: ' . print_r(static::$supportedFormatters, true));
205
        }
206
207
        return 'Leafo\\ScssPhp\\Formatter\\' . ucfirst($formatter);
208
    }
209
210
    /**
211
     * @param FileContainer $file
212
     *
213
     * @throws FileException
214
     */
215
    protected function fetchInputContextIntoFile(FileContainer $file)
216
    {
217
        if (!file_exists($file->getInputPath())) {
218
            throw new FileException("file: {$file->getInputPath()} doesn't exists");
219
        }
220
221
        $file->setInputContent(file_get_contents($file->getInputPath()));
222
    }
223
}
224