/** * @param string $definingFilePath * @param int $definingLineNumber * @param IdentifyingType $IdentifyingType * @param ImplementingType $ImplementingType * @param FactoryFunction $FactoryFunction * @param InitFunction $InitFunction */ public function __construct($definingFilePath, $definingLineNumber, IdentifyingType $IdentifyingType, ImplementingType $ImplementingType = null, FactoryFunction $FactoryFunction = null, InitFunction $InitFunction = null) { $this->definingFilePath = $definingFilePath; $this->definingLineNumber = $definingLineNumber; $this->IdentifyingType = $IdentifyingType->getType(); if ($ImplementingType === null) { $this->ImplementingType = null; } else { if ($ImplementingType->isSameAsIdentifyingType()) { $this->ImplementingType = $this->IdentifyingType; } else { $this->ImplementingType = $ImplementingType->getType(); } } $this->FactoryFunction = $FactoryFunction !== null ? $FactoryFunction->getFactoryFunction() : null; $this->InitFunction = $InitFunction !== null ? $InitFunction->getInitFunction() : null; }
/** * @test */ public function The_getType_method_returns_the_type_passed_to_the_is_method() { // given $Type = Type::fromName('tueena\\spec\\core\\stubs\\IMyService'); // when $ReturnValue = IdentifyingType::is($Type); // then $this->assertSame($Type, $ReturnValue->getType()); }
/** * Defines a service. The service is identified by a type. This can be a class * or an interface. It is implemented by a class, that is an instance of the * identifying type. If both are the same, the second parameter can also be * an instance of ImplementingTypeIsSameAsIdentifyingType. To define a * service, an optional init or/and an optional factory function could be * passed. The factory function is passed as the third parameter, the init * function as fourthe or, if no init function is passed, as third parameter. * * @param IdentifyingType $IdentifyingType * @param IImplementingTypeOrFactoryFunction $ImplementingTypeOrFactoryFunction * @param InitFunction $InitFunction * @return self */ public function add(IdentifyingType $IdentifyingType, IImplementingTypeOrFactoryFunction $ImplementingTypeOrFactoryFunction, InitFunction $InitFunction = null) { $definingFilePath = debug_backtrace()[0]['file']; $definingLineNumber = debug_backtrace()[0]['line']; $Type = $IdentifyingType->getType(); $identifyingTypeName = $Type->getName(); if ($this->has($Type)) { $AlreadyDefinedServiceDefinition = $this->get($Type); $InvalidServiceDefinition = new ServiceDefinition($definingFilePath, $definingLineNumber, $IdentifyingType); $message = 'A service of type ' . $identifyingTypeName . ' has already been defined in ' . $AlreadyDefinedServiceDefinition->getDefiningFilePath() . ' on line ' . $AlreadyDefinedServiceDefinition->getDefiningLineNumber() . '. '; $message .= 'There cannot be defined two services with the same identifying type.'; throw new InvalidServiceDefinition($InvalidServiceDefinition, $message); } if ($ImplementingTypeOrFactoryFunction instanceof ImplementingType) { $ImplementingType = $ImplementingTypeOrFactoryFunction; $FactoryFunction = null; } else { $ImplementingType = null; $FactoryFunction = $ImplementingTypeOrFactoryFunction; } $this->serviceDefinitions[$identifyingTypeName] = new ServiceDefinition($definingFilePath, $definingLineNumber, $IdentifyingType, $ImplementingType, $FactoryFunction, $InitFunction); return $this; }
/** * @test */ public function If_a_service_requires_itself_in_its_init_function_this_is_not_considered_as_circular_reference() { // given $ServiceDefinitions = new ServiceDefinitions(); $ServiceDefinitions->add(IdentifyingType::is(Type::fromName('tueena\\spec\\core\\stubs\\A')), ImplementingType::isTheSame(), InitFunction::is(function (A $A) { })); $Target = new ServiceDefinitionsValidator(); // when, then $Target->validate($ServiceDefinitions); }
public function run() { // Call the Loader configurator. $Loader = new Loader(); $LoaderConfigurator = $this->LoaderConfigurator; $LoaderConfigurator($Loader); // Build the service definitions collection. $ServiceDefinitions = new ServiceDefinitions(); // Call the service definer. $ServiceDefiner = $this->ServiceDefiner; $ServiceDefiner($ServiceDefinitions); // Build the service factory and the injector. $ServiceFactory = new ServiceFactory($ServiceDefinitions); $Injector = new Injector($ServiceFactory); // Register the Injector and the Loader as services. $ServiceFactory->addService(IdentifyingType::is(Type::fromName('tueena\\core\\services\\IInjector')), $Injector)->addService(IdentifyingType::is(Type::fromName('tueena\\core\\ILoader')), $Loader); // Call the main function. $MainFunction = new InjectionTargetClosure($this->MainFunction); $Injector->resolve($MainFunction); }
/** * @param IdentifyingType $IdentifyingType * @param object $ServiceInstance * @return self */ public function addService(IdentifyingType $IdentifyingType, $ServiceInstance) { $this->builtServices[$IdentifyingType->getType()->getName()] = $ServiceInstance; return $this; }
/** * @test */ public function A_servcie_instance_can_be_added() { // given $ServiceDefinitions = new ServiceDefinitions(); $Target = new ServiceFactory($ServiceDefinitions); // when $A = new A(); $Target->addService(IdentifyingType::is(Type::fromName('tueena\\spec\\core\\stubs\\A')), $A); $Injector = new Injector($Target); // then $this->assertSame($A, $Target->getService(Type::fromName('tueena\\spec\\core\\stubs\\A'), $Injector)); }
/** * @test */ public function hasInitFunction_returns_false_if_no_init_function_passed_in() { // given $IdentifyingType = IdentifyingType::is(Type::fromName(__CLASS__)); $ImplementingType = ImplementingType::is(Type::fromName(__CLASS__)); $FactoryFunction = FactoryFunction::is(function () { }); // when $Target = new ServiceDefinition('', 0, $IdentifyingType, $ImplementingType, $FactoryFunction, null); // then $this->AssertTrue($Target->hasFactoryFunction()); $this->AssertFalse($Target->hasInitFunction()); }
/** * @test */ public function The_main_method_is_resolved_by_the_Injector() { // given $loaderConfigurator = function () { }; $serviceDefiner = function (ServiceDefinitions $ServiceDefinitions) { $ServiceDefinitions->add(IdentifyingType::is(Type::fromName('tueena\\spec\\core\\stubs\\IMyService')), ImplementingType::is(Type::fromName('tueena\\spec\\core\\stubs\\MyService'))); }; $passedInServiceInstance = null; $mainFunction = function (IMyService $MyService) use(&$passedInServiceInstance) { $passedInServiceInstance = $MyService; }; $Target = new Application($loaderConfigurator, $serviceDefiner, $mainFunction); // when $Target->run(); // then $this->assertInstanceOf('\\tueena\\spec\\core\\stubs\\MyService', $passedInServiceInstance); }
/** * @test */ public function If_a_service_is_not_defined_with_a_factory_function_the_constructor_of_that_service_gets_injected_with_the_required_services() { // given $serviceDefinitions = new ServiceDefinitions(); $serviceDefinitions->add(IdentifyingType::is(Type::fromName('tueena\\spec\\core\\stubs\\D')), ImplementingType::isTheSame())->add(IdentifyingType::is(Type::fromName('tueena\\spec\\core\\stubs\\E')), ImplementingType::isTheSame()); $ServiceFactory = new ServiceFactory($serviceDefinitions); $Target = new Injector($ServiceFactory); $PropertyDOfE = null; $Closure = function (\tueena\spec\core\stubs\E $E) use(&$PropertyDOfE) { $PropertyDOfE = $E->D; }; // when $Target->resolve(new InjectionTargetClosure($Closure)); // then $this->assertInstanceOf('tueena\\spec\\core\\stubs\\D', $PropertyDOfE); }
/** * @test */ public function The_getAll_method_returns_all_service_definitions() { // given $Target = new ServiceDefinitions(); $Target->add(IdentifyingType::is(Type::fromName('tueena\\spec\\core\\stubs\\IMyService')), ImplementingType::isTheSame())->add(IdentifyingType::is(Type::fromName('tueena\\spec\\core\\stubs\\MyService')), ImplementingType::isTheSame()); // when $result = $Target->getAll(); // then $this->assertEquals(['tueena\\spec\\core\\stubs\\IMyService' => $Target->get(Type::fromName('tueena\\spec\\core\\stubs\\IMyService')), 'tueena\\spec\\core\\stubs\\MyService' => $Target->get(Type::fromName('tueena\\spec\\core\\stubs\\MyService'))], $result); }