Skip to content

Commit

Permalink
Merge pull request #90 from mnapoli/3.3
Browse files Browse the repository at this point in the history
3.3
  • Loading branch information
mnapoli committed Jul 30, 2013
2 parents 302191e + f0f7699 commit 48de53e
Show file tree
Hide file tree
Showing 32 changed files with 769 additions and 247 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.DS_Store
nbproject/*
.idea/*
*.iml
vendor/*
composer.phar
composer.lock
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ PHP-DI also tries to avoid falling into the trap of the "Service Locator" antipa
* **Performances**: supports a large number of Caches
* Lazy injection: lazy-loading of dependencies
* Supports constructor injection, setter injection and property injection
* Easy integration with any framework with [Injection over an existing instance](doc/inject-on-instance.md)


## Usage
Expand Down
8 changes: 8 additions & 0 deletions change-log.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Change log

## 3.3

Read the [news entry](news/03-php-di-3-3.md).

* Inject dependencies on an existing instance with `Container::injectOn` (work from [Jeff Flitton](https://github.com/jflitton): [#89](https://github.com/mnapoli/PHP-DI/pull/89)).
* [#86](https://github.com/mnapoli/PHP-DI/issues/86): Optimized definition lookup (faster)
* FIXED [#87](https://github.com/mnapoli/PHP-DI/issues/87): Rare bug in the `PhpDocParser`, fixed by [drdamour](https://github.com/drdamour)

## 3.2

Read the [news entry](news/02-php-di-3-2.md).
Expand Down
1 change: 1 addition & 0 deletions doc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
Extra topics:

* [Performances](performances.md)
* [Inject on an existing instance](inject-on-instance.md)
* [Contribute](../CONTRIBUTING.md)
* [How PHP-DI works](how-it-works.md)

Expand Down
2 changes: 1 addition & 1 deletion doc/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Create a file named `composer.json` in your project root:
```json
{
"require": {
"mnapoli/php-di": "3.2.*"
"mnapoli/php-di": "3.3.*"
}
}
```
Expand Down
56 changes: 56 additions & 0 deletions doc/inject-on-instance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Inject on an existing instance

*Feature introduced in PHP-DI 3.3*

The standard way of using a container is to get an object from it, with all its dependencies injected:

```php
$object = $container->get('foo');
```

But in some situations, you don't have the control of the creation of an object, yet **you want to resolve its dependencies**.

PHP-DI offers the `injectOn` method:

```php
// $object is an instance of some class

$container->injectOn($object);
```

Now, `$object` has all its dependencies injected (through setter injections and property injections).


## Constructor injection

PHP-DI will not perform any constructor injection (because the instance is already created).

If you create the object yourself, you'll have to do the constructor injection yourself:

```php
$object = new MyClass($someDependency, $someOtherDependency);
$container->injectOn($object);
```

If you get the object from some library/framework, then just call `injectOn()`


### Why?

Hopefully, that will help to integrate PHP-DI with other frameworks:

- **MVC frameworks** (Symfony 2, Zend Framework 2, …): inject dependencies of the controller, in the controller itself.
- **Tests** (PHPUnit, …): inject tools in your test class, for example a logger, a timer (for performance test), **the entity manager** (for integration tests), …

Example:

```php
class MyController {
public function __construct() {
// get container ...
$container->injectOn($this);
}
}
```

**Of course**, the preferred method is still to use `$container->get()`. But sometimes you can't get to the root of the framework to intercept the creation of your objects.
56 changes: 56 additions & 0 deletions news/03-php-di-3-3.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# PHP-DI 3.3 released

*Posted by [Matthieu Napoli](https://github.com/mnapoli) on July 30rd 2013*

I am happy to announce that PHP-DI version 3.3 has just been released.

The major new feature is the possibility to inject all dependencies of **an existing instance**.

But before jumping into that, did you know there's an article on [how PHP-DI works](../doc/how-it-works.md).

## Container::injectOn()

*Read the full documentation [here](../doc/inject-on-instance.md)*

```php
$myObject = new MyClass();

$container->injectOn($myObject);
```

Now, `$myObject` has all its dependencies injected (setter injections and property injections).

It is basically the same as `$myObject = $container->get('MyClass')` except **you** create the instance.

### Why?

Weird right? Well it's not supposed to be used everywhere.

Hopefully, that will help **a lot** to integrate PHP-DI with other frameworks:

- **MVC frameworks** (Symfony 2, Zend Framework 2, …): inject dependencies of the controller, in the controller itself.
- **Tests** (PHPUnit, …): inject tools in your test class, for example a logger, a timer (for performance test), **the entity manager** (for integration tests), …

Example:

```php
class MyController {
public function __construct() {
// get container ...
$container->injectOn($this);
}
}
```

**Of course**, the preferred method is still to use `$container->get()`. But sometimes you can't get to the root of the framework to intercept the creation of your objects (I'm looking at you most MVC frameworks, PHPUnit & …)

### Good to know

PHP-DI will not perform any constructor injection. But of course most of the time you'll be using that feature is when you can't/don't want to use the constructor for getting your dependencies.


## Change log

Except this feature, 3.3 contains an optimization for definition resolution and a bugfix for a rare situation.

Read all the changes and their authors in the [change log](../change-log.md).
6 changes: 4 additions & 2 deletions news/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# News

- July 23rd 2013. [PHP-DI 3.2 released](02-php-di-3-2.md)
- July 30th 2013. [PHP-DI 3.3 released](03-php-di-3-3.md): Inject dependencies into an existing instance and more…

- June 23rd 2013. [PHP-DI 3.1 released](01-php-di-3-1.md)
- July 23rd 2013. [PHP-DI 3.2 released](02-php-di-3-2.md): Lazy injection, `ContainerBuilder` and more…

- June 23rd 2013. [PHP-DI 3.1 released](01-php-di-3-1.md): Zend Framework 1 integration and more…
20 changes: 20 additions & 0 deletions src/DI/Container.php
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,26 @@ public function get($name, $useProxy = false)
throw new NotFoundException("No entry or class found for '$name'");
}

/**
* Inject all dependencies on an existing instance
*
* @param object $instance Object to perform injection upon
* @throws InvalidArgumentException
* @throws DependencyException
* @return object $instance Returns the same instance
*/
public function injectOn($instance)
{
$definition = $this->definitionManager->getDefinition(get_class($instance));

// Check that the definition is a class definition
if ($definition instanceof ClassDefinition) {
$instance = $this->factory->injectInstance($definition, $instance);
}

return $instance;
}

/**
* Define an object or a value in the container
*
Expand Down
90 changes: 48 additions & 42 deletions src/DI/Definition/ClassDefinition.php
Original file line number Diff line number Diff line change
Expand Up @@ -200,55 +200,53 @@ public function isLazy()
*/
public function merge(Definition $definition)
{
if ($definition instanceof ClassDefinition) {
if (!$definition instanceof ClassDefinition) {
throw new DefinitionException("DI definition conflict: there are 2 different definitions for '"
. $definition->getName() . "' that are incompatible, they are not of the same type");
}

// The latter prevails
if ($definition->className !== null) {
$this->className = $definition->className;
}
if ($definition->scope !== null) {
$this->scope = $definition->scope;
}
if ($definition->lazy !== null) {
$this->lazy = $definition->lazy;
}
// The latter prevails
if ($definition->className !== null) {
$this->className = $definition->className;
}
if ($definition->scope !== null) {
$this->scope = $definition->scope;
}
if ($definition->lazy !== null) {
$this->lazy = $definition->lazy;
}

// Merge constructor injection
if ($definition->getConstructorInjection() !== null) {
if ($this->constructorInjection !== null) {
// Merge
$this->constructorInjection->merge($definition->getConstructorInjection());
} else {
// Set
$this->constructorInjection = $definition->getConstructorInjection();
}
// Merge constructor injection
if ($definition->getConstructorInjection() !== null) {
if ($this->constructorInjection !== null) {
// Merge
$this->constructorInjection->merge($definition->getConstructorInjection());
} else {
// Set
$this->constructorInjection = $definition->getConstructorInjection();
}
}

// Merge property injections
foreach ($definition->getPropertyInjections() as $propertyName => $propertyInjection) {
if (array_key_exists($propertyName, $this->propertyInjections)) {
// Merge
$this->propertyInjections[$propertyName]->merge($propertyInjection);
} else {
// Add
$this->propertyInjections[$propertyName] = $propertyInjection;
}
// Merge property injections
foreach ($definition->getPropertyInjections() as $propertyName => $propertyInjection) {
if (array_key_exists($propertyName, $this->propertyInjections)) {
// Merge
$this->propertyInjections[$propertyName]->merge($propertyInjection);
} else {
// Add
$this->propertyInjections[$propertyName] = $propertyInjection;
}
}

// Merge method injections
foreach ($definition->getMethodInjections() as $methodName => $methodInjection) {
if (array_key_exists($methodName, $this->methodInjections)) {
// Merge
$this->methodInjections[$methodName]->merge($methodInjection);
} else {
// Add
$this->methodInjections[$methodName] = $methodInjection;
}
// Merge method injections
foreach ($definition->getMethodInjections() as $methodName => $methodInjection) {
if (array_key_exists($methodName, $this->methodInjections)) {
// Merge
$this->methodInjections[$methodName]->merge($methodInjection);
} else {
// Add
$this->methodInjections[$methodName] = $methodInjection;
}

} else {
throw new DefinitionException("DI definition conflict: there are 2 different definitions for '"
. $definition->getName() . "' that are incompatible, they are not of the same type");
}
}

Expand All @@ -260,4 +258,12 @@ public function isCacheable()
return true;
}

/**
* {@inheritdoc}
*/
public static function isMergeable()
{
return true;
}

}
16 changes: 9 additions & 7 deletions src/DI/Definition/ClosureDefinition.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,7 @@ public function getValue(Container $container)
*/
public function merge(Definition $definition)
{
if ($definition instanceof ClosureDefinition) {
// The latter prevails
$this->closure = $definition->getClosure();
} else {
throw new DefinitionException("DI definition conflict: there are 2 different definitions for '"
. $definition->getName() . "' that are incompatible, they are not of the same type");
}
throw new \BadMethodCallException("Impossible to merge a ClosureDefinition with another definition");
}

/**
Expand All @@ -92,4 +86,12 @@ public function isCacheable()
return false;
}

/**
* {@inheritdoc}
*/
public static function isMergeable()
{
return false;
}

}
7 changes: 7 additions & 0 deletions src/DI/Definition/Definition.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,11 @@ public function merge(Definition $definition);
*/
public function isCacheable();

/**
* Returns true if the definition is mergeable with other definitions
*
* @return bool
*/
public static function isMergeable();

}
16 changes: 10 additions & 6 deletions src/DI/Definition/DefinitionManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -276,19 +276,23 @@ private function saveToCache($name, Definition $definition = null)
*/
private function updateCombinedSource()
{
// Sources are added from highest priority to least priority
$this->combinedSource = new CombinedDefinitionSource();

// Sources are added from least priority to highest priority
if ($this->reflectionSource) {
$this->combinedSource->addSource($this->reflectionSource);
$this->combinedSource->addSource($this->simpleSource);

// Traverses the array reverse
foreach (array_reverse($this->arraySources) as $arraySource) {
$this->combinedSource->addSource($arraySource);
}

if ($this->annotationSource) {
$this->combinedSource->addSource($this->annotationSource);
}
foreach ($this->arraySources as $arraySource) {
$this->combinedSource->addSource($arraySource);

if ($this->reflectionSource) {
$this->combinedSource->addSource($this->reflectionSource);
}
$this->combinedSource->addSource($this->simpleSource);
}

}

0 comments on commit 48de53e

Please sign in to comment.