Skip to content

Commit

Permalink
Add storage for resolved objects. Tests refactoring, add new cases in…
Browse files Browse the repository at this point in the history
… unit tests
  • Loading branch information
renakdup committed Nov 28, 2023
1 parent cb87af7 commit 852808d
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 69 deletions.
15 changes: 12 additions & 3 deletions src/Container.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,20 +75,29 @@ interface NotFoundExceptionInterface extends ContainerExceptionInterface {}
class Container implements ContainerInterface {
protected array $services = [];

protected array $resolved_services = [];

public function set( string $id, $service ): void {
$this->services[ $id ] = $service;
unset( $this->resolved_services[ $id ] );
}

/**
* {@inheritdoc}
*/
public function get( string $id ) {
if ( isset( $this->resolved_services[ $id ] ) || array_key_exists( $id, $this->resolved_services ) ) {
return $this->resolved_services[ $id ];
}

$resolved_service = $this->resolve_service( $this->has( $id ) ? $this->services[ $id ] : $id );

$this->resolved_services[ $id ] = $resolved_service;

return $resolved_service;
}

private function resolve_service( $service ) {
protected function resolve_service( $service ) {
if ( $service instanceof Closure ) {
return $service( $this );
} elseif ( is_object( $service ) ) {
Expand All @@ -115,7 +124,7 @@ private function resolve_service( $service ) {
continue;
}

$constructor_args[] = $this->resolve_service( $param_class->getName() );
$constructor_args[] = $this->get( $param_class->getName() );
continue;
}

Expand Down Expand Up @@ -143,7 +152,7 @@ private function resolve_service( $service ) {
* @inheritdoc
*/
public function has( string $id ): bool {
return isset( $this->services[ $id ] ) || array_key_exists( $id, $this->services );
return array_key_exists( $id, $this->services );
}
}

Expand Down
14 changes: 14 additions & 0 deletions tests/Assets/ClassWithConstructor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

declare( strict_types=1 );

namespace PisarevskiiTests\SimpleDIC\Assets;

class ClassWithConstructor {

public ClassWithConstructorPrimitives $obj_with_constructor_deps;

public function __construct( ClassWithConstructorPrimitives $obj_with_constructor_deps ) {
$this->obj_with_constructor_deps = $obj_with_constructor_deps;
}
}
14 changes: 0 additions & 14 deletions tests/Assets/ClassWithConstructorDeps2.php

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,18 @@

namespace PisarevskiiTests\SimpleDIC\Assets;

class ClassWithConstructorDeps {
class ClassWithConstructorPrimitives {

private SimpleClass $simple_class;
public SimpleClass $simple_class;

private array $array;
private string $string;
private int $number;
public array $array;
public string $string;
public int $number;

/**
* @var null
*/
private $null;
public $null;

public function __construct(
SimpleClass $simple_class,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

namespace PisarevskiiTests\SimpleDIC\Assets;

class ClassInvocable {
class InvocableClass {

private SimpleClass $simple_class;
public SimpleClass $simple_class;

public function __construct(SimpleClass $simple_class) {
$this->simple_class = $simple_class;
Expand Down
112 changes: 68 additions & 44 deletions tests/ContainerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@
use PHPUnit\Framework\TestCase;
use Pisarevskii\SimpleDIC\Container;
use Pisarevskii\SimpleDIC\ContainerException;
use Pisarevskii\SimpleDIC\ContainerInterface;
use Pisarevskii\SimpleDIC\ContainerNotFoundException;
use PisarevskiiTests\SimpleDIC\Assets\ClassInvocable;
use PisarevskiiTests\SimpleDIC\Assets\ClassWithConstructorDeps;
use PisarevskiiTests\SimpleDIC\Assets\ClassWithConstructorDeps2;
use PisarevskiiTests\SimpleDIC\Assets\InvocableClass;
use PisarevskiiTests\SimpleDIC\Assets\ClassWithConstructorPrimitives;
use PisarevskiiTests\SimpleDIC\Assets\ClassWithConstructor;
use PisarevskiiTests\SimpleDIC\Assets\ClassWithConstructorDepsException;
use PisarevskiiTests\SimpleDIC\Assets\StaticClass;
use PisarevskiiTests\SimpleDIC\Assets\SimpleClass;
Expand Down Expand Up @@ -48,26 +49,17 @@ public function test_get__primitives() {
self::assertSame( $value, $this->container->get( $name ) );
}

public function test_get__class() {
$this->container->set( $name = 'service', $value = new stdClass() );
self::assertSame( $value, $this->container->get( $name ) );
}

public function test_get__not_set_class() {
self::assertEquals( new SplQueue(), $this->container->get( SplQueue::class ) );
}

public function test_get__callback() {
$this->container->set( $name = 'service', function () {
return new stdClass();
} );
self::assertEquals( new stdClass(), $this->container->get( $name ) );
}

public function test_get__callback_pass_params() {
public function test_get__pass_container_parameter() {
$this->container->set( 'id', $value1 = 100 );
$this->container->set( 'title', $value2 = 'Title of article' );
$this->container->set( $service = 'service', function ( $c ) {
$this->container->set( $service = 'service', function ( ContainerInterface $c ) {
$obj = new stdClass();
$obj->id = $c->get( 'id' );
$obj->title = $c->get( 'title' );
Expand All @@ -81,6 +73,11 @@ public function test_get__callback_pass_params() {
self::assertEquals( $expected, $this->container->get( $service ) );
}

public function test_get__object() {
$this->container->set( $name = 'service', $value = new stdClass() );
self::assertSame( $value, $this->container->get( $name ) );
}

public function test_get__object_from_class() {
$this->container->set( $name = 'service', SimpleClass::class );
self::assertEquals( new SimpleClass(), $this->container->get( $name ) );
Expand All @@ -89,62 +86,89 @@ public function test_get__object_from_class() {
self::assertEquals( new SimpleClass(), $this->container->get( $name2 ) );
}

// //TODO:: need to add supporting
// public function test_get__singleton() {
// $this->container->set( $name = 'service', function () {
// $obj = new stdClass();
// $obj->title = 'first title';
// return $obj;
// }, true );
// self::assertObjectHasProperty( 'title', $this->container->get( $name ) );
// self::assertSame( 'first title', $this->container->get( $name )->title );
//
// $service = $this->container->get( $name );
// $service->title = 'New title';
//
// self::assertObjectHasProperty( 'changed title', $this->container->get( $name ) );
// }
public function test_get__create_not_bound_service() {
self::assertEquals( new SimpleClass(), $this->container->get( SimpleClass::class ) );
}

public function test_get__check_singleton_for_not_bounded() {
self::assertSame(
$this->container->get( SimpleClass::class ),
$this->container->get( SimpleClass::class )
);
}

public function test_get__check_changing_singleton_property() {
$this->container->set( $name = 'service', function () {
$obj = new stdClass();
$obj->title = 'first title';

return $obj;
} );

$service = $this->container->get( $name );
$service->title = 'changed title';

public function test_get__autowiring_for_bind() {
self::assertObjectHasProperty( 'title', $this->container->get( $name ) );
self::assertSame( 'changed title', $this->container->get( $name )->title );
}

public function test_get__singleton_for_resolved_child_dependencies() {
/**
* @var $obj1 ClassWithConstructor
*/
$obj1 = $this->container->get( ClassWithConstructor::class );

self::assertSame(
$obj1->obj_with_constructor_deps->simple_class,
$this->container->get( SimpleClass::class )
);
}

public function test_get__autowiring() {
$obj1 = new SimpleClass();
$this->container->set( $name = SimpleClass::class, SimpleClass::class );
self::assertEquals( new SimpleClass(), $this->container->get( $name ) );

$obj2 = new ClassWithConstructorDeps( $obj1 );
$this->container->set( $name = ClassWithConstructorDeps::class, ClassWithConstructorDeps::class );
$obj2 = new ClassWithConstructorPrimitives( $obj1 );
$this->container->set( $name = ClassWithConstructorPrimitives::class, ClassWithConstructorPrimitives::class );
self::assertEquals( $obj2, $this->container->get( $name ) );

$obj3 = new ClassWithConstructorDeps2( $obj2 );
$this->container->set( $name = ClassWithConstructorDeps2::class, ClassWithConstructorDeps2::class );
$obj3 = new ClassWithConstructor( $obj2 );
$this->container->set( $name = ClassWithConstructor::class, ClassWithConstructor::class );
self::assertEquals( $obj3, $this->container->get( $name ) );
}

public function test_get__autowiring_for_bind_invocable() {
public function test_get__autowiring_for_invocable() {
$this->container->set( SimpleClass::class, SimpleClass::class );
$this->container->set( $name = ClassInvocable::class, ClassInvocable::class );
$this->container->set( $name = InvocableClass::class, InvocableClass::class );

self::assertInstanceOf( $name, $this->container->get( $name ) );
self::assertSame( 'Function is called from ClassInvocable', $this->container->get( $name )() );
}

public function test_get__autowiring_not_set_deps() {
public function test_get__autowiring_for_not_bound_invocable() {
self::assertInstanceOf( InvocableClass::class, $this->container->get( InvocableClass::class ) );
self::assertSame( 'Function is called from ClassInvocable', $this->container->get( InvocableClass::class )() );
}

public function test_get__autowiring_not_bound_deps() {
$obj1 = new SimpleClass();
$obj2 = new ClassWithConstructorDeps( $obj1 );
$obj3 = new ClassWithConstructorDeps2( $obj2 );
$obj2 = new ClassWithConstructorPrimitives( $obj1 );
$obj3 = new ClassWithConstructor( $obj2 );

$this->container->set( $name = ClassWithConstructorDeps2::class, ClassWithConstructorDeps2::class );
$this->container->set( $name = ClassWithConstructor::class, ClassWithConstructor::class );
self::assertEquals( $obj3, $this->container->get( $name ) );

$this->container->set( SplQueue::class , SplQueue::class );
self::assertInstanceOf( SplQueue::class, $this->container->get( SplQueue::class ) );
}

public function test_get__autowiring_for_not_set_class() {
public function test_get__autowiring_for_not_bound_class() {
$obj1 = new SimpleClass();
$obj2 = new ClassWithConstructorDeps( $obj1 );
$obj3 = new ClassWithConstructorDeps2( $obj2 );
$obj2 = new ClassWithConstructorPrimitives( $obj1 );
$obj3 = new ClassWithConstructor( $obj2 );

self::assertEquals( $obj3, $this->container->get( ClassWithConstructorDeps2::class ) );
self::assertEquals( $obj3, $this->container->get( ClassWithConstructor::class ) );
}

// public function test_get__bind_autowiring_container_not_found_exception_string() {
Expand Down

0 comments on commit 852808d

Please sign in to comment.