Chris@18: drupalRoot = false; Chris@18: $this->composerRoot = false; Chris@18: $this->vendorDir = false; Chris@18: Chris@18: foreach (array(true, false) as $follow_symlinks) { Chris@18: $path = $start_path; Chris@18: if ($follow_symlinks && is_link($path)) { Chris@18: $path = realpath($path); Chris@18: } Chris@18: // Check the start path. Chris@18: if ($this->isValidRoot($path)) { Chris@18: return true; Chris@18: } else { Chris@18: // Move up dir by dir and check each. Chris@18: while ($path = $this->shiftPathUp($path)) { Chris@18: if ($follow_symlinks && is_link($path)) { Chris@18: $path = realpath($path); Chris@18: } Chris@18: if ($this->isValidRoot($path)) { Chris@18: return true; Chris@18: } Chris@18: } Chris@18: } Chris@18: } Chris@18: Chris@18: return false; Chris@18: } Chris@18: Chris@18: /** Chris@18: * Returns parent directory. Chris@18: * Chris@18: * @param string Chris@18: * Path to start from Chris@18: * Chris@18: * @return string|false Chris@18: * Parent path of given path or false when $path is filesystem root Chris@18: */ Chris@18: private function shiftPathUp($path) Chris@18: { Chris@18: $parent = dirname($path); Chris@18: Chris@18: return in_array($parent, ['.', $path]) ? false : $parent; Chris@18: } Chris@18: Chris@18: /** Chris@18: * @param $path Chris@18: * Chris@18: * @return bool Chris@18: */ Chris@18: protected function isValidRoot($path) Chris@18: { Chris@18: if (!empty($path) && is_dir($path) && file_exists($path . '/autoload.php') && file_exists($path . '/' . $this->getComposerFileName())) { Chris@18: // Additional check for the presence of core/composer.json to Chris@18: // grant it is not a Drupal 7 site with a base folder named "core". Chris@18: $candidate = 'core/includes/common.inc'; Chris@18: if (file_exists($path . '/' . $candidate) && file_exists($path . '/core/core.services.yml')) { Chris@18: if (file_exists($path . '/core/misc/drupal.js') || file_exists($path . '/core/assets/js/drupal.js')) { Chris@18: $this->composerRoot = $path; Chris@18: $this->drupalRoot = $path; Chris@18: $this->vendorDir = $this->composerRoot . '/vendor'; Chris@18: } Chris@18: } Chris@18: } Chris@18: if (!empty($path) && is_dir($path) && file_exists($path . '/' . $this->getComposerFileName())) { Chris@18: $json = json_decode( Chris@18: file_get_contents($path . '/' . $this->getComposerFileName()), Chris@18: true Chris@18: ); Chris@18: if (is_array($json)) { Chris@18: if (isset($json['extra']['installer-paths']) && is_array($json['extra']['installer-paths'])) { Chris@18: foreach ($json['extra']['installer-paths'] as $install_path => $items) { Chris@18: if (in_array('type:drupal-core', $items) || Chris@18: in_array('drupal/core', $items) || Chris@18: in_array('drupal/drupal', $items)) { Chris@18: $this->composerRoot = $path; Chris@18: // @todo: Remove this magic and detect the major version instead. Chris@18: if ($install_path == 'core') { Chris@18: $install_path = null; Chris@18: } elseif (substr($install_path, -5) == '/core') { Chris@18: $install_path = substr($install_path, 0, -5); Chris@18: } Chris@18: $this->drupalRoot = rtrim($path . '/' . $install_path, '/'); Chris@18: $this->vendorDir = $this->composerRoot . '/vendor'; Chris@18: } Chris@18: } Chris@18: } Chris@18: } Chris@18: } Chris@18: if ($this->composerRoot && file_exists($this->composerRoot . '/' . $this->getComposerFileName())) { Chris@18: $json = json_decode( Chris@18: file_get_contents($path . '/' . $this->getComposerFileName()), Chris@18: true Chris@18: ); Chris@18: if (is_array($json) && isset($json['config']['vendor-dir'])) { Chris@18: $this->vendorDir = $this->composerRoot . '/' . $json['config']['vendor-dir']; Chris@18: } Chris@18: } Chris@18: Chris@18: return $this->drupalRoot && $this->composerRoot && $this->vendorDir; Chris@18: } Chris@18: Chris@18: /** Chris@18: * @return string Chris@18: */ Chris@18: public function getDrupalRoot() Chris@18: { Chris@18: return $this->drupalRoot; Chris@18: } Chris@18: Chris@18: /** Chris@18: * @return string Chris@18: */ Chris@18: public function getComposerRoot() Chris@18: { Chris@18: return $this->composerRoot; Chris@18: } Chris@18: Chris@18: /** Chris@18: * @return string Chris@18: */ Chris@18: protected function getComposerFileName() Chris@18: { Chris@18: return trim(getenv('COMPOSER')) ?: 'composer.json'; Chris@18: } Chris@18: Chris@18: /** Chris@18: * @return string Chris@18: */ Chris@18: public function getVendorDir() Chris@18: { Chris@18: return $this->vendorDir; Chris@18: } Chris@18: }