Skip to content
This repository has been archived by the owner on Jan 29, 2020. It is now read-only.

Commit

Permalink
Merge branch 'hotfix/4'
Browse files Browse the repository at this point in the history
Close #4
  • Loading branch information
weierophinney committed Jan 19, 2016
2 parents c33367f + 995f43a commit f2d1257
Show file tree
Hide file tree
Showing 7 changed files with 666 additions and 0 deletions.
33 changes: 33 additions & 0 deletions doc/book/zend.di.configuration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Zend\\Di Configuration

Most of the configuration for both the setup of Definitions as well as the setup of the Instance
Manager can be attained by a configuration file. This file will produce an array (typically) and
have a particular iterable structure.

The top two keys are 'definition' and 'instance', each specifying values for respectively,
definition setup and instance manager setup.

The definition section expects the following information expressed as a PHP array:

```php
$config = array(
'definition' => array(
'compiler' => array(/* @todo compiler information */),
'runtime' => array(/* @todo runtime information */),
'class' => array(
'instantiator' => '', // the name of the instantiator, by default this is __construct
'supertypes' => array(), // an array of supertypes the class implements
'methods' => array(
'setSomeParameter' => array( // a method name
'parameterName' => array(
'name', // string parameter name
'type', // type or null
'is-required' // bool
)
)

)
)
)
);
```
131 changes: 131 additions & 0 deletions doc/book/zend.di.debugging-and-complex-use-cases.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
# Zend\\Di Debugging & Complex Use Cases

## Debugging a DiC

It is possible to dump the information contained within both the Definition and InstanceManager for
a Di instance.

The easiest way is to do the following:

```php
Zend\Di\Display\Console::export($di);
```

If you are using a RuntimeDefinition where upon you expect a particular definition to be resolve at
the first-call, you can see that information to the console display to force it to read that class:

```php
Zend\Di\Display\Console::export($di, array('A\ClassIWantTo\GetTheDefinitionFor'));
```

## Complex Use Cases

### Interface Injection

```php
namespace Foo\Bar {
class Baz implements BamAwareInterface
{
public $bam;

public function setBam(Bam $bam)
{
$this->bam = $bam;
}
}
class Bam
{
}
interface BamAwareInterface
{
public function setBam(Bam $bam);
}
}

namespace {
include 'zf2bootstrap.php';
$di = new Zend\Di\Di;
$baz = $di->get('Foo\Bar\Baz');
}
```

### Setter Injection with Class Definition

```php
namespace Foo\Bar {
class Baz
{
public $bam;

public function setBam(Bam $bam)
{
$this->bam = $bam;
}
}
class Bam {
}
}

namespace {
$di = new Zend\Di\Di;
$di->configure(new Zend\Di\Config(array(
'definition' => array(
'class' => array(
'Foo\Bar\Baz' => array(
'setBam' => array('required' => true)
)
)
)
)));
$baz = $di->get('Foo\Bar\Baz');
}
```

### Multiple Injections To A Single Injection Point

```php
namespace Application {
class Page
{
public $blocks;

public function addBlock(Block $block)
{
$this->blocks[] = $block;
}
}
interface Block
{
}
}

namespace MyModule {
class BlockOne implements \Application\Block {}
class BlockTwo implements \Application\Block {}
}

namespace {
include 'zf2bootstrap.php';
$di = new Zend\Di\Di;
$di->configure(new Zend\Di\Config(array(
'definition' => array(
'class' => array(
'Application\Page' => array(
'addBlock' => array(
'block' => array('type' => 'Application\Block', 'required' => true)
)
)
)
),
'instance' => array(
'Application\Page' => array(
'injections' => array(
'MyModule\BlockOne',
'MyModule\BlockTwo'
)
)
)
)));
$page = $di->get('Application\Page');
}
```
132 changes: 132 additions & 0 deletions doc/book/zend.di.definitions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# Zend\\Di Definition

Definitions are the place where Zend\\Di attempts to understand the structure of the code it is
attempting to wire. This means that if you've written non-ambiguous, clear and concise code;
Zend\\Di has a very good chance of understanding how to wire things up without much added
complexity.

## DefinitionList

Definitions are introduced to the Zend\\Di\\Di object through a definition list implemented as
Zend\\Di\\DefinitionList (SplDoublyLinkedList). Order is important. Definitions in the front of the
list will be consulted on a class before definitions at the end of the list.

> ## Note
Regardless of what kind of Definition strategy you decide to use, it is important that your
autoloaders are already setup and ready to use.

## RuntimeDefinition

The default DefinitionList instantiated by Zend\\Di\\Di, when no other DefinitionList is provided,
has as Definition\\RuntimeDefinition baked-in. The RuntimeDefinition will respond to query's about
classes by using Reflection. This Runtime definitions uses any available information inside methods:
their signature, the names of parameters, the type-hints of the parameters, and the default values
to determine if something is optional or required when making a call to that method. The more
explicit you can be in your method naming and method signatures, the easier of a time
Zend\\Di\\Definition\\RuntimeDefinition will have determining the structure of your code.

This is what the constructor of a RuntimeDefinition looks like:

```php
public function __construct(IntrospectionStrategy $introspectionStrategy = null, array
$explicitClasses = null)
{
$this->introspectionStrategy = ($introspectionStrategy) ?: new IntrospectionStrategy();
if ($explicitClasses) {
$this->setExplicitClasses($explicitClasses);
}
}
```

The IntrospectionStrategy object is an object that determines the rules, or guidelines, for how the
RuntimeDefinition will introspect information about your classes. Here are the things it knows how
to do:

- Whether or not to use Annotations (Annotations are expensive and off by default, read more about
these in the Annotations section)
- Which method names to include in the introspection, by default, the pattern /^set\[A-Z\]{1}\\w\*/
is registered by default, this is a list of patterns.
- Which interface names represent the interface injection pattern. By default, the pattern
/\\w\*Aware\\w\*/ is registered, this is a list of patterns.

The constructor for the IntrospectionStrategy looks like this:

```php
public function __construct(AnnotationManager $annotationManager = null)
{
$this->annotationManager = ($annotationManager) ?: $this->createDefaultAnnotationManager();
}
```

This goes to say that an AnnotationManager is not required, but if you wish to create a special
AnnotationManager with your own annotations, and also wish to extend the RuntimeDefinition to look
for these special Annotations, this is the place to do it.

The RuntimeDefinition also can be used to look up either all classes (implicitly, which is default),
or explicitly look up for particular pre-defined classes. This is useful when your strategy for
inspecting one set of classes might differ from those of another strategy for another set of
classes. This can be achieved by using the setExplicitClasses() method or by passing a list of
classes as a second argument to the constructor of the RuntimeDefinition.

## CompilerDefinition

The CompilerDefinition is very much similar in nature to the RuntimeDefinition with the exception
that it can be seeded with more information for the purposes of "compiling" a definition. This is
useful when you do not want to be making all those (sometimes expensive) calls to reflection and the
annotation scanning system during the request of your application. By using the compiler, a
definition can be created and written to disk to be used during a request, as opposed to the task of
scanning the actual code.

For example, let's assume we want to create a script that will create definitions for some of our
library code:

```php
// in "package name" format
$components = array(
'My_MovieApp',
'My_OtherClasses',
);

foreach ($components as $component) {
$diCompiler = new Zend\Di\Definition\CompilerDefinition;
$diCompiler->addDirectory('/path/to/classes/' . str_replace('_', '/', $component));

$diCompiler->compile();
file_put_contents(
__DIR__ . '/../data/di/' . $component . '-definition.php',
'<?php return ' . var_export($diCompiler->toArrayDefinition()->toArray(), true) . ';'
);
}
```

This will create a couple of files that will return an array of the definition for that class. To
utilize this in an application, the following code will suffice:

```php
protected function setupDi(Application $app)
{
$definitionList = new DefinitionList(array(
new Definition\ArrayDefinition(include __DIR__ .
'/path/to/data/di/My_MovieApp-definition.php'),
new Definition\ArrayDefinition(include __DIR__ .
'/path/to/data/di/My_OtherClasses-definition.php'),
$runtime = new Definition\RuntimeDefinition(),
));
$di = new Di($definitionList, null, new Config($this->config->di));
$di->instanceManager()->addTypePreference('Zend\Di\LocatorInterface', $di);
$app->setLocator($di);
}
```

The above code would more than likely go inside your application's or module's bootstrap file. This
represents the simplest and most performant way of configuring your DiC for usage.

## ClassDefinition

The idea behind using a ClassDefinition is two-fold. First, you may want to override some
information inside of a RuntimeDefinition. Secondly, you might want to simply define your complete
class's definition with an xml, ini, or php file describing the structure. This class definition can
be fed in via Configuration or by directly instantiating and registering the Definition with the
DefinitionList.

Todo - example

0 comments on commit f2d1257

Please sign in to comment.