diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..852306a --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +test export-ignore +nbproject export-ignore +.codeclimate.yml export-ignore +.php_cs export-ignore +.travis.yml export-ignore +composer.lock export-ignore +phpunit.xml export-ignore diff --git a/.gitignore b/.gitignore index e91e966..ab728c9 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ /nbproject/private/ /test/coverage/ /test/log/ +/build/ diff --git a/.travis.yml b/.travis.yml index 7555003..15fa52b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,4 +15,12 @@ script: - vendor/bin/phpunit after_script: - - vendor/bin/test-reporter --coverage-report="test/coverage/clover.xml" \ No newline at end of file + - vendor/bin/test-reporter --coverage-report="test/coverage/clover.xml" + +notifications: + webhooks: + urls: + - https://webhooks.gitter.im/e/155f53c8074ea0a9073e + on_success: always + on_failure: always + on_start: never diff --git a/CHANGELOG.md b/CHANGELOG.md index 21e4158..2953364 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,9 +4,19 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [0.1.1] - 2017-02-03 +Non-BC-breaking bugfixes. +Reduced size of dist archive. +Added Gitter notifications of Travis events, and Gitter badge. + +### Fixed +- `CompositeContainer#__construct()` not accepting interop containers. +- `CompositeContainer#add()` not implementing interface method. +- `CompositeContainer` not throwing exceptions correctly. + ## [0.1] - 2017-02-02 Initial release, containing concrete implementations. ### Added - Implementations of regular and compound containers, with service provider support. -- Tests. \ No newline at end of file +- Tests. diff --git a/README.md b/README.md index 4d8fdcb..3ec3663 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,9 @@ ## Dhii - DI ## + [![Build Status](https://travis-ci.org/Dhii/di.svg?branch=master)](https://travis-ci.org/Dhii/di) [![Code Climate](https://codeclimate.com/github/Dhii/di/badges/gpa.svg)](https://codeclimate.com/github/Dhii/di) [![Test Coverage](https://codeclimate.com/github/Dhii/di/badges/coverage.svg)](https://codeclimate.com/github/Dhii/di/coverage) +[![Join the chat at https://gitter.im/Dhii/di](https://badges.gitter.im/Dhii/di.svg)](https://gitter.im/Dhii/di?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) A simple, granular, standards-compliant dependency injection container and factory implementation. diff --git a/src/CompositeContainer.php b/src/CompositeContainer.php index 680632c..52e8ce0 100644 --- a/src/CompositeContainer.php +++ b/src/CompositeContainer.php @@ -3,6 +3,9 @@ namespace Dhii\Di; use Exception; +use Dhii\Di\Exception\ContainerException; +use Dhii\Di\Exception\NotFoundException; +use Interop\Container\ContainerInterface as BaseContainerInterface; /** * Concrete implementation of a container that can have child containers. @@ -11,16 +14,16 @@ */ class CompositeContainer extends AbstractCompositeContainer implements ParentAwareContainerInterface, - CompositeContainerInterface + WritableCompositeContainerInterface { /** * Constructor. * * @since 0.1 * - * @param ContainerInterface $parent The parent container of this instance. + * @param BaseContainerInterface $parent The parent container of this instance. */ - public function __construct(ContainerInterface $parent = null) + public function __construct(BaseContainerInterface $parent = null) { $this->_setParentContainer($parent); } @@ -70,11 +73,11 @@ public function getContainers() * * @since 0.1 * - * @param ContainerInterface $container The container to add. + * @param BaseContainerInterface $container The container to add. * * @return $this This instance. */ - public function add(ContainerInterface $container) + public function add(BaseContainerInterface $container) { $this->_add($container); diff --git a/test/functional/CompositeContainerTest.php b/test/functional/CompositeContainerTest.php index 4d705ff..625f1ff 100644 --- a/test/functional/CompositeContainerTest.php +++ b/test/functional/CompositeContainerTest.php @@ -3,6 +3,8 @@ namespace Dhii\Di\FuncTest; use Dhii\Di\CompositeContainer; +use Dhii\Di\Exception\NotFoundException; +use Dhii\Di\Exception\ContainerException; use Dhii\Di\ParentAwareContainerInterface; use Dhii\Di\ServiceProvider as ServiceProvider2; use Interop\Container\ContainerInterface; @@ -59,9 +61,9 @@ public function createServiceProvider($definitions) * * @since 0.1 * - * @param ServiceProvider $definitions The service provider. - * @param ContainerInterface $parent The container instance which is the be the parent container. - * @param bool $isMutable If true, the container will have its parent container be mutable; immutable if false. + * @param ServiceProvider $definitions The service provider. + * @param ContainerInterface $parent The container instance which is the be the parent container. + * @param bool $isMutable If true, the container will have its parent container be mutable; immutable if false. * * @return ParentAwareContainerInterface */ @@ -76,6 +78,23 @@ public function createContainer(ServiceProvider $definitions, ContainerInterface return $mock; } + /** + * Creates an instance of the most basic interop container. + * + * @since 0.1.1 + * + * @return ContainerInterface The new instance. + */ + public function createBaseContainer() + { + $instance = $this->mock('Interop\\Container\\ContainerInterface') + ->get() + ->has() + ->new(); + + return $instance; + } + /** * Create a service definition that returns a simple value. * @@ -87,11 +106,53 @@ public function createContainer(ServiceProvider $definitions, ContainerInterface */ public function createDefinition($value) { - return function(ContainerInterface $container, $previous = null) use ($value) { + return function (ContainerInterface $container, $previous = null) use ($value) { return $value; }; } + /** + * Tests whether a valid instance of the test subject can be created. + * + * @since 0.1.1 + */ + public function testCanBeCreated() + { + $subject = $this->createInstance(); + $this->assertInstanceOf('Dhii\\Di\\CompositeContainerInterface', $subject, 'A valid instance of the test subject could not be created'); + $this->assertInstanceOf('Dhii\\Di\\WritableCompositeContainerInterface', $subject, 'Test subject does not implement required interface'); + $this->assertInstanceOf('Dhii\\Di\\ParentAwareContainerInterface', $subject, 'Test subject does not implement required interface'); + $this->assertInstanceOf('Interop\\Container\\ContainerInterface', $subject, 'Test subject does not implement required interface'); + } + + /** + * Tests whether an interop container can get added to the composite container. + * + * @since 0.1.1 + */ + public function testAdd() + { + $subject = $this->createInstance(); + $child = $this->createBaseContainer(); + + $subject->add($child); + $this->assertContains($child, $subject->getContainers(), 'Added container is not in the resulting container set'); + } + + /** + * Tests that the constructor accepts correct args. + * + * @since 0.1.1 + */ + public function testConstructor() + { + $class = static::TEST_SUBJECT_CLASSNAME; + $parent = $this->createBaseContainer(); + $subject = $this->createInstance($parent); + + $this->assertSame($parent, $subject->getParentContainer(), 'Parent set in constructor could not be retrieved'); + } + /** * Tests whether services of child containers can be correctly retrieved from parent. * No relationships between services. @@ -103,15 +164,15 @@ public function testOneLevelRetrieval() $rootContainer = $this->createInstance(); $childContainer1 = $this->createContainer( $this->createServiceProvider(array( - 'service1' => $this->createDefinition('service-1'), - 'service2' => $this->createDefinition('service-2'), + 'service1' => $this->createDefinition('service-1'), + 'service2' => $this->createDefinition('service-2'), )), // Servide definitions $rootContainer, // Parent false // Immutable ); $childContainer2 = $this->createContainer( $this->createServiceProvider(array( - 'service3' => $this->createDefinition('service-3'), + 'service3' => $this->createDefinition('service-3'), )), // Servide definitions $rootContainer, // Parent false // Immutable @@ -120,9 +181,9 @@ public function testOneLevelRetrieval() $rootContainer->add($childContainer2); $expected = array( - 'service1' => 'service-1', - 'service2' => 'service-2', - 'service3' => 'service-3', + 'service1' => 'service-1', + 'service2' => 'service-2', + 'service3' => 'service-3', ); $actual = array(); @@ -146,11 +207,12 @@ public function testTwoLevelRetrieval() $childContainer1 = $this->createContainer( $this->createServiceProvider(array( - 'service1' => function (ContainerInterface $container) use ($me) { + 'service1' => function (ContainerInterface $container) use ($me) { $me->assertInstanceOf('Dhii\Di\CompositeContainerInterface', $container, 'Container must be composite in order to retrieve definition from another container'); + return implode('->', array('service-1', $container->get('service3'))); }, - 'service2' => $this->createDefinition('service-2'), + 'service2' => $this->createDefinition('service-2'), )), // Servide definitions $rootContainer, // Parent false // Immutable @@ -159,7 +221,7 @@ public function testTwoLevelRetrieval() $childContainer2 = $this->createContainer( $this->createServiceProvider(array( - 'service3' => $this->createDefinition('service-3'), + 'service3' => $this->createDefinition('service-3'), )), // Servide definitions $rootContainer, // Parent false // Immutable @@ -171,9 +233,9 @@ public function testTwoLevelRetrieval() $this->assertEquals(2, count($rootContainer->getContainers()), 'Incorrect number of child containers'); $expected = array( - 'service1' => 'service-1->service-3', - 'service2' => 'service-2', - 'service3' => 'service-3', + 'service1' => 'service-1->service-3', + 'service2' => 'service-2', + 'service3' => 'service-3', ); $actual = array(); @@ -198,15 +260,17 @@ public function testThreeLevelComplexRetrieval() $rootContainer = $this->createInstance(); $childContainer1 = $this->createContainer( $this->createServiceProvider(array( - 'service1' => $this->createDefinition('service-1'), - 'service2' => function (ContainerInterface $c) use ($me) { + 'service1' => $this->createDefinition('service-1'), + 'service2' => function (ContainerInterface $c) use ($me) { $me->assertInstanceOf('Dhii\Di\CompositeContainerInterface', $c, 'Container must be composite in order to retrieve definition from another container'); + return implode('->', array('service-2', $c->get('service3'))); }, - 'service7' => function (ContainerInterface $c) use ($me) { + 'service7' => function (ContainerInterface $c) use ($me) { $me->assertInstanceOf('Dhii\Di\CompositeContainerInterface', $c, 'Container must be composite in order to retrieve definition from another container'); + return implode('->', array('service-7', $c->get('service4'))); - } + }, )), // Servide definitions $rootContainer, // Parent false // Immutable @@ -215,11 +279,12 @@ public function testThreeLevelComplexRetrieval() $childContainer2 = $this->createContainer( $this->createServiceProvider(array( - 'service3' => $this->createDefinition('service-3'), - 'service4' => function (ContainerInterface $c) use ($me) { + 'service3' => $this->createDefinition('service-3'), + 'service4' => function (ContainerInterface $c) use ($me) { $me->assertInstanceOf('Dhii\Di\CompositeContainerInterface', $c, 'Container must be composite in order to retrieve definition from another container'); + return implode('->', array('service-4', $c->get('service5'))); - } + }, )), // Servide definitions $rootContainer, // Parent false // Immutable @@ -230,25 +295,28 @@ public function testThreeLevelComplexRetrieval() $childContainer3 = $this->createInstance($rootContainer); $childContainer3->add($this->createContainer( $this->createServiceProvider(array( - 'service5' => function (ContainerInterface $c) use ($me) { + 'service5' => function (ContainerInterface $c) use ($me) { $me->assertInstanceOf('Dhii\Di\CompositeContainerInterface', $c, 'Container must be composite in order to retrieve definition from another container'); + return implode('->', array('service-5', $c->get('service8'))); }, - 'service6' => $this->createDefinition('service-6') + 'service6' => $this->createDefinition('service-6'), )), $rootContainer, false )); $childContainer3->add($this->createContainer( $this->createServiceProvider(array( - 'service8' => function (ContainerInterface $c) use ($me) { + 'service8' => function (ContainerInterface $c) use ($me) { $me->assertInstanceOf('Dhii\Di\CompositeContainerInterface', $c, 'Container must be composite in order to retrieve definition from another container'); + return implode('->', array('service-8', $c->get('service1'))); }, - 'service9' => function (ContainerInterface $c) use ($me) { + 'service9' => function (ContainerInterface $c) use ($me) { $me->assertInstanceOf('Dhii\Di\CompositeContainerInterface', $c, 'Container must be composite in order to retrieve definition from another container'); + return implode('->', array('service-9', $c->get('service6'))); - } + }, )), $rootContainer, false @@ -258,17 +326,16 @@ public function testThreeLevelComplexRetrieval() $rootContainer->add($childContainer2); $rootContainer->add($childContainer3); - $expected = array( - 'service1' => 'service-1', - 'service2' => 'service-2->service-3', - 'service3' => 'service-3', - 'service4' => 'service-4->service-5->service-8->service-1', - 'service5' => 'service-5->service-8->service-1', - 'service6' => 'service-6', - 'service7' => 'service-7->service-4->service-5->service-8->service-1', - 'service8' => 'service-8->service-1', - 'service9' => 'service-9->service-6' + 'service1' => 'service-1', + 'service2' => 'service-2->service-3', + 'service3' => 'service-3', + 'service4' => 'service-4->service-5->service-8->service-1', + 'service5' => 'service-5->service-8->service-1', + 'service6' => 'service-6', + 'service7' => 'service-7->service-4->service-5->service-8->service-1', + 'service8' => 'service-8->service-1', + 'service9' => 'service-9->service-6', ); $actual = array(); @@ -278,4 +345,46 @@ public function testThreeLevelComplexRetrieval() $this->assertEquals($expected, $actual, 'The container structure did not resolve services correctly'); } + + /** + * Tests the method that creates a {@see NotFoundException}. + * + * @since 0.1.1 + */ + public function testCreateNotFoundException() + { + $subject = $this->createInstance(); + + $previous = new \Exception('test message', 3, null); + $exception = $subject->this()->_createNotFoundException('test message', 3, $previous); + + $this->assertInstanceOf('Dhii\\Di\\Exception\\NotFoundException', $exception); + $this->assertInstanceOf('Dhii\\Di\\ExceptionInterface', $exception); + $this->assertInstanceOf('Interop\\Container\\Exception\\NotFoundException', $exception); + + $this->assertEquals('test message', $exception->getMessage()); + $this->assertEquals(3, $exception->getCode()); + $this->assertEquals($previous, $exception->getPrevious()); + } + + /** + * Tests the method that creates a {@see ContainerException}. + * + * @since 0.1.1 + */ + public function testContainerException() + { + $subject = $this->createInstance(); + + $previous = new \Exception('test message', 3, null); + $exception = $subject->this()->_createContainerException('test message', 3, $previous); + + $this->assertInstanceOf('Dhii\\Di\\Exception\\ContainerException', $exception); + $this->assertInstanceOf('Dhii\\Di\\ExceptionInterface', $exception); + $this->assertInstanceOf('Interop\\Container\\Exception\\ContainerException', $exception); + + $this->assertEquals('test message', $exception->getMessage()); + $this->assertEquals(3, $exception->getCode()); + $this->assertEquals($previous, $exception->getPrevious()); + } }