config = $config; $this->namespace = $namespace ? : 'Laminas\Di\Generated'; $this->factoryGenerator = new FactoryGenerator($config, $resolver, $this->namespace . '\Factory'); $this->autoloadGenerator = new AutoloadGenerator($this->namespace); $this->logger = $logger ?? new NullLogger(); } private function buildFromTemplate(string $templateFile, string $outputFile, array $replacements): void { $template = file_get_contents($templateFile); assert(is_string($template)); $code = strtr($template, $replacements); $file = new SplFileObject($outputFile, 'w'); $file->fwrite($code); $file->fflush(); } private function generateInjector(): void { $this->buildFromTemplate( self::INJECTOR_TEMPLATE, sprintf('%s/GeneratedInjector.php', $this->outputDirectory), [ '%namespace%' => $this->namespace ? "namespace {$this->namespace};\n" : '', ] ); } private function generateFactoryList(array $factories): void { $indentation = sprintf("\n%s", str_repeat(' ', self::INDENTATION_SPACES)); $codeLines = array_map( fn(string $key, string $value): string => sprintf('%s => %s,', var_export($key, true), var_export($value, true)), array_keys($factories), $factories ); $this->buildFromTemplate(self::FACTORY_LIST_TEMPLATE, sprintf('%s/factories.php', $this->outputDirectory), [ '%factories%' => implode($indentation, $codeLines), ]); } private function generateTypeFactory(string $class, array &$factories): void { if (isset($factories[$class])) { return; } $this->logger->debug(sprintf('Generating factory for class "%s"', $class)); try { $factory = $this->factoryGenerator->generate($class); if ($factory) { $factories[$class] = $factory; } } catch (Throwable $e) { $this->logger->error(sprintf( 'Could not create factory for "%s": %s', $class, $e->getMessage() )); } } private function generateAutoload(): void { $addFactoryPrefix = fn($value) => 'Factory/' . $value; $classmap = array_map($addFactoryPrefix, $this->factoryGenerator->getClassmap()); $classmap[$this->namespace . '\\GeneratedInjector'] = 'GeneratedInjector.php'; $this->autoloadGenerator->generate($classmap); } /** * Returns the namespace this generator uses */ public function getNamespace(): string { return $this->namespace; } /** * Generate the injector * * This will generate the injector and its factories into the output directory * * @param class-string[] $classes */ public function generate($classes = []): void { $this->ensureOutputDirectory(); $this->factoryGenerator->setOutputDirectory($this->outputDirectory . '/Factory'); $this->autoloadGenerator->setOutputDirectory($this->outputDirectory); $factories = []; foreach ($classes as $class) { $this->generateTypeFactory($class, $factories); } foreach ($this->config->getConfiguredTypeNames() as $type) { $this->generateTypeFactory($type, $factories); } $this->generateAutoload(); $this->generateInjector(); $this->generateFactoryList($factories); } }