public function testCreatingDefinitions() { $builder = new DefinitionBuilder(new ParameterBuilder()); $builder->addDefinition(Car::class)->defineConstructor()->defineParameter('driver')->defineDependency(new ClassReference(SlowDriver::class))->end()->end()->end(); $compiler = new DefinitionCompiler(new DefinitionGenerator(new ClassGenerator()), $this->getAnalyzer()); $list = $this->callMethod('getClassDependencies', $compiler, [$builder]); $this->callMethod('generateDefinitions', $compiler, [$builder, $list]); static::assertCount(2, $builder->getDefinitionCollection()); }
/** * Analyze definition builder * * @param DefinitionBuilder $definitionBuilder * @throws ParameterNotFoundException * @return bool */ public function analyze(DefinitionBuilder $definitionBuilder) : bool { $isAnalyzed = false; // Analyze class definitions foreach ($definitionBuilder->getDefinitionCollection() as $classDefinition) { // Analyze only not analyzed classes if (!$classDefinition->isAnalyzed()) { // Get reflection $reflectionClass = new \ReflectionClass($classDefinition->getClassName()); // Analyze class $this->analyzeClass($classDefinition, $reflectionClass); // Analyze properties $this->analyzeProperty($reflectionClass, $classDefinition); // Analyze methods $this->analyzeMethod($reflectionClass, $classDefinition); // Class was analyzed $classDefinition->setIsAnalyzed(true); // Do not analyze this definition $isAnalyzed = true; } } return $isAnalyzed; }
/** * Compile and get container * * @param DefinitionBuilder $definitionBuilder * @return string Get container code * @throws ReferenceNotImplementsException * @throws \InvalidArgumentException */ public function generateClass(DefinitionBuilder $definitionBuilder) : string { // Generate parameters if exists if (count($definitionBuilder->getParameterCollection())) { $parameterMethodGenerator = $this->generator->defMethod('parameter')->defProtected()->defArgument('parameterName'); $isFirstCondition = true; // Generate parameters foreach ($definitionBuilder->getParameterCollection() as $parameterName => $reference) { $parameterMethodGenerator->defLine($this->generateParameterCondition($parameterName, $reference, $isFirstCondition)); $isFirstCondition = false; } // Close method $parameterMethodGenerator->end(); } $methodGenerator = $this->generator->defMethod('logic')->defProtected()->defArgument('classNameOrServiceName')->defLine('static $singletonCollection = [];'); $scopes = []; $isFirstCondition = true; /** @var ClassDefinition $classDefinition */ foreach ($definitionBuilder->getDefinitionCollection() as $classDefinition) { // Get scopes foreach ($classDefinition->getScopes() as $scope) { $id = $scope::getId(); if (!array_key_exists($id, $scopes)) { $scopes[$id] = []; } // Store definition id $scopes[$id][] = $classDefinition->getServiceName() ?: $classDefinition->getClassName(); } $className = $classDefinition->getClassName(); $serviceName = $classDefinition->getServiceName(); // Name for static service collection $serviceId = $serviceName ?? $className; // Generate if condition by class name or value $methodGenerator->defLine($this->generateStartIfCondition($isFirstCondition, $className, $serviceName)); // Generate static property service access if service is singleton // TODO Move this from if condition if ($classDefinition->isSingleton()) { $methodGenerator->defLine($this->generateStaticFunctionCall($serviceId)); } // Generate constructor call if not $methodGenerator->defLine($this->generateConstructor($classDefinition)); // Generate methods foreach ($classDefinition->getMethodsCollection() as $methodDefinition) { // Constructor is not a method skip it if ($methodDefinition->getMethodName() !== '__construct') { $methodGenerator->defLine($this->generateSetters($classDefinition, $methodDefinition)); } } // Generate properties foreach ($classDefinition->getPropertiesCollection() as $propertyDefinition) { // Generate properties $methodGenerator->defLine($this->generateProperty($classDefinition, $propertyDefinition)); } // Generate return operator $methodGenerator->defLine($this->generateReturnOperator($classDefinition, $serviceId)); // Close if $methodGenerator->defLine($this->generateEndIfCondition()); $isFirstCondition = false; } // Generate if condition by class name or value $methodGenerator->defLine($this->generateStartIfCondition(false, '\\' . $this->generator->getNamespace() . '\\' . $this->generator->getClassName(), self::CONTAINER_DEPENDENCY_NAME)); // Return container $methodGenerator->defLine("\treturn \$this;"); // Close if $methodGenerator->defLine($this->generateEndIfCondition()); // Close method $methodGenerator->end(); // Generate constructor $constructorGenerator = $this->generator->defMethod('__construct'); // Generate scope list $this->generateScopeList($constructorGenerator, $scopes); // Close constructor $constructorGenerator->end(); return "<?php \n" . $this->generator->code(); }
/** * Get class dependencies form definition builder * * @param DefinitionBuilder $definitionBuilder * @return array * @throws ImplementerForTypeNotFoundException */ protected function getClassDependencies(DefinitionBuilder $definitionBuilder) : array { $dependencyList = []; // Get dependencies which will be used for generation definitions foreach ($definitionBuilder->getDefinitionCollection() as $classDefinition) { // if (!$classDefinition->isAnalyzed()) { // Iterate properties and get their dependencies foreach ($classDefinition->getPropertiesCollection() as $propertyDefinition) { // Add dependency to list if valid $this->addDependency($definitionBuilder, $dependencyList, $propertyDefinition->getDependency(), $propertyDefinition); } foreach ($classDefinition->getMethodsCollection() as $methodDefinition) { foreach ($methodDefinition->getParametersCollection() as $parameterDefinition) { $this->addDependency($definitionBuilder, $dependencyList, $parameterDefinition->getDependency(), $parameterDefinition); } } // } } return $dependencyList; }