3 namespace Robo\Task\Assets;
6 use Robo\Task\BaseTask;
8 abstract class CssPreprocessor extends BaseTask
10 const FORMAT_NAME = '';
13 * Default compiler to use.
20 * Available compilers list
24 protected $compilers = [];
31 protected $compilerOptions = [];
36 protected $files = [];
39 * Constructor. Accepts array of file paths.
43 public function __construct(array $input)
45 $this->files = $input;
47 $this->setDefaultCompiler();
50 protected function setDefaultCompiler()
52 if (isset($this->compilers[0])) {
53 //set first compiler as default
54 $this->compiler = $this->compilers[0];
59 * Sets import directories
60 * Alias for setImportPaths
61 * @see CssPreprocessor::setImportPaths
63 * @param array|string $dirs
67 public function importDir($dirs)
69 return $this->setImportPaths($dirs);
73 * Adds import directory
79 public function addImportPath($dir)
81 if (!isset($this->compilerOptions['importDirs'])) {
82 $this->compilerOptions['importDirs'] = [];
85 if (!in_array($dir, $this->compilerOptions['importDirs'], true)) {
86 $this->compilerOptions['importDirs'][] = $dir;
93 * Sets import directories
95 * @param array|string $dirs
99 public function setImportPaths($dirs)
101 if (!is_array($dirs)) {
105 $this->compilerOptions['importDirs'] = $dirs;
111 * @param string $formatterName
115 public function setFormatter($formatterName)
117 $this->compilerOptions['formatter'] = $formatterName;
125 * @param string $compiler
126 * @param array $options
130 public function compiler($compiler, array $options = [])
132 $this->compiler = $compiler;
133 $this->compilerOptions = array_merge($this->compilerOptions, $options);
145 protected function compile($file)
147 if (is_callable($this->compiler)) {
148 return call_user_func($this->compiler, $file, $this->compilerOptions);
151 if (method_exists($this, $this->compiler)) {
152 return $this->{$this->compiler}($file);
161 public function run()
163 if (!in_array($this->compiler, $this->compilers, true)
164 && !is_callable($this->compiler)
166 $message = sprintf('Invalid ' . static::FORMAT_NAME . ' compiler %s!', $this->compiler);
168 return Result::error($this, $message);
171 foreach ($this->files as $in => $out) {
172 if (!file_exists($in)) {
173 $message = sprintf('File %s not found.', $in);
175 return Result::error($this, $message);
177 if (file_exists($out) && !is_writable($out)) {
178 return Result::error($this, 'Destination already exists and cannot be overwritten.');
182 foreach ($this->files as $in => $out) {
183 $css = $this->compile($in);
185 if ($css instanceof Result) {
187 } elseif (false === $css) {
189 ucfirst(static::FORMAT_NAME) . ' compilation failed for %s.',
193 return Result::error($this, $message);
196 $dst = $out . '.part';
197 $write_result = file_put_contents($dst, $css);
199 if (false === $write_result) {
200 $message = sprintf('File write failed: %s', $out);
203 return Result::error($this, $message);
206 // Cannot be cross-volume: should always succeed
209 $this->printTaskSuccess('Wrote CSS to {filename}', ['filename' => $out]);
212 return Result::success($this, 'All ' . static::FORMAT_NAME . ' files compiled.');