diff --git a/core/lib/Drupal/Component/FileSystem/CircularReferenceResistantPathCollection.php b/core/lib/Drupal/Component/FileSystem/CircularReferenceResistantPathCollection.php new file mode 100644 index 0000000000..ec6d90dee8 --- /dev/null +++ b/core/lib/Drupal/Component/FileSystem/CircularReferenceResistantPathCollection.php @@ -0,0 +1,61 @@ +canonicalPaths[$realpath] = $pathname; + } + + /** + * Checks whether we are already tracking the given realpath. + * + * @param string $realpath + * The realpath to check. + * + * @return bool + * TRUE if the realpath is already being tracked. + */ + public function realPathExists($realpath) { + return array_key_exists($realpath, $this->canonicalPaths); + } + + /** + * Checks whether we are already tracking the given canonical path. + * + * @param string $pathname + * The canonical path name to check. + * + * @return bool + * TRUE if the canonical path name is already being tracked. + */ + public function canonicalPathExists($pathname) { + return in_array($pathname, $this->canonicalPaths); + } + +} diff --git a/core/lib/Drupal/Component/FileSystem/CircularReferenceResistantRecursiveDirectoryIterator.php b/core/lib/Drupal/Component/FileSystem/CircularReferenceResistantRecursiveDirectoryIterator.php index 7b3c2255b5..62735a90ae 100644 --- a/core/lib/Drupal/Component/FileSystem/CircularReferenceResistantRecursiveDirectoryIterator.php +++ b/core/lib/Drupal/Component/FileSystem/CircularReferenceResistantRecursiveDirectoryIterator.php @@ -2,21 +2,39 @@ namespace Drupal\Component\FileSystem; +/** + * A directory iterator that will not follow circular references more than once. + */ class CircularReferenceResistantRecursiveDirectoryIterator extends \RecursiveDirectoryIterator { /** - * @var CircularReferenceResistantRecursiveDirectoryIteratorCanonicalPathCollection + * A collection of paths that have already been iterated over. + * + * @var CircularReferenceResistantPathCollection */ protected $canonicalPathsCollection; - public function __construct($path, $flags, $canonicalPathsCollection = NULL) { + /** + * Constructs a new CircularReferenceResistantRecursiveDirectoryIterator. + * + * @param string $path + * The path to the directory to iterate over. + * @param int $flags + * The flags to pass, identical to those of \RecursiveDirectoryIterator + * @param \Drupal\Component\FileSystem\CircularReferenceResistantPathCollection $canonicalPathsCollection + * The collection of paths that have already been iterated over. + */ + public function __construct($path, $flags, CircularReferenceResistantPathCollection $canonicalPathsCollection = NULL) { if (empty($canonicalPathsCollection)) { - $canonicalPathsCollection = new CircularReferenceResistantRecursiveDirectoryIteratorCanonicalPathCollection(); + $canonicalPathsCollection = new CircularReferenceResistantPathCollection(); } $this->canonicalPathsCollection = $canonicalPathsCollection; parent::__construct($path, $flags); } + /** + * {@inheritdoc} + */ public function hasChildren($allow_links = NULL) { if ($this->isCanonicalPath()) { return parent::hasChildren($allow_links); @@ -24,6 +42,9 @@ public function hasChildren($allow_links = NULL) { return FALSE; } + /** + * {@inheritdoc} + */ public function getChildren() { if ($this->isCanonicalPath()) { return new CircularReferenceResistantRecursiveDirectoryIterator($this->getPathname(), $this->getFlags(), $this->canonicalPathsCollection); @@ -31,6 +52,14 @@ public function getChildren() { return new \RecursiveIteratorIterator([]); } + /** + * Checks whether the current path is a canonical path. + * + * @return bool + * Will return TRUE for the first path that references a particular + * dereferenced ("real") path. For all other paths referencing the same + * realpath this will return FALSE. + */ protected function isCanonicalPath() { // If we are not following symlinks then all paths will be canonical since // there won't be any circular references. @@ -63,29 +92,3 @@ protected function followingSymlinks() { } } - -class CircularReferenceResistantRecursiveDirectoryIteratorCanonicalPathCollection { - - /** - * The canonical paths of the files in the directory. - * - * @var string[] - * An associative array of canonical paths of files in the directory that - * have already been iterated over, keyed by realpath. If multiple paths - * exist for a given realpath then the first path that was encountered will - * be considered the canonical path. - */ - protected $canonicalPaths = []; - - public function setPath($realpath, $pathname) { - $this->canonicalPaths[$realpath] = $pathname; - } - - public function realPathExists($realpath) { - return array_key_exists($realpath, $this->canonicalPaths); - } - - public function canonicalPathExists($pathname) { - return in_array($pathname, $this->canonicalPaths); - } -} diff --git a/core/modules/simpletest/src/TestDiscovery.php b/core/modules/simpletest/src/TestDiscovery.php index 638c9b9d99..c3df50cd60 100644 --- a/core/modules/simpletest/src/TestDiscovery.php +++ b/core/modules/simpletest/src/TestDiscovery.php @@ -5,6 +5,7 @@ use Doctrine\Common\Annotations\SimpleAnnotationReader; use Doctrine\Common\Reflection\StaticReflectionParser; use Drupal\Component\Annotation\Reflection\MockFileFinder; +use Drupal\Component\FileSystem\CircularReferenceResistantRecursiveDirectoryIterator; use Drupal\Component\Utility\NestedArray; use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\Extension\ExtensionDiscovery; @@ -289,7 +290,7 @@ public static function scanDirectory($namespace_prefix, $path) { $flags |= \FilesystemIterator::FOLLOW_SYMLINKS; $flags |= \FilesystemIterator::CURRENT_AS_SELF; - $iterator = new \RecursiveDirectoryIterator($path, $flags); + $iterator = new CircularReferenceResistantRecursiveDirectoryIterator($path, $flags); $filter = new \RecursiveCallbackFilterIterator($iterator, function ($current, $key, $iterator) { if ($iterator->hasChildren()) { return TRUE;