├── .gitattributes
├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── composer.json
├── phpunit.xml.dist
└── src
├── DefinitionHelper
├── AliasDefinitionHelper.php
├── CreateDefinitionHelper.php
├── DefinitionHelper.php
├── ExtensionConfiguration.php
├── FactoryDefinitionHelper.php
└── ParameterDefinitionHelper.php
├── EnableFluentConfig.php
├── Import.php
├── PhpConfigFileLoader.php
├── PhpConfigLoader.php
├── Reference.php
└── functions.php
/.gitattributes:
--------------------------------------------------------------------------------
1 | # .gitattributes
2 | tests/ export-ignore
3 |
4 | # Auto detect text files and perform LF normalization
5 | * text=auto
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /vendor/
2 | /composer.lock
3 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | php:
4 | - 7.0
5 | - 7.1
6 |
7 | matrix:
8 | include:
9 | - php: 7.0
10 | env: dependencies=lowest
11 |
12 | cache:
13 | directories:
14 | - $HOME/.composer/cache
15 |
16 | before_script:
17 | - if [[ "$dependencies" != "lowest" ]]; then composer install -n ; fi
18 | - if [ "$dependencies" = "lowest" ]; then composer update --prefer-lowest --prefer-stable -n; fi;
19 |
20 | script:
21 | - vendor/bin/phpunit
22 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2017 Matthieu Napoli
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Fluent configuration for Symfony
2 |
3 | [](https://travis-ci.org/mnapoli/fluent-symfony)
4 |
5 | This package offers an alternative configuration syntax for Symfony's container, inspired by [PHP-DI's configuration](http://php-di.org/doc/php-definitions.html).
6 |
7 | - [Why?](#why)
8 | - [Comparison with existing formats](#comparison-with-existing-formats)
9 | - [Installation](#installation)
10 | - [Syntax](#syntax)
11 | - [Parameters](#parameters)
12 | - [Services](#services)
13 | - [Using the class name as the entry ID](#using-the-class-name-as-the-entry-id)
14 | - [Autowiring](#autowiring)
15 | - [Constructor arguments](#constructor-arguments)
16 | - [Dependencies](#dependencies)
17 | - [Setter injection](#setter-injection)
18 | - [Property injection](#property-injection)
19 | - [Optional service references](#optional-service-references)
20 | - [Decorated services](#decorated-services)
21 | - [Non shared services](#non-shared-services)
22 | - [Factories](#factories)
23 | - [Aliases](#aliases)
24 | - [Tags](#tags)
25 | - [Imports](#imports)
26 | - [Extensions](#extensions)
27 |
28 | ## Why?
29 |
30 | The main goal is to benefit from stricter analysis from the PHP engine and IDEs. If you are interested you can also read [why YAML was replaced by a similar syntax in PHP-DI 5](http://php-di.org/news/06-php-di-4-0-new-definitions.html).
31 |
32 | - auto-completion on classes or constants:
33 |
34 | 
35 |
36 | - auto-completion when writing configuration:
37 |
38 | 
39 |
40 | - real time validation in IDEs:
41 |
42 | 
43 |
44 | - constant support:
45 |
46 | 
47 |
48 | - better refactoring support
49 |
50 | ## Comparison with existing formats
51 |
52 | Currently, in Symfony, you can configure the container using:
53 |
54 | - YAML
55 |
56 | ```yaml
57 | parameters:
58 | mailer.transport: sendmail
59 |
60 | services:
61 | mailer:
62 | class: Mailer
63 | arguments: ['%mailer.transport%']
64 | ```
65 |
66 | - XML
67 |
68 | ```xml
69 |
70 |
73 |
74 |
75 | sendmail
76 |
77 |
78 |
79 |
80 | %mailer.transport%
81 |
82 |
83 |
84 | ```
85 |
86 | - PHP code
87 |
88 | ```php
89 | $container->setParameter('mailer.transport', 'sendmail');
90 | $container
91 | ->register('mailer', 'Mailer')
92 | ->addArgument('%mailer.transport%');
93 | ```
94 |
95 | With this package, you can now use a 4th alternative:
96 |
97 | ```php
98 | return [
99 | 'mailer.transport' => 'sendmail',
100 |
101 | 'mailer' => create(Mailer::class)
102 | ->arguments('%mailer.transport%'),
103 | ];
104 | ```
105 |
106 | ## Installation
107 |
108 | ```
109 | composer require mnapoli/fluent-symfony
110 | ```
111 |
112 | To enable the new format in a Symfony fullstack application, simply import the `EnableFluentConfig` trait in `app/AppKernel.php`, for example:
113 |
114 | ```php
115 | load($this->getRootDir().'/config/config_'.$this->getEnvironment().'.php');
143 | }
144 | }
145 | ```
146 |
147 | - or import PHP config files from YAML config files:
148 |
149 | ```yaml
150 | imports:
151 | - services.php
152 |
153 | # ...
154 | ```
155 |
156 | Be advised that PHP config files in the "traditional" form ([see the documentation](http://symfony.com/doc/current/components/dependency_injection.html#setting-up-the-container-with-configuration-files)) *are still supported* and will continue to work.
157 |
158 | ## Syntax
159 |
160 | A configuration file must `return` a PHP array. In that array, parameters, services and imports are defined altogether:
161 |
162 | ```php
163 | 'bar',
178 | ];
179 | ```
180 |
181 | This is the same as:
182 |
183 | ```yaml
184 | parameters:
185 | foo: 'bar'
186 | ```
187 |
188 | Parameters and services can be mixed in the same array.
189 |
190 | ## Services
191 |
192 | Services can be declared simply using the `create()` function helper:
193 |
194 | ```php
195 | use function Fluent\create;
196 |
197 | return [
198 | 'mailer' => create(Mailer::class),
199 | ];
200 | ```
201 |
202 | When calling `$container->get('mailer')` an instance of the `Mailer` class will be created and returned.
203 |
204 | This is the same as:
205 |
206 | ```yaml
207 | services:
208 | mailer:
209 | class: Mailer
210 | ```
211 |
212 | #### Using the class name as the entry ID
213 |
214 | If the container entry ID is a class name, you can skip it when calling `create()`.
215 |
216 | ```php
217 | return [
218 | Mailer::class => create(),
219 | ];
220 | ```
221 |
222 | #### Autowiring
223 |
224 | Services can also be [automatically wired](http://symfony.com/doc/current/components/dependency_injection/autowiring.html) using the `autowire()` function helper in place of `create()`:
225 |
226 | ```php
227 | use function Fluent\autowire;
228 |
229 | return [
230 | Mailer::class => autowire(),
231 | ];
232 | ```
233 |
234 | This is the same as:
235 |
236 | ```yaml
237 | services:
238 | Mailer:
239 | class: Mailer
240 | autowire: true
241 | ```
242 |
243 | #### Constructor arguments
244 |
245 | ```php
246 | return [
247 | 'mailer' => create(Mailer::class)
248 | ->arguments('smtp.google.com', 2525),
249 | ];
250 | ```
251 |
252 | This is the same as:
253 |
254 | ```yaml
255 | services:
256 | mailer:
257 | class: Mailer
258 | arguments: ['smtp.google.com', 2525]
259 | ```
260 |
261 | #### Dependencies
262 |
263 | Parameters can be injected using the `'%foo%'` syntax:
264 |
265 | ```php
266 | return [
267 | 'mailer' => create(Mailer::class)
268 | ->arguments('%mailer.transport%'),
269 | ];
270 | ```
271 |
272 | This is the same as:
273 |
274 | ```yaml
275 | services:
276 | mailer:
277 | class: Mailer
278 | arguments: ['%mailer.transport%']
279 | ```
280 |
281 | Services can be injected using the `get()` function helper:
282 |
283 | ```php
284 | use function Fluent\get;
285 |
286 | return [
287 | 'newsletter_manager' => create(NewsletterManager::class)
288 | ->arguments(get('mailer')),
289 | ];
290 | ```
291 |
292 | This is the same as:
293 |
294 | ```yaml
295 | services:
296 | newsletter_manager:
297 | class: NewsletterManager
298 | arguments: ['@mailer']
299 | ```
300 |
301 | #### Setter injection
302 |
303 | ```php
304 | return [
305 | 'mailer' => create(Mailer::class)
306 | ->method('setHostAndPort', 'smtp.google.com', 2525),
307 | ];
308 | ```
309 |
310 | This is the same as:
311 |
312 | ```yaml
313 | services:
314 | mailer:
315 | class: Mailer
316 | calls:
317 | - [setHostAndPort, ['smtp.google.com', 2525]]
318 | ```
319 |
320 | #### Property injection
321 |
322 | ```php
323 | return [
324 | 'mailer' => create(Mailer::class)
325 | ->property('host', 'smtp.google.com'),
326 | ];
327 | ```
328 |
329 | This is the same as:
330 |
331 | ```yaml
332 | services:
333 | mailer:
334 | class: Mailer
335 | properties:
336 | host: smtp.google.com
337 | ```
338 |
339 | #### Optional service references
340 |
341 | Services can have [optional dependencies](https://symfony.com/doc/current/service_container/optional_dependencies.html), so that the dependency is not required for it to work.
342 |
343 | ##### Setting missing dependencies to null
344 |
345 | ```php
346 | use function Fluent\create;
347 | use function Fluent\get;
348 |
349 | return [
350 | 'newsletter_manager' => create(NewsletterManager::class)
351 | ->arguments(get('mailer')->nullIfMissing()),
352 | ];
353 | ```
354 |
355 | This is the same as :
356 |
357 | ```xml
358 |
359 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 | ```
371 |
372 | ##### Ignore missing dependencies
373 |
374 | When used with setter injection, it's possible to remove the method call using `ignoreIfMissing()` :
375 |
376 | ```php
377 | use function Fluent\create;
378 | use function Fluent\get;
379 |
380 | return [
381 | 'newsletter_manager' => create(NewsletterManager::class)
382 | ->method('setMailer', get('mailer')->ignoreIfMissing()),
383 | ];
384 | ```
385 |
386 | This is the same as :
387 |
388 | ```yaml
389 | services:
390 | app.newsletter_manager:
391 | class: AppBundle\Newsletter\NewsletterManager
392 | calls:
393 | - [setMailer, ['@?app.mailer']]
394 | ```
395 |
396 | #### Private Services
397 |
398 | ```php
399 | return [
400 | Mailer::class => create()
401 | ->private(),
402 | ];
403 | ```
404 |
405 | This is the same as:
406 |
407 | ```yaml
408 | services:
409 | mailer:
410 | class: Mailer
411 | public: false
412 | ```
413 |
414 | #### Decorated services
415 |
416 | Services can be [decorated](https://symfony.com/doc/current/service_container/service_decoration.html) with the `decorate()` method
417 |
418 | ```php
419 | return [
420 | 'decorating_mailer' => create(MailerDecorator::class)
421 | ->decorate('mailer')
422 | ->argument(get('decorating_mailer.inner')),
423 | ];
424 | ```
425 |
426 | This is the same as:
427 |
428 | ```yaml
429 | services:
430 | decorating_mailer:
431 | class: 'MailerDecorator'
432 | decorates: 'mailer'
433 | arguments: ['@decorating_mailer.inner']
434 | ```
435 |
436 | If you want to apply more than one decorator to a service, you can change the inner service name (IE the decorated service) and configure the priority of decoration :
437 |
438 | ```php
439 | return [
440 | 'foo' => create(Foo::class),
441 | 'bar' => create(Bar::class)
442 | ->decorate('foo', 'bar.foo', 5)
443 | ->arguments(get('bar.foo'))
444 | ,
445 | 'baz': create(Baz::class)
446 | ->decorate('foo', 'baz.foo', 1),
447 | ->arguments(get('baz.foo'))
448 | ];
449 | ```
450 |
451 | This is the same as:
452 |
453 | ```yaml
454 | foo:
455 | class: Foo
456 |
457 | bar:
458 | class: Bar
459 | decorates: foo
460 | decoration_inner_name: 'bar.foo'
461 | decoration_priority: 5
462 | arguments: ['@bar.foo']
463 |
464 | baz:
465 | class: Baz
466 | decorates: foo
467 | decoration_inner_name: 'baz.foo'
468 | decoration_priority: 1
469 | arguments: ['@baz.inner']
470 | ```
471 |
472 | #### Non shared services
473 |
474 | All services [are shared by default](http://symfony.com/doc/current/service_container/shared.html). You can force the container to always create a new instance using the `unshared()` function helper:
475 |
476 | ```php
477 | return [
478 | 'app.phpmailer' => create(PhpMailer::class)
479 | ->unshared(),
480 | ];
481 | ```
482 |
483 | This is the same as:
484 |
485 | ```yaml
486 |
487 | services:
488 | app.phpmailer:
489 | class: AppBundle\Mail\PhpMailer
490 | shared: false
491 | ``````
492 |
493 | #### Synthetic services
494 |
495 | Services can be injected [at runtime](http://symfony.com/doc/current/service_container/synthetic_services.html). You can inject a class instance as service, instead of configuring the container to create a new instance using the `synthetic()` function helper:
496 |
497 | ```php
498 | return [
499 | 'app.phpmailer' => create(PhpMailer::class)
500 | ->synthetic(),
501 | ];
502 | ```
503 |
504 | This is the same as:
505 |
506 | ```yaml
507 |
508 | services:
509 | app.phpmailer:
510 | class: AppBundle\Mail\PhpMailer
511 | synthetic: true
512 | ```
513 |
514 | ## Factories
515 |
516 | Services can be created by [factories](https://symfony.com/doc/current/service_container/factories.html) using the `factory()` function helper:
517 |
518 | ```php
519 | use function Fluent\factory;
520 |
521 | return [
522 | 'newsletter_manager' => factory([NewsletterManager::class, 'create'], NewsletterManager::class)
523 | ->arguments('foo', 'bar'),
524 | ];
525 | ```
526 |
527 | When calling `$container->get('newsletter_manager')` the result of `NewsletterManager::create('foo', 'bar')` will be returned.
528 |
529 | This is the same as:
530 |
531 | ```yaml
532 | services:
533 | newsletter_manager:
534 | factory: ['AppBundle\Email\NewsletterManager', 'create']
535 | class: 'AppBundle\Email\NewsletterManager'
536 | arguments: ['foo', 'bar']
537 | ```
538 |
539 | When using the class name as service ID, you don't have to explicitly state the class name of the service:
540 |
541 | ```php
542 | return [
543 | // you can write:
544 | NewsletterManager::class => factory([NewsletterManager::class, 'create']),
545 | // instead of:
546 | NewsletterManager::class => factory([NewsletterManager::class, 'create'], NewsletterManager::class),
547 | ];
548 | ```
549 |
550 | ## Aliases
551 |
552 | Services can be aliased using the `alias()` function helper:
553 |
554 | ```php
555 | use function Fluent\create;
556 | use function Fluent\alias;
557 |
558 | return [
559 | 'app.phpmailer' => create(PhpMailer::class),
560 | 'app.mailer' => alias('app.phpmailer'),
561 | ];
562 | ```
563 |
564 | When calling `$container->get('app.mailer')` the `app.phpmailer` entry will be returned.
565 |
566 | This is the same as:
567 |
568 | ```yaml
569 | services:
570 | app.phpmailer:
571 | class: AppBundle\Mail\PhpMailer
572 | app.mailer:
573 | alias: app.phpmailer
574 | ```
575 |
576 | #### Private Aliases
577 |
578 | ```php
579 | return [
580 | 'app.phpmailer' => create(PhpMailer::class),
581 | 'app.mailer' => alias('app.phpmailer')
582 | ->private(),
583 | ];
584 | ```
585 |
586 | This is the same as:
587 |
588 | ```yaml
589 |
590 | services:
591 | app.phpmailer:
592 | class: AppBundle\Mail\PhpMailer
593 | app.mailer:
594 | alias: app.phpmailer
595 | public: false
596 | ```
597 |
598 | ## Tags
599 |
600 | Services can be tagged :
601 |
602 | ```php
603 | return [
604 | 'mailer' => create(Mailer::class)
605 | ->tag('foo', ['fizz' => 'buzz', 'bar' => 'baz'])
606 | ->tag('bar'),
607 | ];
608 | ```
609 |
610 | This is the same as:
611 |
612 | ```yaml
613 | services:
614 | mailer:
615 | class: Mailer
616 | tags:
617 | - {name: foo, fizz: buzz, bar: baz}
618 | - {name: bar}
619 | ```
620 |
621 | ## Imports
622 |
623 | Other configuration files can be imported using the `import()` function helper:
624 |
625 | ```php
626 | use function Fluent\import;
627 |
628 | return [
629 | import('services/mailer.php'),
630 | ];
631 | ```
632 |
633 | You will notice that the array item is not indexed by an entry ID.
634 |
635 | This is the same as:
636 |
637 | ```yaml
638 | imports:
639 | - { resource: services/mailer.yml }
640 | ```
641 |
642 | ## Extensions
643 |
644 | Extensions (like the framework configuration for example) can be configured using the `extension()` function helper:
645 |
646 | ```php
647 | use function Fluent\extension;
648 |
649 | return [
650 | extension('framework', [
651 | 'http_method_override' => true,
652 | 'trusted_proxies' => ['192.0.0.1', '10.0.0.0/8'],
653 | ]),
654 | ];
655 | ```
656 |
657 | This is the same as:
658 |
659 | ```yaml
660 | framework:
661 | http_method_override: true
662 | trusted_proxies: [192.0.0.1, 10.0.0.0/8]
663 | ```
664 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mnapoli/fluent-symfony",
3 | "license": "MIT",
4 | "autoload": {
5 | "psr-4": {
6 | "Fluent\\": "src/"
7 | },
8 | "files": [
9 | "src/functions.php"
10 | ]
11 | },
12 | "autoload-dev": {
13 | "psr-4": {
14 | "Fluent\\Test\\": "tests"
15 | }
16 | },
17 | "require": {
18 | "php": ">=7.0",
19 | "symfony/dependency-injection": "^3.2",
20 | "symfony/config": "^3.2"
21 | },
22 | "require-dev": {
23 | "phpunit/phpunit": "^6.0",
24 | "symfony/symfony": "^3.2"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
13 |
14 |
15 |
16 | ./tests/
17 |
18 |
19 |
20 |
21 |
22 | src
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/src/DefinitionHelper/AliasDefinitionHelper.php:
--------------------------------------------------------------------------------
1 |
13 | */
14 | class AliasDefinitionHelper implements DefinitionHelper
15 | {
16 | /**
17 | * @var Alias
18 | */
19 | private $alias;
20 |
21 | public function __construct(string $targetEntry)
22 | {
23 | $this->alias = new Alias($targetEntry);
24 | }
25 |
26 | /**
27 | * Marks the alias as private
28 | */
29 | public function private() : self
30 | {
31 | $this->alias->setPublic(false);
32 |
33 | return $this;
34 | }
35 |
36 | public function register(string $entryId, ContainerBuilder $container)
37 | {
38 | $container->setAlias($entryId, $this->alias);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/DefinitionHelper/CreateDefinitionHelper.php:
--------------------------------------------------------------------------------
1 |
14 | */
15 | class CreateDefinitionHelper implements DefinitionHelper
16 | {
17 | /**
18 | * @var Definition
19 | */
20 | private $definition;
21 |
22 | /**
23 | * Helper for defining an object.
24 | *
25 | * @param string|null $className Class name of the object.
26 | * If null, the name of the entry (in the container) will be used as class name.
27 | * @param bool $autowire Whether the class should be autowired.
28 | */
29 | public function __construct(string $className = null, $autowire = false)
30 | {
31 | $this->definition = new Definition($className);
32 | if ($autowire) {
33 | $this->definition->setAutowired(true);
34 | }
35 | }
36 |
37 | public function register(string $entryId, ContainerBuilder $container)
38 | {
39 | if ($this->definition->getClass() === null) {
40 | $this->definition->setClass($entryId);
41 | }
42 |
43 | $container->setDefinition($entryId, $this->definition);
44 | }
45 |
46 | /**
47 | * Define the entry as lazy.
48 | *
49 | * A lazy entry is created only when it is used, a proxy is injected instead.
50 | */
51 | public function lazy() : self
52 | {
53 | $this->definition->setLazy(true);
54 |
55 | return $this;
56 | }
57 |
58 | /**
59 | * Defines the arguments to use to call the constructor.
60 | *
61 | * This method takes a variable number of arguments, example:
62 | * ->arguments($param1, $param2, $param3)
63 | *
64 | * @param mixed ... Arguments to use for calling the constructor of the class.
65 | */
66 | public function arguments(...$arguments) : self
67 | {
68 | $this->definition->setArguments($arguments);
69 |
70 | return $this;
71 | }
72 |
73 | /**
74 | * Defines a value to inject in a property of the object.
75 | *
76 | * @param string $property Entry in which to inject the value.
77 | * @param mixed $value Value to inject in the property.
78 | */
79 | public function property(string $property, $value) : self
80 | {
81 | $this->definition->setProperty($property, $value);
82 |
83 | return $this;
84 | }
85 |
86 | /**
87 | * Defines a method to call and the arguments to use.
88 | *
89 | * This method takes a variable number of arguments after the method name, example:
90 | *
91 | * ->method('myMethod', $param1, $param2)
92 | *
93 | * Can be used multiple times to declare multiple calls.
94 | *
95 | * @param string $method Name of the method to call.
96 | * @param mixed ... Arguments to use for calling the method.
97 | */
98 | public function method(string $method, ...$arguments) : self
99 | {
100 | $this->definition->addMethodCall($method, $arguments);
101 |
102 | return $this;
103 | }
104 |
105 | /**
106 | * Adds a tag to the current definition
107 | *
108 | * Can be used multiple times to declare multiple calls.
109 | *
110 | * @param string $name The tag name
111 | * @param array $attributes An array of attributes
112 | */
113 | public function tag(string $name, array $attributes = []) : self
114 | {
115 | $this->definition->addTag($name, $attributes);
116 |
117 | return $this;
118 | }
119 |
120 | /**
121 | * Marks the definition as unshared
122 | */
123 | public function unshared() : self
124 | {
125 | $this->definition->setShared(false);
126 |
127 | return $this;
128 | }
129 |
130 | /**
131 | * Marks the definition as synthetic
132 | */
133 | public function synthetic() : self
134 | {
135 | $this->definition->setSynthetic(true);
136 |
137 | return $this;
138 | }
139 |
140 | /**
141 | * Marks the definition as private
142 | */
143 | public function private() : self
144 | {
145 | $this->definition->setPublic(false);
146 |
147 | return $this;
148 | }
149 |
150 | /**
151 |
152 | * Mark the service as deprecated
153 | *
154 | * @param string|null $template Template message to use if the definition is deprecated
155 | *
156 | * @throws InvalidArgumentException
157 | */
158 | public function deprecate(string $template = null) : self
159 | {
160 | $this->definition->setDeprecated(true, $template);
161 |
162 | return $this;
163 | }
164 |
165 | /**
166 | * Override an existing definition, keeping acces to the old one
167 | *
168 | * @param string $entryId The decorated service id
169 | * @param null|string $renamedId The new decorated service id
170 | * @param int $priority The priority of decoration
171 | */
172 | public function decorate(string $entryId, string $renamedId = null, int $priority = 0) : self
173 | {
174 | $this->definition->setDecoratedService($entryId, $renamedId, $priority);
175 |
176 | return $this;
177 | }
178 | }
179 |
--------------------------------------------------------------------------------
/src/DefinitionHelper/DefinitionHelper.php:
--------------------------------------------------------------------------------
1 |
10 | */
11 | interface DefinitionHelper
12 | {
13 | public function register(string $entryId, ContainerBuilder $container);
14 | }
15 |
--------------------------------------------------------------------------------
/src/DefinitionHelper/ExtensionConfiguration.php:
--------------------------------------------------------------------------------
1 |
10 | */
11 | class ExtensionConfiguration implements DefinitionHelper
12 | {
13 | /**
14 | * @var string
15 | */
16 | private $extensionName;
17 |
18 | /**
19 | * @var array
20 | */
21 | private $configuration;
22 |
23 | public function __construct(string $extensionName, array $configuration)
24 | {
25 | $this->extensionName = $extensionName;
26 | $this->configuration = $configuration;
27 | }
28 |
29 | public function register(string $entryId, ContainerBuilder $container)
30 | {
31 | $container->loadFromExtension($this->extensionName, $this->configuration);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/DefinitionHelper/FactoryDefinitionHelper.php:
--------------------------------------------------------------------------------
1 |
13 | */
14 | class FactoryDefinitionHelper implements DefinitionHelper
15 | {
16 | /**
17 | * @var Definition
18 | */
19 | private $definition;
20 |
21 | /**
22 | * @param string|array $factory A PHP function or an array containing a class/Reference and a method to call
23 | * @param string|null $className Class name of the object.
24 | * If null, the name of the entry (in the container) will be used as class name.
25 | */
26 | public function __construct($factory, string $className = null)
27 | {
28 | $this->definition = new Definition($className);
29 | $this->definition->setFactory($factory);
30 | }
31 |
32 | public function register(string $entryId, ContainerBuilder $container)
33 | {
34 | if ($this->definition->getClass() === null) {
35 | $this->definition->setClass($entryId);
36 | }
37 |
38 | $container->setDefinition($entryId, $this->definition);
39 | }
40 |
41 | /**
42 | * Defines the arguments to use when calling the factory.
43 | *
44 | * This method takes a variable number of arguments, example:
45 | * ->arguments($param1, $param2, $param3)
46 | */
47 | public function arguments(...$arguments) : self
48 | {
49 | $this->definition->setArguments($arguments);
50 |
51 | return $this;
52 | }
53 |
54 | /**
55 | * Marks the definition as synthetic
56 | */
57 | public function synthetic() : self
58 | {
59 | $this->definition->setSynthetic(true);
60 |
61 | return $this;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/DefinitionHelper/ParameterDefinitionHelper.php:
--------------------------------------------------------------------------------
1 |
12 | */
13 | class ParameterDefinitionHelper implements DefinitionHelper
14 | {
15 | /**
16 | * Parameter value.
17 | *
18 | * @var mixed
19 | */
20 | private $value;
21 |
22 | public function __construct($value)
23 | {
24 | $this->value = $value;
25 | }
26 |
27 | public function register(string $entryId, ContainerBuilder $container)
28 | {
29 | $container->setParameter($entryId, $this->value);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/EnableFluentConfig.php:
--------------------------------------------------------------------------------
1 |
29 | */
30 | trait EnableFluentConfig
31 | {
32 | protected function getContainerLoader(ContainerInterface $container)
33 | {
34 | $locator = new FileLocator($this);
35 | $resolver = new LoaderResolver(array(
36 | new XmlFileLoader($container, $locator),
37 | new YamlFileLoader($container, $locator),
38 | new IniFileLoader($container, $locator),
39 | new PhpConfigFileLoader($container, $locator),
40 | new DirectoryLoader($container, $locator),
41 | new ClosureLoader($container),
42 | ));
43 |
44 | return new DelegatingLoader($resolver);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/Import.php:
--------------------------------------------------------------------------------
1 |
10 | */
11 | class Import
12 | {
13 | /**
14 | * @var string
15 | */
16 | private $resource;
17 |
18 | public function __construct(string $resource)
19 | {
20 | $this->resource = $resource;
21 | }
22 |
23 | public function getResource() : string
24 | {
25 | return $this->resource;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/PhpConfigFileLoader.php:
--------------------------------------------------------------------------------
1 |
16 | */
17 | class PhpConfigFileLoader extends FileLoader
18 | {
19 | /**
20 | * @var PhpConfigLoader
21 | */
22 | private $loader;
23 |
24 | public function __construct(ContainerBuilder $container, FileLocatorInterface $locator)
25 | {
26 | parent::__construct($container, $locator);
27 |
28 | $this->loader = new PhpConfigLoader($container);
29 | }
30 |
31 | public function load($resource, $type = null)
32 | {
33 | // The container and loader variables are exposed to the included file below
34 | // This is done to support "traditional" PHP config files
35 | // @see \Symfony\Component\DependencyInjection\Loader\PhpFileLoader
36 | $container = $this->container;
37 | $loader = $this;
38 |
39 | $path = $this->locator->locate($resource);
40 | $this->setCurrentDir(dirname($path));
41 | $this->container->addResource(new FileResource($path));
42 |
43 | $definitions = require $path;
44 |
45 | if (!is_array($definitions)) {
46 | // Support for traditional PHP config files
47 | return;
48 | }
49 |
50 | // Process imports
51 | foreach ($definitions as $entryId => $definition) {
52 | if ($definition instanceof Import) {
53 | // Import the resource
54 | $this->import($definition->getResource());
55 | // Remove it from the array
56 | unset($definitions[$entryId]);
57 | }
58 | }
59 |
60 | $this->loader->load($definitions);
61 | }
62 |
63 | public function supports($resource, $type = null)
64 | {
65 | if (!is_string($resource)) {
66 | return false;
67 | }
68 |
69 | if (null === $type && 'php' === pathinfo($resource, PATHINFO_EXTENSION)) {
70 | return true;
71 | }
72 |
73 | return 'php' === $type;
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/src/PhpConfigLoader.php:
--------------------------------------------------------------------------------
1 |
15 | */
16 | class PhpConfigLoader extends Loader
17 | {
18 | /**
19 | * @var ContainerBuilder
20 | */
21 | private $container;
22 |
23 | public function __construct(ContainerBuilder $container)
24 | {
25 | $this->container = $container;
26 | }
27 |
28 | public function load($resource, $type = null)
29 | {
30 | if (!is_array($resource)) {
31 | throw new \Exception('Invalid resource');
32 | }
33 |
34 | $definitions = $resource;
35 |
36 | foreach ($definitions as $entryId => $definitionHelper) {
37 | // Raw values are automatically turned into parameters
38 | if (!$definitionHelper instanceof DefinitionHelper) {
39 | $definitionHelper = new ParameterDefinitionHelper($definitionHelper);
40 | }
41 |
42 | // Register the definition in the container
43 | $definitionHelper->register((string) $entryId, $this->container);
44 | }
45 | }
46 |
47 | public function supports($resource, $type = null)
48 | {
49 | return is_array($resource);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/Reference.php:
--------------------------------------------------------------------------------
1 | ['192.0.0.1', '10.0.0.0/8'],
81 | * ]),
82 | * ];
83 | */
84 | function extension(string $extensionName, array $config) : ExtensionConfiguration
85 | {
86 | return new ExtensionConfiguration($extensionName, $config);
87 | }
88 |
89 | }
90 |
--------------------------------------------------------------------------------