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