5 * Contains \DrupalFinder\DrupalFinder.
8 namespace DrupalFinder;
13 * Drupal web public directory.
20 * Drupal package composer directory.
24 private $composerRoot;
27 * Composer vendor directory.
31 * @see https://getcomposer.org/doc/06-config.md#vendor-dir
35 public function locateRoot($start_path)
37 $this->drupalRoot = false;
38 $this->composerRoot = false;
39 $this->vendorDir = false;
41 foreach (array(true, false) as $follow_symlinks) {
43 if ($follow_symlinks && is_link($path)) {
44 $path = realpath($path);
46 // Check the start path.
47 if ($this->isValidRoot($path)) {
50 // Move up dir by dir and check each.
51 while ($path = $this->shiftPathUp($path)) {
52 if ($follow_symlinks && is_link($path)) {
53 $path = realpath($path);
55 if ($this->isValidRoot($path)) {
66 * Returns parent directory.
71 * @return string|false
72 * Parent path of given path or false when $path is filesystem root
74 private function shiftPathUp($path)
76 $parent = dirname($path);
78 return in_array($parent, ['.', $path]) ? false : $parent;
86 protected function isValidRoot($path)
88 if (!empty($path) && is_dir($path) && file_exists($path . '/autoload.php') && file_exists($path . '/' . $this->getComposerFileName())) {
89 // Additional check for the presence of core/composer.json to
90 // grant it is not a Drupal 7 site with a base folder named "core".
91 $candidate = 'core/includes/common.inc';
92 if (file_exists($path . '/' . $candidate) && file_exists($path . '/core/core.services.yml')) {
93 if (file_exists($path . '/core/misc/drupal.js') || file_exists($path . '/core/assets/js/drupal.js')) {
94 $this->composerRoot = $path;
95 $this->drupalRoot = $path;
96 $this->vendorDir = $this->composerRoot . '/vendor';
100 if (!empty($path) && is_dir($path) && file_exists($path . '/' . $this->getComposerFileName())) {
102 file_get_contents($path . '/' . $this->getComposerFileName()),
105 if (is_array($json)) {
106 if (isset($json['extra']['installer-paths']) && is_array($json['extra']['installer-paths'])) {
107 foreach ($json['extra']['installer-paths'] as $install_path => $items) {
108 if (in_array('type:drupal-core', $items) ||
109 in_array('drupal/core', $items) ||
110 in_array('drupal/drupal', $items)) {
111 $this->composerRoot = $path;
112 // @todo: Remove this magic and detect the major version instead.
113 if ($install_path == 'core') {
114 $install_path = null;
115 } elseif (substr($install_path, -5) == '/core') {
116 $install_path = substr($install_path, 0, -5);
118 $this->drupalRoot = rtrim($path . '/' . $install_path, '/');
119 $this->vendorDir = $this->composerRoot . '/vendor';
125 if ($this->composerRoot && file_exists($this->composerRoot . '/' . $this->getComposerFileName())) {
127 file_get_contents($path . '/' . $this->getComposerFileName()),
130 if (is_array($json) && isset($json['config']['vendor-dir'])) {
131 $this->vendorDir = $this->composerRoot . '/' . $json['config']['vendor-dir'];
135 return $this->drupalRoot && $this->composerRoot && $this->vendorDir;
141 public function getDrupalRoot()
143 return $this->drupalRoot;
149 public function getComposerRoot()
151 return $this->composerRoot;
157 protected function getComposerFileName()
159 return trim(getenv('COMPOSER')) ?: 'composer.json';
165 public function getVendorDir()
167 return $this->vendorDir;