/**
* 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 {
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) {
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();
- }
- }
-
}
--- /dev/null
+<?php
+
+namespace Civi\PhpStorm;
+
+/**
+ * Utility class for building new metadata files. For example:
+ *
+ * $builder = new PhpStormMetadata('foobar', __CLASS__);
+ * $builder->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);
+ }
+
+}
// 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().
*