Skip to content

Commit

Permalink
Adds redirects for old files
Browse files Browse the repository at this point in the history
Signed-off-by: Frank Brückner <[email protected]>
  • Loading branch information
froschdesign committed Dec 24, 2020
1 parent d2636bc commit 09c338d
Show file tree
Hide file tree
Showing 12 changed files with 78 additions and 1,197 deletions.
111 changes: 6 additions & 105 deletions docs/book/codegen.md
Original file line number Diff line number Diff line change
@@ -1,105 +1,6 @@
# Code Generator

laminas-di comes with [Ahead-of-Time (AoT)](https://en.wikipedia.org/wiki/Ahead-of-time_compilation)
generators to create optimized code for production. These generators will
inspect the provided classes, resolve their dependencies, and generate factories
based on these results.

> ### Removal of laminas-code dependencies
>
> Before version 3.1, this feature required [laminas-code](https://docs.laminas.dev/laminas-code/),
> which you can add to your project using Composer:
>
> ```bash
> $ composer require --dev laminas/laminas-code
> ```
>
> **Since version 3.1 and up, this is no longer required.**
## Generating an optimized injector
The `Laminas\Di\CodeGenerator\InjectorGenerator` class offers an implementation to
generate an optimized injector based on the runtime configuration and a resolver
instance.
```php
use Laminas\Di\Config;
use Laminas\Di\Definition\RuntimeDefinition;
use Laminas\Di\Resolver\DependencyResolver;
use Laminas\Di\CodeGenerator\InjectorGenerator;
$config = new Config();
$resolver = new DependencyResolver(new RuntimeDefinition(), $config);
$generator = new InjectorGenerator($config, $resolver);
// It is highly recommended to set the container that is used at runtime:
$resolver->setContainer($container);
$generator->setOutputDirectory('/path/to/generated/files');
$generator->generate([
MyClassA::class,
MyClassB::class,
// ...
]);
```
You can also utilize `Laminas\Code\Scanner` to scan your code for classes:
```php
$scanner = new DirectoryScanner(__DIR__);
$generator->generate($scanner->getClassNames());
```
## MVC and Mezzio integration
When you are using laminas-di's `ConfigProvider` with Mezzio or consuming the
`Module` class via laminas-mvc, you can obtain the generator instance from the
service manager:
```php
$generator = $serviceManager->get(\Laminas\Di\CodeGenerator\InjectorGenerator::class);
```
### AoT Config Options
The service factory uses options in your `config` service, located under the key
`dependencies.auto.aot`. This should be defined as an associative array of
options for creating the code generator instance. This array respects the
following keys (unknown keys are ignored):
- `namespace`: This will be used as base namespace to prefix the namespace of
the generated classes. It will be passed to the constructor of
`Laminas\Di\CodeGenerator\InjectorGenerator`; the default value is
`Laminas\Di\Generated`.
- `directory`: The directory where the generated PHP files will be stored. If
this value is not provided, you will need to set it with the generator's
`setOutputDirectory()` method before calling `generate()`.
- `logger`: must be resolvable in container and must be an instance of `Psr\Log\LoggerInterface.`
By default `Psr\Log\NullLogger` is used. See the [Logging section](#logging) for details.
Below is an example detailing configuration of the generator factory:
```php
return [
'dependencies' => [
'auto' => [
'aot' => [
'namespace' => 'AppAoT\Generated',
'directory' => __DIR__ . '/../gen',
'logger' => Psr\Log\LoggerInterface::class,
],
],
],
];
```
## Logging
The `InjectorGenerator` allows passing a [PSR-3 logger](http://www.php-fig.org/psr/psr-3/) instance
via an optional fourth constructor parameter.
The generator will log the following information:
* When a factory is about to be generated for a class or alias (Log level: Debug)
* When the factory generation caused an exception (Log level: Error)
<noscript><meta http-equiv="refresh" content="0; url=/laminas-di/v3/codegen/"></noscript>
<script>
document.addEventListener("DOMContentLoaded", function (event) {
window.location.pathname = '/laminas-di/v3/codegen/';
});
</script>
232 changes: 6 additions & 226 deletions docs/book/config.md
Original file line number Diff line number Diff line change
@@ -1,226 +1,6 @@
# Configuration

Configuration detailing how types are constructed and dependencies should be
resolved can be provided as an associative array when instantiating
`Laminas\Di\Config`. A type may be an actual class name or an alias to a class
name.

The configuration array respects the following keys (unknown keys are ignored):

- `preferences`: Associative nested array that maps class or interface names to
a service name that should be used to provide a dependency. See the
[Type Preferences](#type-preferences) section below for details.

- `types`: Associative array defining how classes or aliases should be
constructed. Each key in this array is a class or alias name, and its value is
another associative array with the following keys:

- `preferences`: The same as `preferences` above, but only for the associated
class.

- `parameters`: Associative array declaring the values to inject for the
declared construction parameters. Each key is the parameter name as
declared in the constructor method of the associated class name. See the
[Parameters](#parameters) section below for details.

- `typeOf`: String that contains a class name. It declares that the
associated key is an alias of the given class name. This class must exist.
It cannot not be another alias.

Below is an example of injector configuration.

```php
$config = new \Laminas\Di\Config([
// Declares global preferences to use when resolving
// dependencies of the specified type
'preferences' => [
// A map of classname => preferred type
MyInterface::class => MyImplementation::class,
],

// Declares how types should be constructed.
// This also allows declaring aliases of a specific class
'types' => [
ClassName::class => [
// Declaration in the same way as global preferences
// but these will aply when the type of the associated key
// should be instanciated
'preferences' => [],

// Constructor parameters to inject. This option will define
// the injections directly by the parameter name of the constructor
// used as key.
//
// If the parameter is type-hinted by a class/interface name, you can
// provide the injection by string. The injector will use the IoC
// container to obtain it.
'parameters' => [
'foo' => 'bar',
],
],

// Define an alias
'Alias.Name' => [
'typeOf' => ClassName::class,

'preferences' => [],
'parameters' => [],
],
],
]);
```

## Type Preferences

In many cases, you might be using interfaces as type hints as opposed to
concrete types. Even though type preferences are not limited to interfaces or
abstract class names, they provide hints to the injector on how such types
should be resolved.

The resolver will look up the name finally passed to the container in the
following way (the first match will be used):

1. The preference defined in the type configuration of the class if it satifies
the typehint (implements, extends, or typeOf).
2. If there is a global preference defined and it satisfies the typehint.
3. Use the typehinted name directly.

```php
// Assume the following classes are declared:

interface FooInterface
{}

class Foo implements FooInterface
{}

class SpecialFoo implements FooInterface
{}

class Bar
{}

class MyClass
{
public function __construct(FooInterface $foo)
{
// ...
}
}

// With the following configuration:

use Laminas\Di\Injector;
use Laminas\Di\Config;

$injector = new Injector(new Config([
'preferences' => [
FooInterface::class => Foo::class,
],
'types' => [
'MyClass.A' => [
'typeOf' => MyClass::class,
'preferences' => [
FooInterface::class => SpecialFoo::class,
],
],
'MyClass.B' => [
'typeOf' => MyClass::class,
'preferences' => [
FooInterface::class => Bar::class,
],
],
],
]));


// The results are:
$a = $injector->create(MyClass::class); // Constructed with Foo
$b = $injector->create('MyClass.A'); // Constructed with SpecialFoo
$c = $injector->create('MyClass.B'); // Constructed with Foo (since Bar does not satisfy FooInterface)
```


## Parameters

In contrast to type preferences, the resolver will not perform checks if the
provided value satisfies the required type. It will be used directly to inject
the value.

There are several ways to define injections.

- An IoC container service name as string: This is only possible if the required
type is a class or interface. For other types (scalars, `iterable`,
`callable`, etc) or typeless parameters, the string value is passed __as is__.

- An instance of `Laminas\Di\Resolver\ValueInjection`: Injects the value returned
by `getValue()` as is.

- An instance of `Laminas\Di\Resolver\TypeInjection`: Obtains the injected value
from the IoC container by passing the return value of `getType()` to the
container's `get()` method.

- The string literal `'*'`: This requests the injector to ignore any previously
defined parameter and use the type preference resolution as described in
[Type Preferences](#type-preferences).

- Any other value will be used as is and encapsulated in a
`Laminas\Di\Resolver\ValueInjection`. If the provided value's type does not fit
the required parameter type, an exception is thrown.

## Aliases

Aliases allow you to configure the same class with different construction
options. Aliases can directly be created with the injector or declared as type
preferences.

An alias must refer to an actual class or an interface, therefore you cannot
declare aliases for another alias.

For example the following the following class should be instantiated in two
different ways:

```php
// Assume the following classes are declared:

class Foo
{}

class SpecialFoo extends Foo
{}

class MyClass
{
public function __construct(Foo $foo, string $bar)
{
// ...
}
}

// With the following injection config:

use Laminas\Di\Injector;
use Laminas\Di\Config;

$injector = new Injector(new Config([
'types' => [
MyClass::class => [
'parameters' => [
'foo' => SpecialFoo::class,
'bar' => 'Stringvalue',
],
],
'MyClass.Alias' => [
'typeOf' => MyClass::class,
'parameters' => [
'foo' => '*',
'bar' => 'Stringvalue',
],
],
],
]));

// The results are:
$a = $injector->create(MyClass::class); // Constructed with SpecialFoo
$b = $injector->create('MyClass.Alias'); // Constructed with Foo (since there are no type preferences for Foo)
```
<noscript><meta http-equiv="refresh" content="0; url=/laminas-di/v3/config/"></noscript>
<script>
document.addEventListener("DOMContentLoaded", function (event) {
window.location.pathname = '/laminas-di/v3/config/';
});
</script>
Loading

0 comments on commit 09c338d

Please sign in to comment.