Updated Drupal to 8.6. This goes with the following updates because it's possible...
[yaffs-website] / vendor / drush / drush / src / Drupal / Commands / core / CliCommands.php
1 <?php
2
3 namespace Drush\Drupal\Commands\core;
4
5 use Drush\Commands\DrushCommands;
6 use Drush\Drush;
7 use Drush\Log\LogLevel;
8 use Drush\Psysh\DrushCommand;
9 use Drush\Psysh\DrushHelpCommand;
10 use Drupal\Component\Assertion\Handle;
11 use Drush\Psysh\Shell;
12 use Psy\Configuration;
13 use Psy\VersionUpdater\Checker;
14 use Webmozart\PathUtil\Path;
15
16 class CliCommands extends DrushCommands
17 {
18
19     /**
20      * Drush's PHP Shell.
21      *
22      * @command docs:repl
23      * @aliases docs-repl
24      * @hidden
25      * @topic
26      */
27     public function docs()
28     {
29         self::printFile(DRUSH_BASE_PATH. '/docs/repl.md');
30     }
31
32     /**
33      * @command php:cli
34      * @description Open an interactive shell on a Drupal site.
35      * @aliases php,core:cli,core-cli
36      * @option $version-history Use command history based on Drupal version
37      *   (Default is per site).
38      * @option $cwd Changes the working directory of the shell
39      *   (Default is the project root directory)
40      * @topics docs:repl
41      * @remote-tty
42      */
43     public function cli(array $options = ['version-history' => false, 'cwd' => null])
44     {
45         $configuration = new Configuration();
46
47         // Set the Drush specific history file path.
48         $configuration->setHistoryFile($this->historyPath($options));
49
50         // Disable checking for updates. Our dependencies are managed with Composer.
51         $configuration->setUpdateCheck(Checker::NEVER);
52
53         $shell = new Shell($configuration);
54
55
56         // Register the assertion handler so exceptions are thrown instead of errors
57         // being triggered. This plays nicer with PsySH.
58         Handle::register();
59         $shell->setScopeVariables(['container' => \Drupal::getContainer()]);
60
61         // Add Drupal 8 specific casters to the shell configuration.
62         $configuration->addCasters($this->getCasters());
63
64         // Add Drush commands to the shell.
65         $shell->addCommands([new DrushHelpCommand()]);
66         $shell->addCommands($this->getDrushCommands());
67
68         // PsySH will never return control to us, but our shutdown handler will still
69         // run after the user presses ^D.  Mark this command as completed to avoid a
70         // spurious error message.
71         drush_set_context('DRUSH_EXECUTION_COMPLETED', true);
72
73         // Run the terminate event before the shell is run. Otherwise, if the shell
74         // is forking processes (the default), any child processes will close the
75         // database connection when they are killed. So when we return back to the
76         // parent process after, there is no connection. This will be called after the
77         // command in preflight still, but the subscriber instances are already
78         // created from before. Call terminate() regardless, this is a no-op for all
79         // DrupalBoot classes except DrupalBoot8.
80         if ($bootstrap = Drush::bootstrap()) {
81             $bootstrap->terminate();
82         }
83
84         // If the cwd option is passed, lets change the current working directory to wherever
85         // the user wants to go before we lift psysh.
86         if ($options['cwd']) {
87             chdir($options['cwd']);
88         }
89
90         $shell->run();
91     }
92
93     /**
94      * Returns a filtered list of Drush commands used for CLI commands.
95      *
96      * @return array
97      */
98     protected function getDrushCommands()
99     {
100         $application = Drush::getApplication();
101         $commands = $application->all();
102
103         $ignored_commands = [
104             'help',
105             'php:cli',
106             'core:cli',
107             'php',
108             'php:eval',
109             'eval',
110             'ev',
111             'php:script',
112             'scr',
113         ];
114         $php_keywords = $this->getPhpKeywords();
115
116         /** @var \Consolidation\AnnotatedCommand\AnnotatedCommand $command */
117         foreach ($commands as $name => $command) {
118             $definition = $command->getDefinition();
119
120             // Ignore some commands that don't make sense inside PsySH, are PHP keywords
121             // are hidden, or are aliases.
122             if (in_array($name, $ignored_commands) || in_array($name, $php_keywords) || ($name !== $command->getName())) {
123                 unset($commands[$name]);
124             } else {
125                 $aliases = $command->getAliases();
126                 // Make sure the command aliases don't contain any PHP keywords.
127                 if (!empty($aliases)) {
128                     $command->setAliases(array_diff($aliases, $php_keywords));
129                 }
130             }
131         }
132
133         return array_map(function ($command) {
134             return new DrushCommand($command);
135         }, $commands);
136     }
137
138     /**
139      * Returns a mapped array of casters for use in the shell.
140      *
141      * These are Symfony VarDumper casters.
142      * See http://symfony.com/doc/current/components/var_dumper/advanced.html#casters
143      * for more information.
144      *
145      * @return array.
146      *   An array of caster callbacks keyed by class or interface.
147      */
148     protected function getCasters()
149     {
150         return [
151         'Drupal\Core\Entity\ContentEntityInterface' => 'Drush\Psysh\Caster::castContentEntity',
152         'Drupal\Core\Field\FieldItemListInterface' => 'Drush\Psysh\Caster::castFieldItemList',
153         'Drupal\Core\Field\FieldItemInterface' => 'Drush\Psysh\Caster::castFieldItem',
154         'Drupal\Core\Config\Entity\ConfigEntityInterface' => 'Drush\Psysh\Caster::castConfigEntity',
155         'Drupal\Core\Config\ConfigBase' => 'Drush\Psysh\Caster::castConfig',
156         'Drupal\Component\DependencyInjection\Container' => 'Drush\Psysh\Caster::castContainer',
157         'Drupal\Component\Render\MarkupInterface' => 'Drush\Psysh\Caster::castMarkup',
158         ];
159     }
160
161     /**
162      * Returns the file path for the CLI history.
163      *
164      * This can either be site specific (default) or Drupal version specific.
165      *
166      * @param array $options
167      *
168      * @return string.
169      */
170     protected function historyPath(array $options)
171     {
172         $cli_directory = Path::join($this->getConfig()->cache(), 'cli');
173         $drupal_major_version = Drush::getMajorVersion();
174
175         // If there is no drupal version (and thus no root). Just use the current
176         // path.
177         // @todo Could use a global file within drush?
178         if (!$drupal_major_version) {
179             $file_name = 'global-' . md5($this->getConfig()->cwd());
180         } // If only the Drupal version is being used for the history.
181         else if ($options['version-history']) {
182             $file_name = "drupal-$drupal_major_version";
183         } // If there is an alias, use that in the site specific name. Otherwise,
184         // use a hash of the root path.
185         else {
186              $aliasRecord = Drush::aliasManager()->getSelf();
187
188             if ($aliasRecord->name()) {
189                 $site_suffix = ltrim($aliasRecord->name(), '@');
190             } else {
191                 $drupal_root = Drush::bootstrapManager()->getRoot();
192                 $site_suffix = md5($drupal_root);
193             }
194
195             $file_name = "drupal-site-$site_suffix";
196         }
197
198         $full_path = "$cli_directory/$file_name";
199
200         $this->logger()->info(dt('History: @full_path', ['@full_path' => $full_path]));
201
202         return $full_path;
203     }
204
205     /**
206      * Returns a list of PHP keywords.
207      *
208      * This will act as a blacklist for command and alias names.
209      *
210      * @return array
211      */
212     protected function getPhpKeywords()
213     {
214         return [
215         '__halt_compiler',
216         'abstract',
217         'and',
218         'array',
219         'as',
220         'break',
221         'callable',
222         'case',
223         'catch',
224         'class',
225         'clone',
226         'const',
227         'continue',
228         'declare',
229         'default',
230         'die',
231         'do',
232         'echo',
233         'else',
234         'elseif',
235         'empty',
236         'enddeclare',
237         'endfor',
238         'endforeach',
239         'endif',
240         'endswitch',
241         'endwhile',
242         'eval',
243         'exit',
244         'extends',
245         'final',
246         'for',
247         'foreach',
248         'function',
249         'global',
250         'goto',
251         'if',
252         'implements',
253         'include',
254         'include_once',
255         'instanceof',
256         'insteadof',
257         'interface',
258         'isset',
259         'list',
260         'namespace',
261         'new',
262         'or',
263         'print',
264         'private',
265         'protected',
266         'public',
267         'require',
268         'require_once',
269         'return',
270         'static',
271         'switch',
272         'throw',
273         'trait',
274         'try',
275         'unset',
276         'use',
277         'var',
278         'while',
279         'xor',
280         ];
281     }
282 }