Skip to content

Commit

Permalink
Implement Reliese Dependency Container
Browse files Browse the repository at this point in the history
  • Loading branch information
CristianLlanos committed Mar 11, 2021
0 parents commit 07fd8d7
Show file tree
Hide file tree
Showing 5 changed files with 462 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
composer.lock
/vendor
/.idea
30 changes: 30 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"name": "reliese/dependency",
"description": "Dependency Container",
"keywords": ["reliese", "dependency"],
"license": "MIT",
"type": "library",
"authors": [
{
"name": "Cristian Llanos",
"email": "[email protected]"
}
],
"support": {
"issues": "https://github.com/reliese/php-dependency/issues",
"source": "https://github.com/reliese/php-dependency"
},
"require": {
"php": ">=7.2",
"reliese/component-dependency": "^1.0"
},
"require-dev": {
"kahlan/kahlan": "^4.6"
},
"autoload": {
"psr-4": {
"Reliese\\Dependency\\": "src/"
}
},
"prefer-stable": true
}
3 changes: 3 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Reliese Dependency

This is the implementation of Reliese Component Dependency. An actual Dependency Container.
194 changes: 194 additions & 0 deletions spec/Container.spec.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
<?php

use Reliese\Dependency\Container;

describe("Container", function () {
describe("Registered Dependencies", function () {
it("resolves a registered dependency", function () {
$container = new Container();

$container->register(OneSimpleDependency::class, function () {
return new OneSimpleDependency();
});

$resolve = function () use ($container) {
expect($container->resolve(OneSimpleDependency::class))->toBeAnInstanceOf(OneSimpleDependency::class);
};

expect($resolve)->not->toThrow();
});

it("resolves a singleton registered dependency", function () {
$container = new Container();

$container->singleton(OneSimpleDependency::class, function () {
return new OneSimpleDependency();
});

$resolve = function () use ($container) {
$firstInstance = $container->resolve(OneSimpleDependency::class);
expect($firstInstance)->toBeAnInstanceOf(OneSimpleDependency::class);

$secondInstance = $container->resolve(OneSimpleDependency::class);
expect($secondInstance)->toBeAnInstanceOf(OneSimpleDependency::class);

expect($firstInstance)->toBe($secondInstance);
};

expect($resolve)->not->toThrow();
});

it("resolves an abstract dependency to an instantiable dependency", function() {
$container = new Container();

$container->register(RegisteredAbstractDependency::class, function () {
return new AnotherSimpleDependency();
});

$resolve = function () use ($container) {
expect($container->resolve(RegisteredAbstractDependency::class))->toBeAnInstanceOf(AnotherSimpleDependency::class);
};

expect($resolve)->not->toThrow();
});

it("resolves a registered dependency on a method call", function () {
$container = new Container();

$container->register(OneSimpleDependency::class, function () {
return new OneSimpleDependency();
});

$resolve = function () use ($container) {
$object = new OneSimpleDependencyWithMethodDependencies();
expect($container->call($object, 'handle'))->toBeAnInstanceOf(OneSimpleDependency::class);
};

$resolve();

// expect($resolve)->not->toThrow();
});
});

describe("Unregistered Dependencies", function () {
describe("Unresolvable Dependencies", function () {
it("cannot resolve an unregistered abstract dependency", function () {
$container = new Container();

$resolve = function () use ($container) {
$container->resolve(NotRegisteredAbstractDependency::class);
};

expect($resolve)->toThrow();
});

it("cannot resolve a complex dependency when it depends on a not registered interface", function() {
$container = new Container();

$resolve = function () use ($container) {
return $container->resolve(NotResolvableComplexDependency::class);
};

expect($resolve)->toThrow();
});
});

describe("Resolvable Dependencies", function () {
it("resolves a simple dependency", function () {
$container = new Container();

$resolve = function () use ($container) {
expect($container->resolve(OneSimpleDependency::class))->toBeAnInstanceOf(OneSimpleDependency::class);
};

expect($resolve)->not->toThrow();
});

it("resolves a complex dependency", function () {
$container = new Container();

$cases = [
OneComplexDependency::class,
ResolvableComplexDependencyWithDefaultValuesInTheMiddle::class
];

foreach ($cases as $dependency) {
$resolve = function () use ($container, $dependency) {
expect($container->resolve($dependency))->toBeAnInstanceOf($dependency);
};

expect($resolve)->not->toThrow();
}
});

it("resolves a complex dependency when it depends on registered abstract dependencies", function () {
$container = new Container();

$container->register(RegisteredAbstractDependency::class, function () {
return new AnotherSimpleDependency();
});

$resolve = function () use ($container) {
expect($container->resolve(AnotherComplexDependency::class))->toBeAnInstanceOf(AnotherComplexDependency::class);
};

expect($resolve)->not->toThrow();
});

it("resolves a deep complex dependency when it depends on registered abstract dependencies", function () {
$container = new Container();

$container->register(RegisteredAbstractDependency::class, function () {
return new AnotherSimpleDependency();
});

$resolve = function () use ($container) {
$resolved = $container->resolve(DeepComplexDependency::class);
expect($resolved)->toBeAnInstanceOf(DeepComplexDependency::class);
};

expect($resolve)->not->toThrow();
});
});

describe("Dependencies with primitive type params", function () {
it("cannot resolve complex dependencies when it depends on primitive types", function () {
$container = new Container();

$resolve = function () use ($container) {
$container->resolve(UnresolvableComplexDependency::class);
};

expect($resolve)->toThrow();
});

it("can resolve complex dependencies when it depends on optional primitive types", function () {
$container = new Container();

$container->register(RegisteredAbstractDependency::class, function () {
return new AnotherSimpleDependency();
});

$resolve = function () use ($container) {
$resolved = $container->resolve(ResolvableComplexDependency::class);
expect($resolved)->toBeAnInstanceOf(ResolvableComplexDependency::class);
};

expect($resolve)->not->toThrow();
});
});
});
});

interface RegisteredAbstractDependency {}
interface NotRegisteredAbstractDependency {};
class OneSimpleDependency {};
class OneSimpleDependencyWithMethodDependencies { public function handle(OneSimpleDependency $a): OneSimpleDependency { return $a; } };
class AnotherSimpleDependency implements RegisteredAbstractDependency {};
class OneComplexDependency { public function __construct(OneSimpleDependency $a, AnotherSimpleDependency $b) {} };
class AnotherComplexDependency { public function __construct(OneSimpleDependency $a, RegisteredAbstractDependency $b) {} };
class NotResolvableComplexDependency { public function __construct(OneSimpleDependency $a, NotRegisteredAbstractDependency $b) {} };
class DeepComplexDependency { public function __construct(AnotherComplexDependency $a, RegisteredAbstractDependency $b){} };
class UnresolvableComplexDependency { public function __construct(AnotherComplexDependency $a, string $b){} };
class ResolvableComplexDependency { public function __construct(AnotherComplexDependency $a, string $b = "hola"){} };
class ResolvableComplexDependencyWithDefaultValuesInTheMiddle { public function __construct(OneSimpleDependency $a, string $b = "hola", OneSimpleDependency $c){} };
Loading

0 comments on commit 07fd8d7

Please sign in to comment.