<?php /** * LessCompiler class file. * @author Christoffer Niska <ChristofferNiska@gmail.com> * @copyright Copyright © Christoffer Niska 2011- * @license http://www.opensource.org/licenses/bsd-license.php New BSD License * @version 0.10.0 */ require(dirname(__FILE__).'/../lib/lessphp/lessc.inc.php'); class LessCompiler extends CApplicationComponent { /** * @var string base path. */ public $basePath; /** * @var array paths to process. */ public $paths = array(); /** * @var boolean indicates whether to always compile all files. */ public $forceCompile = false; /** * @var lessc LESS compiler instance. */ protected $_parser; /** * Initializes the component. * @throws CException if the base path does not exist. */ public function init() { if (!isset($this->basePath)) $this->basePath = Yii::getPathOfAlias('webroot'); if (!file_exists($this->basePath)) throw new CException(__CLASS__.': Failed to initialize compiler. Base path does not exist!'); if (!is_dir($this->basePath)) throw new CException(__CLASS__.': Failed to initialize compiler. Base path is not a directory!'); $this->_parser = new lessc(); if ($this->forceCompile || $this->hasChanges()) $this->compileAll(); } /** * Compiles a LESS file to a CSS file. * @param string $from the path to the source LESS file. * @param string $to the path to the target CSS file. * @throws CException if the compilation fails or the source path does not exist. */ public function compile($from, $to) { if (file_exists($from)) { try { $this->_parser->importDir = dirname($from); // Set the correct context. file_put_contents($to, $this->_parser->parse(file_get_contents($from))); } catch (exception $e) { throw new CException(__CLASS__.': Failed to compile less file with message: '.$e->getMessage().'.'); } } else throw new CException(__CLASS__.': Failed to compile less file. Source path does not exist!'); } /** * Compiles all LESS files. */ protected function compileAll() { foreach ($this->paths as $lessPath => $cssPath) { $from = $this->basePath.'/'.$lessPath; $to = $this->basePath.'/'.$cssPath; $this->compile($from, $to); } } /** * Returns whether any of files configured to be compiled has changed. * @return boolean the result. */ protected function hasChanges() { $dirs = array(); foreach ($this->paths as $source => $destination) { $compiled = $this->getLastModified($destination); if (!isset($lastCompiled) || $compiled < $lastCompiled) $lastCompiled = $compiled; if (!in_array(dirname($source), $dirs)) $dirs[] = $source; } foreach ($dirs as $dir) { $modified = $this->getLastModified($dir); if (!isset($lastModified) || $modified < $lastModified) $lastModified = $modified; } return isset($lastCompiled) && isset($lastModified) && $lastModified > $lastCompiled; } /** * Returns the last modified for a specific path. * @param string $path the path. * @return integer the last modified (as a timestamp). */ protected function getLastModified($path) { if (!file_exists($path)) return 0; else { if (is_file($path)) { $stat = stat($path); return $stat['mtime']; } else { $lastModified = null; /** @var Directory $dir */ $dir = dir($path); while ($entry = $dir->read()) { if (strpos($entry, '.') === 0) continue; $path .= '/'.$entry; if (is_dir($path)) $modified = $this->getLastModified($path); else { $stat = stat($path); $modified = $stat['mtime']; } if (isset($lastModified) || $modified > $lastModified) $lastModified = $modified; } return $lastModified; } } } }