[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/lessphp/Tree/ -> Import.php (source)

   1  <?php
   2  
   3  /**
   4   * CSS @import node
   5   *
   6   * The general strategy here is that we don't want to wait
   7   * for the parsing to be completed, before we start importing
   8   * the file. That's because in the context of a browser,
   9   * most of the time will be spent waiting for the server to respond.
  10   *
  11   * On creation, we push the import path to our import queue, though
  12   * `import,push`, we also pass it a callback, which it'll call once
  13   * the file has been fetched, and parsed.
  14   *
  15   * @package Less
  16   * @subpackage tree
  17   */
  18  class Less_Tree_Import extends Less_Tree{
  19  
  20      public $options;
  21      public $index;
  22      public $path;
  23      public $features;
  24      public $currentFileInfo;
  25      public $css;
  26      public $skip;
  27      public $root;
  28      public $type = 'Import';
  29  
  30      public function __construct($path, $features, $options, $index, $currentFileInfo = null ){
  31          $this->options = $options;
  32          $this->index = $index;
  33          $this->path = $path;
  34          $this->features = $features;
  35          $this->currentFileInfo = $currentFileInfo;
  36  
  37          if( is_array($options) ){
  38              $this->options += array('inline'=>false);
  39  
  40              if( isset($this->options['less']) || $this->options['inline'] ){
  41                  $this->css = !isset($this->options['less']) || !$this->options['less'] || $this->options['inline'];
  42              } else {
  43                  $pathValue = $this->getPath();
  44                  if( $pathValue && preg_match('/css([\?;].*)?$/',$pathValue) ){
  45                      $this->css = true;
  46                  }
  47              }
  48          }
  49      }
  50  
  51  //
  52  // The actual import node doesn't return anything, when converted to CSS.
  53  // The reason is that it's used at the evaluation stage, so that the rules
  54  // it imports can be treated like any other rules.
  55  //
  56  // In `eval`, we make sure all Import nodes get evaluated, recursively, so
  57  // we end up with a flat structure, which can easily be imported in the parent
  58  // ruleset.
  59  //
  60  
  61      public function accept($visitor){
  62  
  63          if( $this->features ){
  64              $this->features = $visitor->visitObj($this->features);
  65          }
  66          $this->path = $visitor->visitObj($this->path);
  67  
  68          if( !$this->options['inline'] && $this->root ){
  69              $this->root = $visitor->visit($this->root);
  70          }
  71      }
  72  
  73      /**
  74       * @see Less_Tree::genCSS
  75       */
  76      public function genCSS( $output ){
  77          if( $this->css ){
  78  
  79              $output->add( '@import ', $this->currentFileInfo, $this->index );
  80  
  81              $this->path->genCSS( $output );
  82              if( $this->features ){
  83                  $output->add( ' ' );
  84                  $this->features->genCSS( $output );
  85              }
  86              $output->add( ';' );
  87          }
  88      }
  89  
  90      public function toCSS(){
  91          $features = $this->features ? ' ' . $this->features->toCSS() : '';
  92  
  93          if ($this->css) {
  94              return "@import " . $this->path->toCSS() . $features . ";\n";
  95          } else {
  96              return "";
  97          }
  98      }
  99  
 100      /**
 101       * @return string
 102       */
 103      public function getPath(){
 104          if ($this->path instanceof Less_Tree_Quoted) {
 105              $path = $this->path->value;
 106              $path = ( isset($this->css) || preg_match('/(\.[a-z]*$)|([\?;].*)$/',$path)) ? $path : $path . '.less';
 107          } else if ($this->path instanceof Less_Tree_URL) {
 108              $path = $this->path->value->value;
 109          }else{
 110              return null;
 111          }
 112  
 113          //remove query string and fragment
 114          return preg_replace('/[\?#][^\?]*$/','',$path);
 115      }
 116  
 117      public function compileForImport( $env ){
 118          return new Less_Tree_Import( $this->path->compile($env), $this->features, $this->options, $this->index, $this->currentFileInfo);
 119      }
 120  
 121      public function compilePath($env) {
 122          $path = $this->path->compile($env);
 123          $rootpath = '';
 124          if( $this->currentFileInfo && $this->currentFileInfo['rootpath'] ){
 125              $rootpath = $this->currentFileInfo['rootpath'];
 126          }
 127  
 128  
 129          if( !($path instanceof Less_Tree_URL) ){
 130              if( $rootpath ){
 131                  $pathValue = $path->value;
 132                  // Add the base path if the import is relative
 133                  if( $pathValue && Less_Environment::isPathRelative($pathValue) ){
 134                      $path->value = $this->currentFileInfo['uri_root'].$pathValue;
 135                  }
 136              }
 137              $path->value = Less_Environment::normalizePath($path->value);
 138          }
 139  
 140  
 141  
 142          return $path;
 143      }
 144  
 145      public function compile( $env ){
 146  
 147          $evald = $this->compileForImport($env);
 148  
 149          //get path & uri
 150          $path_and_uri = null;
 151          if( is_callable(Less_Parser::$options['import_callback']) ){
 152              $path_and_uri = call_user_func(Less_Parser::$options['import_callback'],$evald);
 153          }
 154  
 155          if( !$path_and_uri ){
 156              $path_and_uri = $evald->PathAndUri();
 157          }
 158  
 159          if( $path_and_uri ){
 160              list($full_path, $uri) = $path_and_uri;
 161          }else{
 162              $full_path = $uri = $evald->getPath();
 163          }
 164  
 165  
 166          //import once
 167          if( $evald->skip( $full_path, $env) ){
 168              return array();
 169          }
 170  
 171          if( $this->options['inline'] ){
 172              //todo needs to reference css file not import
 173              //$contents = new Less_Tree_Anonymous($this->root, 0, array('filename'=>$this->importedFilename), true );
 174  
 175              Less_Parser::AddParsedFile($full_path);
 176              $contents = new Less_Tree_Anonymous( file_get_contents($full_path), 0, array(), true );
 177  
 178              if( $this->features ){
 179                  return new Less_Tree_Media( array($contents), $this->features->value );
 180              }
 181  
 182              return array( $contents );
 183          }
 184  
 185          // optional (need to be before "CSS" to support optional CSS imports. CSS should be checked only if empty($this->currentFileInfo))
 186          if( isset($this->options['optional']) && $this->options['optional'] && !file_exists($full_path) && (!$evald->css || !empty($this->currentFileInfo))) {
 187              return array();
 188          }
 189  
 190  
 191          // css ?
 192          if( $evald->css ){
 193              $features = ( $evald->features ? $evald->features->compile($env) : null );
 194              return new Less_Tree_Import( $this->compilePath( $env), $features, $this->options, $this->index);
 195          }
 196  
 197  
 198          return $this->ParseImport( $full_path, $uri, $env );
 199      }
 200  
 201  
 202      /**
 203       * Using the import directories, get the full absolute path and uri of the import
 204       *
 205       * @param Less_Tree_Import $evald
 206       */
 207      public function PathAndUri(){
 208  
 209          $evald_path = $this->getPath();
 210  
 211          if( $evald_path ){
 212  
 213              $import_dirs = array();
 214  
 215              if( Less_Environment::isPathRelative($evald_path) ){
 216                  //if the path is relative, the file should be in the current directory
 217                  $import_dirs[ $this->currentFileInfo['currentDirectory'] ] = $this->currentFileInfo['uri_root'];
 218  
 219              }else{
 220                  //otherwise, the file should be relative to the server root
 221                  $import_dirs[ $this->currentFileInfo['entryPath'] ] = $this->currentFileInfo['entryUri'];
 222  
 223                  //if the user supplied entryPath isn't the actual root
 224                  $import_dirs[ $_SERVER['DOCUMENT_ROOT'] ] = '';
 225  
 226              }
 227  
 228              // always look in user supplied import directories
 229              $import_dirs = array_merge( $import_dirs, Less_Parser::$options['import_dirs'] );
 230  
 231  
 232              foreach( $import_dirs as $rootpath => $rooturi){
 233                  if( is_callable($rooturi) ){
 234                      list($path, $uri) = call_user_func($rooturi, $evald_path);
 235                      if( is_string($path) ){
 236                          $full_path = $path;
 237                          return array( $full_path, $uri );
 238                      }
 239                  }elseif( !empty($rootpath) ){
 240  
 241  
 242                      if( $rooturi ){
 243                          if( strpos($evald_path,$rooturi) === 0 ){
 244                              $evald_path = substr( $evald_path, strlen($rooturi) );
 245                          }
 246                      }
 247  
 248                      $path = rtrim($rootpath,'/\\').'/'.ltrim($evald_path,'/\\');
 249  
 250                      if( file_exists($path) ){
 251                          $full_path = Less_Environment::normalizePath($path);
 252                          $uri = Less_Environment::normalizePath(dirname($rooturi.$evald_path));
 253                          return array( $full_path, $uri );
 254                      } elseif( file_exists($path.'.less') ){
 255                          $full_path = Less_Environment::normalizePath($path.'.less');
 256                          $uri = Less_Environment::normalizePath(dirname($rooturi.$evald_path.'.less'));
 257                          return array( $full_path, $uri );
 258                      }
 259                  }
 260              }
 261          }
 262      }
 263  
 264  
 265      /**
 266       * Parse the import url and return the rules
 267       *
 268       * @return Less_Tree_Media|array
 269       */
 270      public function ParseImport( $full_path, $uri, $env ){
 271  
 272          $import_env = clone $env;
 273          if( (isset($this->options['reference']) && $this->options['reference']) || isset($this->currentFileInfo['reference']) ){
 274              $import_env->currentFileInfo['reference'] = true;
 275          }
 276  
 277          if( (isset($this->options['multiple']) && $this->options['multiple']) ){
 278              $import_env->importMultiple = true;
 279          }
 280  
 281          $parser = new Less_Parser($import_env);
 282          $root = $parser->parseFile($full_path, $uri, true);
 283  
 284  
 285          $ruleset = new Less_Tree_Ruleset(array(), $root->rules );
 286          $ruleset->evalImports($import_env);
 287  
 288          return $this->features ? new Less_Tree_Media($ruleset->rules, $this->features->value) : $ruleset->rules;
 289      }
 290  
 291  
 292      /**
 293       * Should the import be skipped?
 294       *
 295       * @return boolean|null
 296       */
 297  	private function Skip($path, $env){
 298  
 299          $path = Less_Parser::winPath(realpath($path));
 300  
 301          if( $path && Less_Parser::FileParsed($path) ){
 302  
 303              if( isset($this->currentFileInfo['reference']) ){
 304                  return true;
 305              }
 306  
 307              return !isset($this->options['multiple']) && !$env->importMultiple;
 308          }
 309  
 310      }
 311  }


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1