Skip to content

Commit

Permalink
Merge pull request #18 from filecage/#13-configurable-uninstantiable-…
Browse files Browse the repository at this point in the history
…factory

Removes uninstantiable factory
  • Loading branch information
filecage authored Jul 1, 2019
2 parents 1ed6c4b + 2d53a8a commit c01ec50
Show file tree
Hide file tree
Showing 12 changed files with 8 additions and 232 deletions.
12 changes: 2 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,6 @@ Injecting instances is supported as well.
If you have resources that can not be created without additional logic, but also should only be created once another component depends them, you can register a factory for this factory.
A factory can be a callable, an instance of `Creator\Interfaces\Factory` or a class string of a Factory (see [lazy bound factories](#lazy-bound-factories)) and can be registered for any class resource, i.e. interfaces, abstracts or normal classes.

*Please note* that factory classes share the interface with Factories for [uninstantiable class factories](#uninstantiable-classes) but are different features and are being called at different points in the creation order.

### Global Factories
````php
<?php
Expand Down Expand Up @@ -216,15 +214,9 @@ In the example above, the instances of `ArbitraryClassWithSimpleClassDependency`
## Uninstantiable Classes
### Singletons
Singletons can be resolved if they implement the `Creator\Interfaces\Singleton` interface.
### Abstracts, Interfaces
If Creator stumbles upon an interface or an abstract class, it will try to:

1. Look up the resource registry if any resource implements the interface / abstract class. First one is being served.
2. Look up a factory by using the entities name + "Factory", i.e. the factory of `Foo\Bar\MyInterface` is `Foo\Bar\MyInterfaceFactory`

#### Additional notes on Factory classes
* A factory has to implement the `Creator\Interfaces\Factory` interface
* Factories are being created via `Creator::create` and thus may require further dependencies
### Abstracts, Interfaces
If Creator stumbles upon an interface or an abstract class, it will try to look up the resource registry if any resource implements the interface / abstract class. First one is being served.

## Registering Resources
### Classes
Expand Down
49 changes: 6 additions & 43 deletions lib/Creation.php
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,13 @@ private function createInstanceFromUninstantiableCreatable (Creatable $creatable
if ($reflector->implementsInterface(Interfaces\Singleton::class)) {
return $this->getInstanceFromSingleton($reflector);
} elseif ($reflector->isInterface() || $reflector->isAbstract()) {
return $this->findsFulfillngInstanceForUninstantiableCreatable($creatable) ?? $this->createInstanceFromFactoryCreatable($creatable, $this->getFactoryClassCreatable($reflector));
} else {
throw new Unresolvable('Class is neither instantiable nor implements Singleton interface', $reflector->getName());
$instance = $this->findsFulfillngInstanceForUninstantiableCreatable($creatable);
if ($instance !== null) {
return $instance;
}
}

throw new Unresolvable('Class is neither instantiable nor implements Singleton interface', $reflector->getName());
}

/**
Expand All @@ -138,30 +141,6 @@ private function createInstanceFromCreatable (Creatable $creatable) {
return (new Invocation($creatable, $this->resourceRegistry, $this->injectionRegistry))->invoke();
}

/**
* @param Creatable $creatable
* @param Creatable $factory
*
* @return object
* @throws Unresolvable
*/
private function createInstanceFromFactoryCreatable (Creatable $creatable, Creatable $factory) {
$factoryReflector = $factory->getReflectionClass();
$reflector = $creatable->getReflectionClass();

$factory = $this->createInstance($factory);
if (!$factory instanceof Factory) {
throw new Unresolvable('Factory `' . $factoryReflector->getName() . '` does not implement required interface Creator\\Interfaces\\Factory', $reflector->getName());
}

$class = $factory->createInstance();
if (!$reflector->isInstance($class)) {
throw new Unresolvable('Create method of factory `' . $factoryReflector->getName() . '` did not return instance of `' . $reflector->getName() . '` class', $reflector->getName());
}

return $class;
}

/**
* @param ReflectionClass $reflector
*
Expand All @@ -179,20 +158,4 @@ private function findsFulfillngInstanceForUninstantiableCreatable (Creatable $cr
return $this->injectionRegistry->findFulfillingInstance($creatable) ?? $this->resourceRegistry->findFulfillingInstance($creatable);
}

/**
* @param ReflectionClass $reflector
*
* @return Creatable
* @throws Unresolvable
*/
private function getFactoryClassCreatable (ReflectionClass $reflector) {
$className = $reflector->getName();
try {
$factoryCreatable = new FactoryCreatable($className);
} catch (ReflectionException $e) {
throw new Unresolvable('Can not load factory for uninstantiable class `' . $className . '`: ' . $e->getMessage(), $reflector->getName());
}

return $factoryCreatable;
}
}
24 changes: 0 additions & 24 deletions lib/FactoryCreatable.php

This file was deleted.

16 changes: 0 additions & 16 deletions tests/ExceptionsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
use Creator\Exceptions\Unresolvable;
use Creator\Exceptions\UnresolvableDependency;
use Creator\Tests\Mocks\InvalidClass;
use Creator\Tests\Mocks\InvalidFactoryInstanceTestUninstantiableClass;
use Creator\Tests\Mocks\InvalidFactoryTestUninstantiableClass;
use Creator\Tests\Mocks\InvalidNestedRequirementClass;
use Creator\Tests\Mocks\InvalidPrimitiveDependencyClass;
use Creator\Tests\Mocks\InvalidRequirementClass;
Expand All @@ -29,20 +27,6 @@ function testShouldThrowExceptionIfClassRequiresInexistentDependency () {
$this->creator->create(InvalidRequirementClass::class);
}

function testShouldThrowExceptionIfFactoryDoesNotImplementInterface () {
$this->expectException(Unresolvable::class);
$this->expectExceptionMessageRegExp('/^Factory `\S+` does not implement required interface/');

$this->creator->create(InvalidFactoryTestUninstantiableClass::class);
}

function testShouldThrowExceptionIfFactoryDoesNotReturnRequestedInstance () {
$this->expectException(Unresolvable::class);
$this->expectExceptionMessageRegExp('/^Create method of factory `\S+` did not return instance/');

$this->creator->create(InvalidFactoryInstanceTestUninstantiableClass::class);
}

function testShouldThrowExceptionIfClassRequiresUnknownPrimitiveResource () {
$this->expectException(UnresolvableDependency::class);
$this->expectExceptionMessage('`Creator\Tests\Mocks\InvalidPrimitiveDependencyClass::__construct()` demands a primitive resource for parameter `$unknownParameter` but the resource is unresolvable');
Expand Down
5 changes: 0 additions & 5 deletions tests/Mocks/InvalidFactoryInstanceTestUninstantiableClass.php

This file was deleted.

This file was deleted.

5 changes: 0 additions & 5 deletions tests/Mocks/InvalidFactoryTestUninstantiableClass.php

This file was deleted.

9 changes: 0 additions & 9 deletions tests/Mocks/InvalidFactoryTestUninstantiableClassFactory.php

This file was deleted.

41 changes: 0 additions & 41 deletions tests/Mocks/MoreExtendedInterfaceFactory.php

This file was deleted.

16 changes: 0 additions & 16 deletions tests/Mocks/SimpleAbstractClassFactory.php

This file was deleted.

13 changes: 0 additions & 13 deletions tests/Mocks/SimpleInterfaceFactory.php

This file was deleted.

39 changes: 0 additions & 39 deletions tests/UninstantiableCreationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,51 +2,12 @@

namespace Creator\Tests;

use Creator\Tests\Mocks\ExtendedClass;
use Creator\Tests\Mocks\ExtendedInterface;
use Creator\Tests\Mocks\SimpleAbstractClass;
use Creator\Tests\Mocks\SimpleClass;
use Creator\Tests\Mocks\SimpleInterface;
use Creator\Tests\Mocks\SimpleSingleton;
use Creator\Tests\Mocks\UninstantiableInterface;
use Creator\Tests\Mocks\UninstantiableSupplier;

class UninstantiableCreationTest extends AbstractCreatorTest {

function testExpectsInstanceFromSingleton () {
$this->assertInstanceOf(SimpleSingleton::class, $this->creator->create(SimpleSingleton::class));
}

function testExpectsInstanceFromUninstantiableInterface () {
$this->assertInstanceOf(SimpleInterface::class, $this->creator->create(SimpleInterface::class));
}

function testExpectsInstanceFromUninstantiableAbstractClass () {
$this->assertInstanceOf(SimpleAbstractClass::class, $this->creator->create(SimpleAbstractClass::class));
}

function testExpectsInstanceFromFactoryWithDependencies () {
$this->assertInstanceOf(ExtendedClass::class, $this->creator->create(ExtendedInterface::class));
}

function testExpectsFactoryInstanceCreatedWithInjectedInstance () {
$simpleInstance = new SimpleClass();
/** @var ExtendedInterface $extendedInstance */
$extendedInstance = $this->creator->createInjected(ExtendedInterface::class)
->with($simpleInstance)
->create();

$this->assertInstanceOf(ExtendedInterface::class, $extendedInstance);
$this->assertInstanceOf(ExtendedClass::class, $extendedInstance);
$this->assertSame($simpleInstance, $extendedInstance->getSimpleClass());
}

function testExpectsSupplierInstanceWhenDependingUninstantiable () {
$supplierInstance = new UninstantiableSupplier();
$this->creator->registerClassResource($supplierInstance);

$this->assertSame($supplierInstance, $this->creator->create(UninstantiableInterface::class));
$this->assertSame($supplierInstance, $this->creator->create(UninstantiableSupplier::class));
}

}

0 comments on commit c01ec50

Please sign in to comment.