b8fb7daa196e8d344fecbd54fca30ea3c1997315
[yaffs-website] / vendor / drush / drush / src / Boot / DrupalBoot.php
1 <?php
2
3 namespace Drush\Boot;
4
5 use Drush\Drush;
6 use Drush\Log\LogLevel;
7 use Drush\Sql\SqlBase;
8 use Psr\Log\LoggerInterface;
9 use Drupal\user\Entity\User;
10 use Symfony\Component\HttpFoundation\Request;
11 use Webmozart\PathUtil\Path;
12
13 abstract class DrupalBoot extends BaseBoot
14 {
15     /**
16      * Select the best URI for the provided cwd. Only called
17      * if the user did not explicitly specify a URI.
18      */
19     public function findUri($root, $cwd)
20     {
21         if (Path::isBasePath($root, $cwd)) {
22             $siteDir = $this->scanUpForUri($root, $cwd);
23             if ($siteDir) {
24                 return basename($siteDir);
25             }
26         }
27         return 'default';
28     }
29
30     protected function scanUpForUri($root, $scan)
31     {
32         $root = Path::canonicalize($root);
33         while (!empty($scan)) {
34             if (file_exists("$scan/settings.php")) {
35                 return $scan;
36             }
37             // Use Path::getDirectory instead of dirname to
38             // avoid certain bugs. Returns a canonicalized path.
39             $next = Path::getDirectory($scan);
40             if ($next == $scan) {
41                 return false;
42             }
43             $scan = $next;
44             if ($scan == $root) {
45                 return false;
46             }
47         }
48         return false;
49     }
50
51     public function validRoot($path)
52     {
53     }
54
55     public function getVersion($drupal_root)
56     {
57     }
58
59     public function confPath($require_settings = true, $reset = false)
60     {
61         return confPath($require_settings, $reset);
62     }
63
64     /**
65      * Bootstrap phases used with Drupal:
66      *
67      *     DRUSH_BOOTSTRAP_DRUSH                = Only Drush.
68      *     DRUSH_BOOTSTRAP_DRUPAL_ROOT          = Find a valid Drupal root.
69      *     DRUSH_BOOTSTRAP_DRUPAL_SITE          = Find a valid Drupal site.
70      *     DRUSH_BOOTSTRAP_DRUPAL_CONFIGURATION = Load the site's settings.
71      *     DRUSH_BOOTSTRAP_DRUPAL_DATABASE      = Initialize the database.
72      *     DRUSH_BOOTSTRAP_DRUPAL_FULL          = Initialize Drupal fully.
73      *
74      * The value is the name of the method of the Boot class to
75      * execute when bootstrapping.  Prior to bootstrapping, a "validate"
76      * method is called, if defined.  The validate method name is the
77      * bootstrap method name with "_validate" appended.
78      */
79     public function bootstrapPhases()
80     {
81         return parent::bootstrapPhases() + [
82             DRUSH_BOOTSTRAP_DRUPAL_ROOT            => 'bootstrapDrupalRoot',
83             DRUSH_BOOTSTRAP_DRUPAL_SITE            => 'bootstrapDrupalSite',
84             DRUSH_BOOTSTRAP_DRUPAL_CONFIGURATION   => 'bootstrapDrupalConfiguration',
85             DRUSH_BOOTSTRAP_DRUPAL_DATABASE        => 'bootstrapDrupalDatabase',
86             DRUSH_BOOTSTRAP_DRUPAL_FULL            => 'bootstrapDrupalFull',
87         ];
88     }
89
90     public function bootstrapPhaseMap()
91     {
92         return parent::bootstrapPhaseMap() + [
93             'root' => DRUSH_BOOTSTRAP_DRUPAL_ROOT,
94             'site' => DRUSH_BOOTSTRAP_DRUPAL_SITE,
95             'config' => DRUSH_BOOTSTRAP_DRUPAL_CONFIGURATION,
96             'configuration' => DRUSH_BOOTSTRAP_DRUPAL_CONFIGURATION,
97             'db' => DRUSH_BOOTSTRAP_DRUPAL_DATABASE,
98             'database' => DRUSH_BOOTSTRAP_DRUPAL_DATABASE,
99             'full' => DRUSH_BOOTSTRAP_DRUPAL_FULL,
100         ];
101     }
102
103     /**
104      * Validate the DRUSH_BOOTSTRAP_DRUPAL_ROOT phase.
105      *
106      * In this function, we will check if a valid Drupal directory is available.
107      * We also determine the value that will be stored in the DRUSH_DRUPAL_ROOT
108      * context and DRUPAL_ROOT constant if it is considered a valid option.
109      */
110     public function bootstrapDrupalRootValidate()
111     {
112         $drupal_root = Drush::bootstrapManager()->getRoot();
113
114         if (empty($drupal_root)) {
115             return drush_bootstrap_error('DRUSH_NO_DRUPAL_ROOT', dt("A Drupal installation directory could not be found"));
116         }
117         // TODO: Perhaps $drupal_root is now ALWAYS valid by the time we get here.
118         if (!$this->legacyValidRootCheck($drupal_root)) {
119             return drush_bootstrap_error('DRUSH_INVALID_DRUPAL_ROOT', dt("The directory !drupal_root does not contain a valid Drupal installation", ['!drupal_root' => $drupal_root]));
120         }
121
122         $version = drush_drupal_version($drupal_root);
123         $major_version = drush_drupal_major_version($drupal_root);
124         if ($major_version <= 6) {
125             return drush_set_error('DRUSH_DRUPAL_VERSION_UNSUPPORTED', dt('Drush !drush_version does not support Drupal !major_version.', ['!drush_version' => Drush::getMajorVersion(), '!major_version' => $major_version]));
126         }
127
128         drush_bootstrap_value('drupal_root', $drupal_root);
129
130         return true;
131     }
132
133     protected function legacyValidRootCheck($root)
134     {
135         $bootstrap_class = Drush::bootstrapManager()->bootstrapObjectForRoot($root);
136         return $bootstrap_class != null;
137     }
138
139     /**
140      * Bootstrap Drush with a valid Drupal Directory.
141      *
142      * In this function, the pwd will be moved to the root
143      * of the Drupal installation.
144      *
145      * We also now load the drush.yml for this specific Drupal site.
146      * We can now include files from the Drupal tree, and figure
147      * out more context about the codebase, such as the version of Drupal.
148      */
149     public function bootstrapDrupalRoot()
150     {
151
152         $drupal_root = drush_set_context('DRUSH_DRUPAL_ROOT', drush_bootstrap_value('drupal_root'));
153         chdir($drupal_root);
154         $this->logger->log(LogLevel::BOOTSTRAP, dt("Change working directory to !drupal_root", ['!drupal_root' => $drupal_root]));
155         $version = drush_drupal_version();
156         $major_version = drush_drupal_major_version();
157
158         $core = $this->bootstrapDrupalCore($drupal_root);
159
160         // DRUSH_DRUPAL_CORE should point to the /core folder in Drupal 8+ or to DRUPAL_ROOT
161         // in prior versions.
162         define('DRUSH_DRUPAL_CORE', $core);
163
164         $this->logger->log(LogLevel::BOOTSTRAP, dt("Initialized Drupal !version root directory at !drupal_root", ["!version" => $version, '!drupal_root' => $drupal_root]));
165     }
166
167     /**
168      * VALIDATE the DRUSH_BOOTSTRAP_DRUPAL_SITE phase.
169      *
170      * In this function we determine the URL used for the command,
171      * and check for a valid settings.php file.
172      */
173     public function bootstrapDrupalSiteValidate()
174     {
175     }
176
177     /**
178      * Called by bootstrapDrupalSite to do the main work
179      * of the drush drupal site bootstrap.
180      */
181     public function bootstrapDoDrupalSite()
182     {
183         drush_set_context('DRUSH_URI', $this->uri);
184         $site = drush_set_context('DRUSH_DRUPAL_SITE', drush_bootstrap_value('site'));
185         $confPath = drush_set_context('DRUSH_DRUPAL_SITE_ROOT', drush_bootstrap_value('confPath'));
186
187         $this->logger->log(LogLevel::BOOTSTRAP, dt("Initialized Drupal site !site at !site_root", ['!site' => $site, '!site_root' => $confPath]));
188     }
189
190     /**
191      * Initialize a site on the Drupal root.
192      *
193      * We now set various contexts that we determined and confirmed to be valid.
194      * Additionally we load an optional drush.yml file in the site directory.
195      */
196     public function bootstrapDrupalSite()
197     {
198         $this->bootstrapDoDrupalSite();
199     }
200
201     /**
202      * Initialize and load the Drupal configuration files.
203      */
204     public function bootstrapDrupalConfiguration()
205     {
206     }
207
208     /**
209      * Validate the DRUSH_BOOTSTRAP_DRUPAL_DATABASE phase
210      *
211      * Attempt to make a working database connection using the
212      * database credentials that were loaded during the previous
213      * phase.
214      */
215     public function bootstrapDrupalDatabaseValidate()
216     {
217         // Drupal requires PDO, and Drush requires php 5.6+ which ships with PDO
218         // but PHP may be compiled with --disable-pdo.
219         if (!class_exists('\PDO')) {
220             $this->logger->log(LogLevel::BOOTSTRAP, dt('PDO support is required.'));
221             return false;
222         }
223         try {
224             $sql = SqlBase::create();
225             // Drush requires a database client program during its Drupal bootstrap.
226             $command = $sql->command();
227             if (drush_program_exists($command) === false) {
228                 $this->logger->warning(dt('The command \'!command\' is required for preflight but cannot be found. Please install it and retry.', ['!command' => $command]));
229                 return false;
230             }
231             if (!$sql->query('SELECT 1;', null, drush_bit_bucket())) {
232                 $message = dt("Drush was not able to start (bootstrap) the Drupal database.\n");
233                 $message .= dt("Hint: This may occur when Drush is trying to:\n");
234                 $message .= dt(" * bootstrap a site that has not been installed or does not have a configured database. In this case you can select another site with a working database setup by specifying the URI to use with the --uri parameter on the command line. See `drush topic docs-aliases` for details.\n");
235                 $message .= dt(" * connect the database through a socket. The socket file may be wrong or the php-cli may have no access to it in a jailed shell. See http://drupal.org/node/1428638 for details.\n");
236                 $message .= dt('More information may be available by running `drush status`');
237                 $this->logger->log(LogLevel::BOOTSTRAP, $message);
238                 return false;
239             }
240         } catch (\Exception $e) {
241             $this->logger->log(LogLevel::DEBUG, dt('Unable to validate DB: @e', ['@e' => $e->getMessage()]));
242             return false;
243         }
244         return true;
245     }
246
247     /**
248      * Test to see if the Drupal database has a specified
249      * table or tables.
250      *
251      * This is a bootstrap helper function designed to be called
252      * from the bootstrapDrupalDatabaseValidate() methods of
253      * derived DrupalBoot classes.  If a database exists, but is
254      * empty, then the Drupal database bootstrap will fail.  To
255      * prevent this situation, we test for some table that is needed
256      * in an ordinary bootstrap, and return FALSE from the validate
257      * function if it does not exist, so that we do not attempt to
258      * start the database bootstrap.
259      *
260      * Note that we must manually do our own prefix testing here,
261      * because the existing wrappers we have for handling prefixes
262      * depend on bootstrapping to the "database" phase, and therefore
263      * are not available to validate this same phase.
264      *
265      * @param $required_tables
266      *   Array of table names, or string with one table name
267      *
268      * @return TRUE if all required tables exist in the database.
269      */
270     public function bootstrapDrupalDatabaseHasTable($required_tables)
271     {
272         try {
273             $sql = SqlBase::create();
274             $spec = $sql->getDbSpec();
275             $prefix = isset($spec['prefix']) ? $spec['prefix'] : null;
276             if (!is_array($prefix)) {
277                 $prefix = ['default' => $prefix];
278             }
279             foreach ((array)$required_tables as $required_table) {
280                 $prefix_key = array_key_exists($required_table, $prefix) ? $required_table : 'default';
281                 $table_name = $prefix[$prefix_key] . $required_table;
282                 if (!$sql->alwaysQuery("SELECT 1 FROM $table_name LIMIT 1;", null, drush_bit_bucket())) {
283                     $this->logger->notice('Missing database table: '. $table_name);
284                     return false;
285                 }
286             }
287         } catch (Exception $e) {
288             // Usually the checks above should return a result without
289             // throwing an exception, but we'll catch any that are
290             // thrown just in case.
291             return false;
292         }
293         return true;
294     }
295
296     /**
297      * Boostrap the Drupal database.
298      */
299     public function bootstrapDrupalDatabase()
300     {
301         // We presume that our derived classes will connect and then
302         // either fail, or call us via parent::
303         $this->logger->log(LogLevel::BOOTSTRAP, dt("Successfully connected to the Drupal database."));
304     }
305
306     /**
307      * Attempt to load the full Drupal system.
308      */
309     public function bootstrapDrupalFull()
310     {
311     }
312 }