Skip to content

Commit 82655d1

Browse files
committed
Define services in convenient and readable way
1 parent cef2a97 commit 82655d1

File tree

3 files changed

+349
-0
lines changed

3 files changed

+349
-0
lines changed
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
<?php
2+
3+
/**
4+
* @copyright Copyright (C) 2013 - 2015 Open Source Matters, Inc. All rights reserved.
5+
* @license GNU General Public License version 2 or later; see LICENSE
6+
*/
7+
8+
namespace Joomla\DI\Tests;
9+
10+
use Joomla\DI\Container;
11+
use PHPUnit\Framework\TestCase;
12+
13+
include_once __DIR__ . '/Stubs/stubs.php';
14+
15+
/**
16+
* Tests for ContainerResourceDefinition class.
17+
*/
18+
class ContainerResourceDefinitionTest extends TestCase
19+
{
20+
/**
21+
* @testdox Defines services in convenient and readable way
22+
*
23+
* @covers Joomla\DI\ContainerResourceDefinition
24+
*/
25+
public function testDef(): void
26+
{
27+
$container = new Container();
28+
$container->def('foo')
29+
->shared()
30+
->protected()
31+
->aliases(['bar', 'baz'])
32+
->tags(['tag1', 'tag2'])
33+
->factory(static function () {
34+
return new Stub1();
35+
})
36+
->end();
37+
38+
39+
$foo = $container->get('foo');
40+
41+
$this->assertInstanceOf(Stub1::class, $foo);
42+
$this->assertTrue($container->isShared('foo'));
43+
$this->assertTrue($container->isProtected('foo'));
44+
45+
$this->assertSame($foo, $container->get('bar'));
46+
$this->assertSame($foo, $container->get('baz'));
47+
48+
$this->assertSame([ $foo ], $container->getTagged('tag1'));
49+
$this->assertSame([ $foo ], $container->getTagged('tag2'));
50+
}
51+
52+
/**
53+
* @testdox Creates factory automatically
54+
*
55+
* @covers Joomla\DI\ContainerResourceDefinition
56+
*/
57+
public function testDefAutoFactory(): void
58+
{
59+
$container = new Container();
60+
$container->def(Stub1::class)->end();
61+
62+
$stub1 = $container->get(Stub1::class);
63+
64+
$this->assertInstanceOf(Stub1::class, $stub1);
65+
}
66+
67+
/**
68+
* @testdox Defines lazy services
69+
*
70+
* @covers Joomla\DI\ContainerResourceDefinition
71+
*/
72+
public function testDefLazy(): void
73+
{
74+
$container = new Container();
75+
76+
$container->def(StubInterface::class)
77+
->lazy(Stub2::class)
78+
->factory(static fn () => new Stub2(new Stub1()))
79+
->end();
80+
81+
$stub1 = $container->get(StubInterface::class);
82+
83+
if (PHP_VERSION_ID >= 80400) {
84+
$this->assertTrue((new \ReflectionClass(Stub2::class))->isUninitializedLazyObject($stub1));
85+
}
86+
87+
$this->assertInstanceOf(Stub2::class, $stub1);
88+
}
89+
}

src/Container.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,21 @@ private function getMethodArgs(\ReflectionMethod $method): array
596596
return $methodArgs;
597597
}
598598

599+
/**
600+
* Define a resource (service).
601+
*
602+
* @param string $key Name of resources key to set.
603+
*
604+
* @return ContainerResourceDefinition
605+
*
606+
* @since __DEPLOY_VERSION__
607+
* @throws ProtectedKeyException Thrown if the provided key is already set and is protected.
608+
*/
609+
public function def(string $key): ContainerResourceDefinition
610+
{
611+
return new ContainerResourceDefinition($key, $this);
612+
}
613+
599614
/**
600615
* Set a resource to the container. If the value is null the resource is removed.
601616
*

src/ContainerResourceDefinition.php

Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
<?php
2+
3+
/**
4+
* Part of the Joomla Framework DI Package
5+
*
6+
* @copyright Copyright (C) 2013 - 2025 Open Source Matters, Inc. All rights reserved.
7+
* @license GNU General Public License version 2 or later; see LICENSE
8+
*/
9+
10+
namespace Joomla\DI;
11+
12+
/**
13+
* Defines services in convenient and readable way.
14+
*
15+
* @since __DEPLOY_VERSION__
16+
*/
17+
class ContainerResourceDefinition
18+
{
19+
/**
20+
* Resource key.
21+
*
22+
* @var string
23+
* @since __DEPLOY_VERSION__
24+
*/
25+
private string $key;
26+
27+
/**
28+
* Container for resource.
29+
*
30+
* @var Container
31+
* @since __DEPLOY_VERSION__
32+
*/
33+
private Container $container;
34+
35+
/**
36+
* Resource value.
37+
*
38+
* @var mixed
39+
* @since __DEPLOY_VERSION__
40+
*/
41+
private $value = null;
42+
43+
/**
44+
* Is resource shared?
45+
*
46+
* @var bool
47+
* @since __DEPLOY_VERSION__
48+
*/
49+
private bool $shared = false;
50+
51+
/**
52+
* Is resource protected?
53+
*
54+
* @var bool
55+
* @since __DEPLOY_VERSION__
56+
*/
57+
private bool $protected = false;
58+
59+
/**
60+
* Is resource lazy?
61+
*
62+
* @var bool
63+
* @since __DEPLOY_VERSION__
64+
*/
65+
private bool $lazy = false;
66+
67+
/**
68+
* Full class name of the resource.
69+
*
70+
* @var ?string
71+
* @since __DEPLOY_VERSION__
72+
*/
73+
private ?string $lazyClass = null;
74+
75+
/**
76+
* Resource aliases.
77+
*
78+
* @var array
79+
* @since __DEPLOY_VERSION__
80+
*/
81+
private array $aliases = [];
82+
83+
/**
84+
* Resource tags.
85+
*
86+
* @var array
87+
* @since __DEPLOY_VERSION__
88+
*/
89+
private array $tags = [];
90+
91+
/**
92+
* Constructor.
93+
*
94+
* @param string $key Resource key
95+
* @param Container $container Resource container
96+
*
97+
* @since __DEPLOY_VERSION__
98+
*/
99+
public function __construct(string $key, Container $container)
100+
{
101+
$this->key = $key;
102+
$this->container = $container;
103+
}
104+
105+
/**
106+
* Set resource factory.
107+
*
108+
* @param callable $factory Resource factory
109+
*
110+
* @return $this
111+
*
112+
* @since __DEPLOY_VERSION__
113+
*/
114+
public function factory(callable $factory): self
115+
{
116+
$this->value = $factory;
117+
118+
return $this;
119+
}
120+
121+
/**
122+
* Set resource value.
123+
*
124+
* @param mixed $value Resource value
125+
*
126+
* @return $this
127+
*
128+
* @since __DEPLOY_VERSION__
129+
*/
130+
public function value($value): self
131+
{
132+
$this->value = $value;
133+
134+
return $this;
135+
}
136+
137+
/**
138+
* Set resource as shared.
139+
*
140+
* @return $this
141+
*
142+
* @since __DEPLOY_VERSION__
143+
*/
144+
public function shared(): self
145+
{
146+
$this->shared = true;
147+
148+
return $this;
149+
}
150+
151+
/**
152+
* Set resource as protected.
153+
*
154+
* @return $this
155+
*
156+
* @since __DEPLOY_VERSION__
157+
*/
158+
public function protected(): self
159+
{
160+
$this->protected = true;
161+
162+
return $this;
163+
}
164+
165+
/**
166+
* Set resource as lazy.
167+
*
168+
* @param ?string $class Full class name of the resource.
169+
*
170+
* @return $this
171+
*
172+
* @since __DEPLOY_VERSION__
173+
*/
174+
public function lazy(?string $class = null): self
175+
{
176+
$this->lazy = true;
177+
178+
$this->lazyClass = $class ?? $this->key;
179+
180+
return $this;
181+
}
182+
183+
/**
184+
* Set resource aliases.
185+
*
186+
* @param array $aliases Array of aliases
187+
*
188+
* @return $this
189+
*
190+
* @since __DEPLOY_VERSION__
191+
*/
192+
public function aliases(array $aliases): self
193+
{
194+
$this->aliases = $aliases;
195+
196+
return $this;
197+
}
198+
199+
/**
200+
* Set resource tags.
201+
*
202+
* @param array $tags Array of tags
203+
*
204+
* @return $this
205+
*
206+
* @since __DEPLOY_VERSION__
207+
*/
208+
public function tags(array $tags): self
209+
{
210+
$this->tags = $tags;
211+
212+
return $this;
213+
}
214+
215+
/**
216+
* Apply the resource definition to the container.
217+
*
218+
* @return Container
219+
*
220+
* @since __DEPLOY_VERSION__
221+
*/
222+
public function end(): Container
223+
{
224+
if ($this->lazy) {
225+
$this->value = $this->container->lazy(
226+
$this->lazyClass,
227+
$this->value ?? fn () => new $this->lazyClass(),
228+
);
229+
} else {
230+
$this->value = $this->value ?? fn () => new $this->key();
231+
}
232+
233+
$this->container->set($this->key, $this->value, $this->shared, $this->protected);
234+
235+
foreach ($this->aliases as $alias) {
236+
$this->container->alias($alias, $this->key);
237+
}
238+
239+
foreach ($this->tags as $tag) {
240+
$this->container->tag($tag, [ $this->key ]);
241+
}
242+
243+
return $this->container;
244+
}
245+
}

0 commit comments

Comments
 (0)