Completed
Push — master ( c0b2e0...0bd897 )
by Eugene
32s
created

Processor::fetchInputContextIntoFile()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

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 4
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 lessc as LESSCompiler;
11
use scss_compass as CompassCompiler;
12
13
/**
14
 * @since 0.1
15
 */
16
class Processor
17
{
18
    const FORMATTER_COMPRESSED = 'compressed';
19
    const FORMATTER_CRUNCHED   = 'crunched';
20
    const FORMATTER_EXPANDED   = 'expanded';
21
    const FORMATTER_NESTED     = 'nested';
22
    const FORMATTER_COMPACT    = 'compact';
23
    static $supportedFormatters = [
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $supportedFormatters.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
24
        self::FORMATTER_COMPRESSED,
25
        self::FORMATTER_CRUNCHED,
26
        self::FORMATTER_EXPANDED,
27
        self::FORMATTER_NESTED,
28
        self::FORMATTER_COMPACT
29
    ];
30
    /**
31
     * @var IOInterface
32
     */
33
    private $io;
34
    /**
35
     * @var FileContainer[]
36
     */
37
    private $files = [];
38
    /**
39
     * @var SASSCompiler
40
     */
41
    private $sass;
42
    /**
43
     * @var LESSCompiler
44
     */
45
    private $less;
46
47
    public function __construct(IOInterface $io)
48
    {
49
        $this->io = $io;
50
        $this->initCompilers();
51
    }
52
53
    protected function initCompilers()
54
    {
55
        $this->less = new LESSCompiler();
56
        $this->sass = new SASSCompiler();
57
        /** attaches compass functionality to the SASS compiler */
58
        new CompassCompiler($this->sass);
59
    }
60
61
    /**
62
     * @param string $inputPath
63
     * @param string $outputPath
64
     *
65
     * @throws \Exception
66
     */
67
    public function attachFiles($inputPath, $outputPath)
68
    {
69
        if (is_dir($inputPath)) {
70
            $files = scandir($inputPath);
71
            unset($files[0], $files[1]);
72
73
            foreach ($files as $file) {
74
                $this->attachFiles("$inputPath/$file", $outputPath);
75
            }
76
        } else if (is_file($inputPath)) {
77
            $this->files[] = new FileContainer($inputPath, $outputPath);
78
        } else {
79
            throw new \Exception("file doesn't exists");
80
        }
81
    }
82
83
    /**
84
     * @return FileContainer[]
85
     */
86
    public function getFiles()
87
    {
88
        return $this->files;
89
    }
90
91
    /**
92
     * @return string[]
93
     */
94
    protected function concatOutput()
95
    {
96
        $outputMap = [];
97
        foreach ($this->files as $file) {
98
            if (!isset($outputMap[$file->getOutputPath()])) {
99
                $outputMap[$file->getOutputPath()] = '';
100
            }
101
102
            $outputMap[$file->getOutputPath()] .= $file->getOutputContent();
103
        }
104
105
        return $outputMap;
106
    }
107
108
    /**
109
     * save output into file
110
     */
111
    public function saveOutput()
112
    {
113
        foreach ($this->concatOutput() as $path => $content) {
114
            $directory = dirname($path);
115
            if (!is_dir($directory)) {
116
                $this->io->write("<info>creating directory</info>: {$directory}");
117
                mkdir($directory, 0755, true);
118
            }
119
120
            $this->io->write("<info>save output into</info>: {$path}");
121
            file_put_contents($path, $content);
122
        }
123
    }
124
125
    /**
126
     * @param string $formatter
127
     *
128
     * @throws CompilerException
129
     */
130
    public function processFiles($formatter)
131
    {
132
        $this->sass->setFormatter($this->getFormatterClass($formatter));
133
        $this->io->write("<info>use '{$formatter}' formatting</info>");
134
135
        foreach ($this->files as $file) {
136
            $this->io->write("<info>processing</info>: {$file->getInputPath()}");
137
            $this->fetchInputContextIntoFile($file);
138
139
            try {
140
                $this->processFile($file);
141
            } catch (CompilerException $e) {
142
                $this->io->writeError("<error>failed to process: {$file->getOutputPath()}</error>");
143
            }
144
        }
145
    }
146
147
    /**
148
     * @param FileContainer $file
149
     *
150
     * @return FileContainer
151
     * @throws CompilerException
152
     */
153
    public function processFile(FileContainer $file)
154
    {
155
        switch ($file->getType()) {
156
            case FileContainer::TYPE_SCSS:
157
                $this->sass->addImportPath(dirname($file->getInputPath()));
158
                $content = $this->sass->compile($file->getInputContent());
159
160
                return $file->setOutputContent($content);
161
            case FileContainer::TYPE_LESS:
162
                return $file->setOutputContent($this->less->compileFile($file->getInputPath()));
163
        }
164
165
        throw new CompilerException('unknown compiler');
166
    }
167
168
    /**
169
     * @param string $formatter
170
     *
171
     * @return string
172
     */
173
    protected function getFormatterClass($formatter)
174
    {
175
        if (!in_array($formatter, static::$supportedFormatters)) {
0 ignored issues
show
Bug introduced by
Since $supportedFormatters is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $supportedFormatters to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
176
            throw new \InvalidArgumentException('unknown formatter, available options are: ' . print_r(static::$supportedFormatters, true));
0 ignored issues
show
Bug introduced by
Since $supportedFormatters is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $supportedFormatters to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
177
        }
178
179
        return 'Leafo\\ScssPhp\\Formatter\\' . ucfirst($formatter);
180
    }
181
182
    /**
183
     * @param FileContainer $file
184
     *
185
     * @throws FileException
186
     */
187
    protected function fetchInputContextIntoFile(FileContainer $file)
188
    {
189
        if (!file_exists($file->getInputPath())) {
190
            throw new FileException("file: {$file->getInputPath()} doesn't exists");
191
        }
192
193
        $file->setInputContent(file_get_contents($file->getInputPath()));
194
    }
195
}
196