You are here

protected function ComponentDiscovery::scanDirectory in Decoupled Blocks 8

This is mostly extended to be able to use a different RecursiveExtensionFilterIterator class when searching custom user dirs.

Overrides ExtensionDiscovery::scanDirectory

1 call to ComponentDiscovery::scanDirectory()
ComponentDiscovery::scan in src/ComponentDiscovery.php
Extends to provide user defined paths to look for components.

File

src/ComponentDiscovery.php, line 154

Class

ComponentDiscovery
Discovery service for front-end components provided by modules and themes.

Namespace

Drupal\pdb

Code

protected function scanDirectory($dir, $include_tests) {

  // If it is a global discovery, then follow parent's approach.
  if ($this->globalDiscovery) {
    return parent::scanDirectory($dir, $include_tests);
  }

  // Based on parent::scanDirectory().
  $files = [];

  // In order to scan top-level directories, absolute directory paths have to
  // be used (which also improves performance, since any configured PHP
  // include_paths will not be consulted). Retain the relative originating
  // directory being scanned, so relative paths can be reconstructed below
  // (all paths are expected to be relative to $this->root).
  $dir_prefix = $dir == '' ? '' : "{$dir}/";
  $absolute_dir = $dir == '' ? $this->root : $this->root . "/{$dir}";
  if (!is_dir($absolute_dir)) {
    return $files;
  }

  // Use Unix paths regardless of platform, skip dot directories, follow
  // symlinks (to allow extensions to be linked from elsewhere), and return
  // the RecursiveDirectoryIterator instance to have access to getSubPath(),
  // since SplFileInfo does not support relative paths.
  $flags = \FilesystemIterator::UNIX_PATHS;
  $flags |= \FilesystemIterator::SKIP_DOTS;
  $flags |= \FilesystemIterator::FOLLOW_SYMLINKS;
  $flags |= \FilesystemIterator::CURRENT_AS_SELF;
  $directory_iterator = new \RecursiveDirectoryIterator($absolute_dir, $flags);

  // Allow directories specified in settings.php to be ignored. You can use
  // this to not check for files in common special-purpose directories. For
  // example, node_modules and bower_components. Ignoring irrelevant
  // directories is a performance boost.
  $ignore_directories = Settings::get('file_scan_ignore_directories', []);

  // Filter the recursive scan to discover extensions only.
  // Important: Without a RecursiveFilterIterator, RecursiveDirectoryIterator
  // would recurse into the entire filesystem directory tree without any kind
  // of limitations.
  $filter = new PdbRecursiveExtensionFilterIterator($directory_iterator, $ignore_directories);
  $filter
    ->acceptTests($include_tests);

  // The actual recursive filesystem scan is only invoked by instantiating the
  // RecursiveIteratorIterator.
  $iterator = new \RecursiveIteratorIterator($filter, \RecursiveIteratorIterator::LEAVES_ONLY, \RecursiveIteratorIterator::CATCH_GET_CHILD);
  foreach ($iterator as $key => $fileinfo) {

    // All extension names in Drupal have to be valid PHP function names due
    // to the module hook architecture.
    if (!preg_match(static::PHP_FUNCTION_PATTERN, $fileinfo
      ->getBasename('.info.yml'))) {
      continue;
    }
    $extension_arguments = $this->fileCache ? $this->fileCache
      ->get($fileinfo
      ->getPathName()) : FALSE;

    // Ensure $extension_arguments is an array. Previously, the Extension
    // object was cached and now needs to be replaced with the array.
    if (empty($extension_arguments) || !is_array($extension_arguments)) {

      // Determine extension type from info file.
      $type = FALSE;
      $file = $fileinfo
        ->openFile('r');
      while (!$type && !$file
        ->eof()) {
        preg_match('@^type:\\s*(\'|")?(\\w+)\\1?\\s*$@', $file
          ->fgets(), $matches);
        if (isset($matches[2])) {
          $type = $matches[2];
        }
      }
      if (empty($type)) {
        continue;
      }
      $name = $fileinfo
        ->getBasename('.info.yml');
      $pathname = $dir_prefix . $fileinfo
        ->getSubPathname();

      // Determine whether the extension has a main extension file.
      // For theme engines, the file extension is .engine.
      if ($type == 'theme_engine') {
        $filename = $name . '.engine';
      }
      else {
        $filename = $name . '.' . $type;
      }
      if (!file_exists($this->root . '/' . dirname($pathname) . '/' . $filename)) {
        $filename = NULL;
      }
      $extension_arguments = [
        'type' => $type,
        'pathname' => $pathname,
        'filename' => $filename,
        'subpath' => $fileinfo
          ->getSubPath(),
      ];
      if ($this->fileCache) {
        $this->fileCache
          ->set($fileinfo
          ->getPathName(), $extension_arguments);
      }
    }
    $extension = new Extension($this->root, $extension_arguments['type'], $extension_arguments['pathname'], $extension_arguments['filename']);

    // Track the originating directory for sorting purposes.
    $extension->subpath = $extension_arguments['subpath'];
    $extension->origin = $dir;
    $files[$extension_arguments['type']][$key] = $extension;
  }
  return $files;
}