Nette Documentation Preview

syntax
Generated Factories
*******************

.[perex]
Nette DI can automatically generate factory code based on the interface, which saves you from writing code.

A factory is a class that creates and configures objects. It therefore passes their dependencies to them as well. We showed what such a factory looks like in [introduction|introduction#factory]:

```php
class ArticleFactory
{
	private Nette\Database\Connection $db;

	public function __construct(Nette\Database\Connection $db)
	{
		$this->db = $db;
	}

	public function create(): Article
	{
		return new Article($this->db);
	}
}
```

Nette DI can generate factory code automatically. All you have to do is create an interface and Nette DI will generate an implementation. The interface must have exactly one method named `create` and declare a return type:

```php
interface ArticleFactory
{
	function create(): Article;
}
```

So the factory `ArticleFactory` has a method `create` that creates objects `Article`. Class `Article` might look like the following, for example:

```php
class Article
{
	private $db;

	public function __construct(Nette\Database\Connection $db)
	{
		$this->db = $db;
	}
}
```

Add the factory to the configuration file:

```neon
services:
	- ArticleFactory
```

Nette DI will generate the corresponding factory implementation.

Thus, in the code that uses the factory, we request the object by interface and Nette DI uses the generated implementation:

```php
class UserController
{
	private $articleFactory;

	public function __construct(ArticleFactory $articleFactory)
	{
		$this->articleFactory = $articleFactory;
	}

	public function foo()
	{
		// let the factory create an object
		$article = $this->articleFactory->create();
	}
}
```


Parameterized Factory
=====================

The factory method `create` can accept parameters which it then passes to the constructor. For example, let's add an article author ID to the class `Article`:

```php
class Article
{
	private $db;
	private $authorId;

	public function __construct(Nette\Database\Connection $db, int $authorId)
	{
		$this->db = $db;
		$this->authorId = $authorId;
	}
}
```

We will also add the parameter to the factory:

```php
interface ArticleFactory
{
	function create(int $authorId): Article;
}
```

Because the parameter in the constructor and the parameter in the factory have the same name, Nette DI will pass them automatically.


Advanced Definition
===================

The definition can also be written in multi-line form using the key `implement`:

```neon
services:
	articleFactory:
		implement: ArticleFactory
```

When writing in this longer way, it is possible to provide additional arguments for the constructor in the key `arguments` and additional configuration using `setup`, just as for normal services.

Example: if the method `create()` did not accept the parameter `$authorId`, we could specify a fixed value in the configuration that would be passed to the constructor `Article`:

```neon
services:
	articleFactory:
		implement: ArticleFactory
		arguments:
			authorId: 123
```

Or, conversely, if `create()` did accept the parameter `$authorId` but it was not part of the constructor and was passed by method `Article::setAuthorId()`, we would refer to it in section `setup`:

```neon
services:
	articleFactory:
		implement: ArticleFactory
		setup:
			- setAuthorId($authorId)
```


Accessor
========

Besides factories, Nette can also generate so called accessors. Accessor is an object with `get()` method returning a particular service from the DI container. Multiple `get()` calls will always return the same instance.

Accessors bring lazy-loading to dependencies. Let's have a class logging errors to a special database. If the database connection would be passed as a dependency in its constructor, the connection would need to be always created although it would be used only rarely when an error appears so the connection would stay mostly unused.
Instead, the class can pass an accessor and when its `get()` method is called, only then the database object is created:

How to create an accessor? Write an interface only and Nette DI will generate the implementation. The interface must have exactly one method called `get` and must declare the return type:

```php
interface PDOAccessor
{
	function get(): PDO;
}
```

Add the accessor to the configuration file together with the definition of the service the accessor will return:

```neon
services:
	- PDOAccessor
	- PDO(%dsn%, %user%, %password%)
```

The accessor returns a service of type `PDO` and because there's only one such service in the configuration, the accessor will return it. With multiple configured services of that type you can specify which one should be returned using its name, for example `- PDOAccessor(@db1)`.


Multifactory/Accessor
=====================
So far, the factories and accessors could only create or return just one object. A multifactory combined with an accessor can be created as well. The interface of such multifactory class can consist of multiple methods called `create<name>()` and `get<name>()`, for example:

```php
interface MultiFactory
{
	function createArticle(): Article;
    function createFoo(): Model\Foo;
    function getDb(): PDO;
}
```

Instead of passing multiple generated factories and accessors, you can pass just one complex multifactory.

Alternatively, you can use `create()` and `get()` with a parameter instead of multiple methods:

```php
interface MultiFactoryAlt
{
	function create($name);
    function get($name): PDO;
}
```

In this case, `MultiFactory::createArticle()` does the same thing as `MultiFactoryAlt::create('article')`. However, the alternative syntax has a few disadvantages. It's not clear which `$name` values are supported and the return type cannot be specified in the interface when using multiple different `$name` values.


Definition with a List
----------------------
Hos to define a multifactory in your configuration? Let's create three services which will be returned by the multifactory, and the multifactory itself:

```neon
services:
	article: Article
	- Model\Foo
	- PDO(%dsn%, %user%, %password%)
    - MultiFactory(
        article: @article  # createArticle()
        foo: @Model\Foo    # createFoo()
        db: @\PDO          # getDb()
    )
```


Definition with Tags
--------------------

Another option how to define a multifactory is to use [tags|services#Tags]:

```neon
services:
	- App\Router\RouterFactory::createRouter
	- App\Model\DatabaseAccessor(
	    db1: @database.db1.explorer
	)
```

{{composer: nette/di}}
/--comment
TODO: extensive update
\--

Generated Factories

Nette DI can automatically generate factory code based on the interface, which saves you from writing code.

A factory is a class that creates and configures objects. It therefore passes their dependencies to them as well. We showed what such a factory looks like in introduction:

class ArticleFactory
{
	private Nette\Database\Connection $db;

	public function __construct(Nette\Database\Connection $db)
	{
		$this->db = $db;
	}

	public function create(): Article
	{
		return new Article($this->db);
	}
}

Nette DI can generate factory code automatically. All you have to do is create an interface and Nette DI will generate an implementation. The interface must have exactly one method named create and declare a return type:

interface ArticleFactory
{
	function create(): Article;
}

So the factory ArticleFactory has a method create that creates objects Article. Class Article might look like the following, for example:

class Article
{
	private $db;

	public function __construct(Nette\Database\Connection $db)
	{
		$this->db = $db;
	}
}

Add the factory to the configuration file:

services:
	- ArticleFactory

Nette DI will generate the corresponding factory implementation.

Thus, in the code that uses the factory, we request the object by interface and Nette DI uses the generated implementation:

class UserController
{
	private $articleFactory;

	public function __construct(ArticleFactory $articleFactory)
	{
		$this->articleFactory = $articleFactory;
	}

	public function foo()
	{
		// let the factory create an object
		$article = $this->articleFactory->create();
	}
}

Parameterized Factory

The factory method create can accept parameters which it then passes to the constructor. For example, let's add an article author ID to the class Article:

class Article
{
	private $db;
	private $authorId;

	public function __construct(Nette\Database\Connection $db, int $authorId)
	{
		$this->db = $db;
		$this->authorId = $authorId;
	}
}

We will also add the parameter to the factory:

interface ArticleFactory
{
	function create(int $authorId): Article;
}

Because the parameter in the constructor and the parameter in the factory have the same name, Nette DI will pass them automatically.

Advanced Definition

The definition can also be written in multi-line form using the key implement:

services:
	articleFactory:
		implement: ArticleFactory

When writing in this longer way, it is possible to provide additional arguments for the constructor in the key arguments and additional configuration using setup, just as for normal services.

Example: if the method create() did not accept the parameter $authorId, we could specify a fixed value in the configuration that would be passed to the constructor Article:

services:
	articleFactory:
		implement: ArticleFactory
		arguments:
			authorId: 123

Or, conversely, if create() did accept the parameter $authorId but it was not part of the constructor and was passed by method Article::setAuthorId(), we would refer to it in section setup:

services:
	articleFactory:
		implement: ArticleFactory
		setup:
			- setAuthorId($authorId)

Accessor

Besides factories, Nette can also generate so called accessors. Accessor is an object with get() method returning a particular service from the DI container. Multiple get() calls will always return the same instance.

Accessors bring lazy-loading to dependencies. Let's have a class logging errors to a special database. If the database connection would be passed as a dependency in its constructor, the connection would need to be always created although it would be used only rarely when an error appears so the connection would stay mostly unused. Instead, the class can pass an accessor and when its get() method is called, only then the database object is created:

How to create an accessor? Write an interface only and Nette DI will generate the implementation. The interface must have exactly one method called get and must declare the return type:

interface PDOAccessor
{
	function get(): PDO;
}

Add the accessor to the configuration file together with the definition of the service the accessor will return:

services:
	- PDOAccessor
	- PDO(%dsn%, %user%, %password%)

The accessor returns a service of type PDO and because there's only one such service in the configuration, the accessor will return it. With multiple configured services of that type you can specify which one should be returned using its name, for example - PDOAccessor(@db1).

Multifactory/Accessor

So far, the factories and accessors could only create or return just one object. A multifactory combined with an accessor can be created as well. The interface of such multifactory class can consist of multiple methods called create<name>() and get<name>(), for example:

interface MultiFactory
{
	function createArticle(): Article;
    function createFoo(): Model\Foo;
    function getDb(): PDO;
}

Instead of passing multiple generated factories and accessors, you can pass just one complex multifactory.

Alternatively, you can use create() and get() with a parameter instead of multiple methods:

interface MultiFactoryAlt
{
	function create($name);
    function get($name): PDO;
}

In this case, MultiFactory::createArticle() does the same thing as MultiFactoryAlt::create('article'). However, the alternative syntax has a few disadvantages. It's not clear which $name values are supported and the return type cannot be specified in the interface when using multiple different $name values.

Definition with a List

Hos to define a multifactory in your configuration? Let's create three services which will be returned by the multifactory, and the multifactory itself:

services:
	article: Article
	- Model\Foo
	- PDO(%dsn%, %user%, %password%)
    - MultiFactory(
        article: @article  # createArticle()
        foo: @Model\Foo    # createFoo()
        db: @\PDO          # getDb()
    )

Definition with Tags

Another option how to define a multifactory is to use tags:

services:
	- App\Router\RouterFactory::createRouter
	- App\Model\DatabaseAccessor(
	    db1: @database.db1.explorer
	)