From 478fc33bad5c0b64e0f2f5e5cf0f726599439d05 Mon Sep 17 00:00:00 2001 From: Tim Otten Date: Fri, 25 Aug 2023 15:52:00 -0700 Subject: [PATCH] (REF) Extract helper PhpStormMetadata --- .../Civi/PhpStorm/PhpStormCompilePass.php | 31 +------ .../Civi/PhpStorm/PhpStormMetadata.php | 92 +++++++++++++++++++ tools/extensions/phpstorm/phpstorm.php | 14 +++ 3 files changed, 110 insertions(+), 27 deletions(-) create mode 100644 tools/extensions/phpstorm/Civi/PhpStorm/PhpStormMetadata.php diff --git a/tools/extensions/phpstorm/Civi/PhpStorm/PhpStormCompilePass.php b/tools/extensions/phpstorm/Civi/PhpStorm/PhpStormCompilePass.php index 8d108c150d..debe9f8d5e 100644 --- a/tools/extensions/phpstorm/Civi/PhpStorm/PhpStormCompilePass.php +++ b/tools/extensions/phpstorm/Civi/PhpStorm/PhpStormCompilePass.php @@ -7,8 +7,6 @@ use Symfony\Component\DependencyInjection\ContainerBuilder; /** * Generate metadata about dynamic CiviCRM services for use by PhpStorm. - * - * @link https://www.jetbrains.com/help/phpstorm/2021.3/ide-advanced-metadata.html */ class PhpStormCompilePass implements CompilerPassInterface { @@ -21,17 +19,12 @@ class PhpStormCompilePass implements CompilerPassInterface { return; } - // Not 100% sure which is better. These trade-off in edge-cases of writability and readability. - // - '[civicrm.files]/.phpstorm.meta.php' - // - '[civicrm.compile]/.phpstorm.meta.php' - // - '[civicrm.root]/.phpstorm.meta.php' - $file = \Civi::paths()->getPath('[civicrm.files]/.phpstorm.meta.php'); - - $data = static::renderMetadata(static::findServices($container)); - file_put_contents($file, $data); + $builder = new PhpStormMetadata('services', __CLASS__); + $builder->addOverrideMap('\Civi::service()', $this->findServices($container)); + $builder->write(); } - private static function findServices(ContainerBuilder $c): array { + private function findServices(ContainerBuilder $c): array { $aliases = $c->getAliases(); $services = []; foreach ($c->getServiceIds() as $serviceId) { @@ -50,20 +43,4 @@ class PhpStormCompilePass implements CompilerPassInterface { return $services; } - private static function renderMetadata(array $services): string { - ob_start(); - try { - printf('<' . "?php\n"); - printf("namespace PHPSTORM_META {\n"); - printf("override(\Civi::service(), map(\n"); - echo str_replace('\\\\', '\\', var_export($services, 1)); - // PhpStorm 2022.3.1: 'Civi\\Foo' doesn't work, but 'Civi\Foo' does. - printf(");\n"); - printf("}\n"); - } - finally { - return ob_get_clean(); - } - } - } diff --git a/tools/extensions/phpstorm/Civi/PhpStorm/PhpStormMetadata.php b/tools/extensions/phpstorm/Civi/PhpStorm/PhpStormMetadata.php new file mode 100644 index 0000000000..854e8643ef --- /dev/null +++ b/tools/extensions/phpstorm/Civi/PhpStorm/PhpStormMetadata.php @@ -0,0 +1,92 @@ +addOverrideMap('\Foo::bar()', ['gee' => '\Whiz\Bang']); + * $builder->write(); + * + * @link https://www.jetbrains.com/help/phpstorm/2021.3/ide-advanced-metadata.html + */ +class PhpStormMetadata { + + /** + * Short symbolic name. Maps to filename. + * + * @var string + */ + protected $name; + + /** + * The party responsible for building this thing. + * + * @var string + */ + protected $attribution; + + /** + * @var string + */ + protected $buffer; + + /** + * @param string $name + * Short symbolic name. This will be used in the filename. + * @param string $attribution + * The party responsible for running this builder. If someone finds buggy, where should they look first? + */ + public function __construct(string $name, string $attribution) { + $this->name = $name; + $this->attribution = $attribution; + $this->buffer = ''; + } + + /** + * @param string $for + * @param array $map + * Array(string $parameterId => string $className) + * + * @return $this + */ + public function addOverrideMap(string $for, array $map) { + // PhpStorm 2022.3.1: 'Civi\\Foo' doesn't work, but 'Civi\Foo' does. + $mapData = str_replace('\\\\', '\\', var_export($map, 1)); + $this->buffer .= "override($for, map(\n$mapData));\n"; + return $this; + } + + /** + * Write the metadata to its file. + * + * @return void + */ + public function write(): void { + $path = phpstorm_metadata_dir(); + + if (file_exists($path) && !is_dir($path)) { + unlink($path); + } + if (!file_exists($path)) { + mkdir($path); + } + + if (!preg_match(';^[-a-zA-Z0-9]+$;', $this->name)) { + throw new \RuntimeException("Malformed name for metadata file"); + } + $file = $path . DIRECTORY_SEPARATOR . $this->name . '.php'; + + $lines = []; + $lines[] = "<" . "?php"; + $lines[] = sprintf("// Generated by %s at %s", $this->attribution, date('Y-m-d H:i:s')); + $lines[] = "namespace PHPSTORM_META {\n"; + $lines[] = $this->buffer; + $lines[] = "}"; + + $content = implode("\n", $lines) . "\n"; + file_put_contents($file, $content); + } + +} diff --git a/tools/extensions/phpstorm/phpstorm.php b/tools/extensions/phpstorm/phpstorm.php index 71a5085f44..d778d90eaa 100644 --- a/tools/extensions/phpstorm/phpstorm.php +++ b/tools/extensions/phpstorm/phpstorm.php @@ -6,6 +6,20 @@ // phpcs:enable use Symfony\Component\DependencyInjection\Compiler\PassConfig; +/** + * Determine the folder where we will store PhpStorm metadata files. + * + * Not 100% sure which is best. These options trade-off in edge-cases of writability and readability: + * - '[civicrm.files]/.phpstorm.meta.php' + * - '[civicrm.compile]/.phpstorm.meta.php' + * - '[civicrm.root]/.phpstorm.meta.php' + * + * @return string + */ +function phpstorm_metadata_dir(): string { + return \Civi::paths()->getPath('[civicrm.files]/.phpstorm.meta.php'); +} + /** * Implements hook_civicrm_config(). * -- 2.25.1