classMapGenerator = $generator; $this->classNameResolver = $resolver; $this->classDir = dirname(dirname(__DIR__)); } /** * @return array */ public function getClassMap() { if (!empty($this->classMap)) { return $this->classMap; } $this->classMap = $this->classMapGenerator->generate($this->classDir); return $this->classMap; } /** * @return array */ public function getServices() { if (!empty($this->services)) { return $this->services; } $classNames = $this->getBootstrapClassNames(); foreach ($classNames as $className) { if (empty($className)) { continue; } if (!class_exists($className, true)) { $this->loadClass($className); } if (!method_exists($className, 'registerServices')) { continue; } $services = forward_static_call([$className, 'registerServices']); foreach ($services as $serviceName => $factoryMethod) { $this->addServiceDefinition($serviceName, $className, $factoryMethod); } } return $this->services; } /** * @throws RuntimeException * * @return SchemaCollection */ public function getTableSchemas(): SchemaCollection { $schemaCollection = new SchemaCollection(); $classNames = $this->getBootstrapClassNames(); foreach ($classNames as $className) { if (empty($className)) { continue; } if (!class_exists($className, true)) { $this->loadClass($className); } if (!method_exists($className, 'registerTableSchemas')) { continue; } forward_static_call([$className, 'registerTableSchemas'], $schemaCollection); } return $schemaCollection; } /** * @return array */ public function getJavascriptFiles() { $classNames = $this->getBootstrapClassNames(); foreach ($classNames as $className) { if (!class_exists($className, true)) { continue; } if (!method_exists($className, 'registerJavascript')) { continue; } $javascript = forward_static_call([$className, 'registerJavascript']); foreach ($javascript as $cacheName => $jsFiles) { $this->addJavascriptDefinition($cacheName, $jsFiles); } } return $this->javascript; } /** * @return array Absolute paths to all bootstrap files */ private function getBootstrapFiles() { $directory = new RecursiveDirectoryIterator($this->classDir); $iterator = new RecursiveIteratorIterator($directory); $bootstraps = new RegexIterator($iterator, '/^.+Bootstrap\.php$/', RegexIterator::MATCH); $files = []; /** @var \SplFileInfo $bootstrap */ foreach ($bootstraps as $bootstrap) { $files[] = $bootstrap->getRealPath(); } return $files; } /** * @return array FQCN of all bootstrap classes */ private function getBootstrapClassNames() { if (!empty($this->bootstrapClasses)) { return $this->bootstrapClasses; } $files = $this->getBootstrapFiles(); foreach ($files as $file) { $className = $this->classNameResolver->resolveClassName($file); if ($className === null) { continue; } $this->bootstrapClasses[] = $className; } return $this->bootstrapClasses; } /** * @param string $serviceName * @param string $bootstrapClass * @param string $factoryMethod * * @return void */ private function addServiceDefinition($serviceName, $bootstrapClass, $factoryMethod) { if (isset($this->services[$serviceName])) { $registeredCallString = $this->services[$serviceName][0] . '::' . $this->services[$serviceName][1]; $failedCallString = $bootstrapClass . '::' . $factoryMethod; throw new RuntimeException(sprintf( 'Service "%s" can not be registered. Name is already taken. Registered "%s" - Failed "%s"', $serviceName, $registeredCallString, $failedCallString )); } $this->services[$serviceName] = [$bootstrapClass, $factoryMethod]; } /** * @param $cacheName * @param $files * * @return void */ private function addJavascriptDefinition($cacheName, $files) { $this->javascript[$cacheName] = $files; } /** * @param string $className * * @throws RuntimeException * * @return void */ private function loadClass($className) { if (empty($className)) { return; } if (empty($this->classMap)) { $this->getClassMap(); } if (!isset($this->classMap[$className])) { throw new RuntimeException(sprintf( 'Could not load class "%s"', $className )); } include $this->classMap[$className]; } }