-
-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Using Dependency Injection With Active Record (#370)
- Loading branch information
Showing
15 changed files
with
378 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
# Using Dependency Injection With Active Record | ||
|
||
Using [dependency injection](https://github.com/yiisoft/di) in the Active Record model allows to inject dependencies | ||
into the model and use them in the model methods. | ||
|
||
To create an Active Record model with dependency injection, you need to use | ||
a [factory](https://github.com/yiisoft/factory) that will create an instance of the model and inject the dependencies | ||
into it. | ||
|
||
## Define The Active Record Model | ||
|
||
Yii Active Record provides a `FactoryTrait` trait that allows to use the factory with the Active Record class. | ||
|
||
```php | ||
use Yiisoft\ActiveRecord\ActiveQueryInterface; | ||
use Yiisoft\ActiveRecord\ActiveRecord; | ||
use Yiisoft\ActiveRecord\Trait\FactoryTrait; | ||
|
||
#[\AllowDynamicProperties] | ||
final class User extends ActiveRecord | ||
{ | ||
use FactoryTrait; | ||
|
||
public function __construct(private MyService $myService) | ||
{ | ||
} | ||
|
||
public function getTableName(): string | ||
{ | ||
return '{{%user}}'; | ||
} | ||
|
||
public function relationQuery(string $name): ActiveQueryInterface | ||
{ | ||
return match ($name) { | ||
'profile' => $this->hasOne(Profile::class, ['id' => 'profile_id']), | ||
'orders' => $this->hasMany(Order::class, ['user_id' => 'id']), | ||
default => parent::relationQuery($name), | ||
}; | ||
} | ||
|
||
public function getProfile(): Profile|null | ||
{ | ||
return $this->relation('profile'); | ||
} | ||
|
||
/** @return Order[] */ | ||
public function getOrders(): array | ||
{ | ||
return $this->relation('orders'); | ||
} | ||
} | ||
``` | ||
|
||
When you use dependency injection in the Active Record model, you need to create the Active Record instance using | ||
the factory. | ||
|
||
```php | ||
/** @var \Yiisoft\Factory\Factory $factory */ | ||
$user = $factory->create(User::class); | ||
``` | ||
|
||
To create `ActiveQuery` instance you also need to use the factory to create the Active Record model. | ||
|
||
```php | ||
$userQuery = new ActiveQuery($factory->create(User::class)->withFactory($factory)); | ||
``` | ||
|
||
## Factory Parameter In The Constructor | ||
|
||
Optionally, you can define the factory parameter in the constructor of the Active Record class. | ||
|
||
```php | ||
use Yiisoft\ActiveRecord\ActiveQueryInterface; | ||
use Yiisoft\ActiveRecord\ActiveRecord; | ||
use Yiisoft\ActiveRecord\Trait\FactoryTrait; | ||
|
||
#[\AllowDynamicProperties] | ||
final class User extends ActiveRecord | ||
{ | ||
use FactoryTrait; | ||
|
||
public function __construct(Factory $factory, private MyService $myService) | ||
{ | ||
$this->factory = $factory; | ||
} | ||
} | ||
``` | ||
|
||
This will allow to create the `ActiveQuery` instance without calling `ActiveRecord::withFactory()` method. | ||
|
||
```php | ||
$userQuery = new ActiveQuery($factory->create(User::class)); | ||
``` | ||
|
||
Back to [Create Active Record Model](docs/create-model.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Yiisoft\ActiveRecord\Trait; | ||
|
||
use Closure; | ||
use Yiisoft\ActiveRecord\ActiveQuery; | ||
use Yiisoft\ActiveRecord\ActiveQueryInterface; | ||
use Yiisoft\ActiveRecord\ActiveRecordInterface; | ||
use Yiisoft\Factory\Factory; | ||
|
||
use function is_string; | ||
use function method_exists; | ||
|
||
/** | ||
* Trait to add factory support to ActiveRecord. | ||
* | ||
* @see AbstractActiveRecord::instantiateQuery() | ||
*/ | ||
trait FactoryTrait | ||
{ | ||
private Factory $factory; | ||
|
||
/** | ||
* Set the factory to use for creating new instances. | ||
*/ | ||
public function withFactory(Factory $factory): static | ||
{ | ||
$new = clone $this; | ||
$new->factory = $factory; | ||
return $new; | ||
} | ||
|
||
public function instantiateQuery(string|ActiveRecordInterface|Closure $arClass): ActiveQueryInterface | ||
{ | ||
if (!isset($this->factory)) { | ||
return new ActiveQuery($arClass); | ||
} | ||
|
||
if (is_string($arClass)) { | ||
if (method_exists($arClass, 'withFactory')) { | ||
return new ActiveQuery( | ||
fn (): ActiveRecordInterface => $this->factory->create($arClass)->withFactory($this->factory) | ||
); | ||
} | ||
|
||
return new ActiveQuery(fn (): ActiveRecordInterface => $this->factory->create($arClass)); | ||
} | ||
|
||
if ($arClass instanceof ActiveRecordInterface && method_exists($arClass, 'withFactory')) { | ||
return new ActiveQuery( | ||
$arClass->withFactory($this->factory) | ||
); | ||
} | ||
|
||
return new ActiveQuery($arClass); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.