Skip to content

Commit db202d4

Browse files
author
danielRConsid
committed
Add Autowire class for consistent DI support
1 parent bb349c0 commit db202d4

15 files changed

Lines changed: 159 additions & 41 deletions

README.md

Lines changed: 15 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,14 @@ Container, Factories and dependency injectors will help to make your PHP code mo
1414
Containers allowing you to easily create and retrieve objects that are needed throughout your application.
1515
```php
1616
use MaplePHP\Container\Container;
17+
1718
$container = new Container();
18-
$container->set("YourClass", \YourNamespace\To\YourClass::class); // Bind "YourClass" to container and dependency injector
19-
$yourClass = $container->get("YourClass")->get(); // Will return "YourClass"
20-
//$yourClass->yourClassMehthod();
19+
20+
// You can set mixed values in the container
21+
$container->set("hasEmail", true);
22+
23+
$hasEmail = $container->get("hasEmail")->get();
24+
var_dump($hasEmail); // Result in: (bool) true
2125
```
2226
If the constructor of "YourClass" contains unresolved class arguments, the dependency injector will attempt to automatically locate them for you. Read more under the headline **dependency injector**.
2327

@@ -40,32 +44,16 @@ Take a look at this example
4044

4145
```php
4246

43-
$container->set("YourClass", \YourNamespace\To\YourClass::class);
44-
$testService = $container->get("YourClass");
45-
echo $testService->start();
46-
47-
```
48-
The above code will load **YourClass** and auto initialize the class **Test**.
49-
50-
```php
51-
namespace YourNamespace\To;
52-
53-
use YourNamespace\ToTestClasses\Test;
54-
55-
class YourClass {
56-
57-
private $test;
47+
use MaplePHP\Container\Container;
48+
use MaplePHP\Container\Autowire;
49+
use App\Services\MailService;
5850

59-
// Dependency injector will auto load "Test" class and the "Test" classes and so on.
60-
function __construct(Test $test) {
61-
$this->test = $test;
62-
}
51+
$container = new Container();
52+
$container->set("MailService", new Autowire(MailService::class));
6353

64-
function start() {
65-
return $this->test->get("This is the start page");
66-
}
67-
68-
}
54+
// This will return "MailService" with all dependencies resolved on constructor
55+
$mailService = $container->get("MailService")->get();
56+
echo $mailService->send();
6957
```
7058

7159
## Event handler

composer.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,12 @@
2727
"maplephp/dto": "^3.0"
2828
},
2929
"autoload": {
30+
"files": [
31+
"src/Setup/aliases.php"
32+
],
3033
"psr-4": {
31-
"MaplePHP\\Container\\": ""
34+
"Psr\\Container\\": "src/Interfaces/",
35+
"MaplePHP\\Container\\": "src"
3236
}
3337
},
3438
"minimum-stability": "dev"

src/Autowire.php

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
<?php
2+
3+
namespace MaplePHP\Container;
4+
5+
use MaplePHP\Container\Interfaces\AutowireInterface;
6+
7+
class Autowire implements AutowireInterface
8+
{
9+
10+
private Reflection $reflect;
11+
/**
12+
* @var mixed|object|null
13+
*/
14+
private mixed $class = null;
15+
private bool $disableDI = false;
16+
17+
/**
18+
* @param string $class
19+
* @throws \ReflectionException
20+
*/
21+
public function __construct(string $class)
22+
{
23+
if (is_string($class) && class_exists($class)) {
24+
$this->reflect = new Reflection($class);
25+
} else {
26+
throw new \InvalidArgumentException("The class {$class} does not exist.");
27+
}
28+
}
29+
30+
/**
31+
* Disable the dependency injector
32+
*
33+
* Note: This method MUST be implemented in such a way as to retain the immutability
34+
*
35+
* @return $this
36+
*/
37+
public function disableDI(): self
38+
{
39+
$inst = clone $this;
40+
$inst->disableDI = true;
41+
return $inst;
42+
}
43+
44+
/**
45+
* Pass custom arguments to the class constructor
46+
*
47+
* Note: This method MUST be implemented in such a way as to retain the immutability
48+
* NOTE: This will disable the dependency injector
49+
*
50+
* @param array $args
51+
* @return $this
52+
*/
53+
public function addArgs(array $args): self
54+
{
55+
if(count($args) <= 0) {
56+
throw new \InvalidArgumentException("You must provide at least one argument.");
57+
}
58+
$inst = $this->disableDI();
59+
$inst->reflect->setArgs($args);
60+
return $inst;
61+
}
62+
63+
/**
64+
* Run the class with all dependencies.
65+
*
66+
* @return mixed
67+
* @throws \ReflectionException
68+
*/
69+
public function run(): mixed
70+
{
71+
if (is_null($this->class)) {
72+
$this->class = ($this->disableDI) ? $this->reflect->get() : $this->reflect->dependencyInjector();
73+
}
74+
return $this->class;
75+
}
76+
}

Container.php renamed to src/Container.php

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
namespace MaplePHP\Container;
66

77
use Closure;
8-
use MaplePHP\Container\Interfaces\ContainerInterface;
8+
use MaplePHP\Container\Interfaces\AutowireInterface;
9+
use Psr\Container\ContainerInterface;
910
use MaplePHP\Container\Interfaces\FactoryInterface;
1011
use MaplePHP\DTO\Format\Arr;
1112
//use MaplePHP\Container\Reflection;
@@ -112,27 +113,26 @@ public function isContainer(string $identifier): bool
112113

113114
/**
114115
* Get a container or factory
115-
* @param string $identifier [description]
116-
* @param array $args Is possible to overwrite/add __construct or method argumnets
117-
* @return mixed
116+
* @template T of object
117+
* @param class-string<T>|string $identifier The class or service identifier
118+
* @param string $identifier
119+
* @param array $args Is possible to overwrite/add __construct or method arguments
120+
* @return T
118121
* @throws ReflectionException
119122
*/
120123
public function get(string $identifier, array $args = []): mixed
121124
{
122-
if ($service = $this->getService($identifier)) {
125+
$service = $this->getService($identifier);
126+
if (isset($service)) {
123127
if (count($args) === 0) {
124128
$args = $this->getArgs($identifier);
125129
}
126130
if ($this->isFactory($identifier)) {
127131
$this->getter[$identifier] = $service(...$args);
128132
} else {
129-
if (empty($this->getter[$identifier])) {
130-
if (is_string($service) && class_exists($service)) {
131-
$reflect = new Reflection($service);
132-
if (count($args) > 0) {
133-
$reflect->setArgs($args);
134-
}
135-
$this->getter[$identifier] = $reflect->get();
133+
if (!isset($this->getter[$identifier])) {
134+
if ($service instanceof AutowireInterface) {
135+
$this->getter[$identifier] = $service->run();
136136
} else {
137137
$this->getter[$identifier] = $service;
138138
}
File renamed without changes.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
namespace MaplePHP\Container\Interfaces;
4+
5+
interface AutowireInterface
6+
{
7+
/**
8+
* Disable the dependency injector
9+
*
10+
* Note: This method MUST be implemented in such a way as to retain the immutability
11+
*
12+
* @return $this
13+
*/
14+
public function disableDI(): self;
15+
16+
/**
17+
* Pass custom arguments to the class constructor
18+
*
19+
* Note: This method MUST be implemented in such a way as to retain the immutability
20+
* Note: This will disable the dependency injector
21+
*
22+
* @param array $args
23+
* @return $this
24+
*/
25+
public function addArgs(array $args): self;
26+
27+
/**
28+
* Run the class with all dependencies.
29+
*
30+
* @return mixed
31+
* @throws \ReflectionException
32+
*/
33+
public function run(): mixed;
34+
}
File renamed without changes.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
declare(strict_types=1);
44

5-
namespace MaplePHP\Container\Interfaces;
5+
namespace Psr\Container;
66

77
/**
88
* Describes the interface of a container that exposes methods to read its entries.

0 commit comments

Comments
 (0)