tonybogdanov / magic-services-bundle
Auto-magic service definition generator for Symfony 4.0+ / 5.0+
Installs: 1 677
Dependents: 0
Suggesters: 0
Security: 0
Stars: 1
Watchers: 2
Forks: 0
Open Issues: 0
Type:symfony-bundle
Requires
- php-64bit: ^7.4
- ext-intl: *
- ext-json: *
- doctrine/annotations: 1.*
- nette/php-generator: 3.*
- symfony/console: 4.*|5.*
- symfony/filesystem: 4.*|5.*
- symfony/finder: 4.*|5.*
- symfony/framework-bundle: 4.*|5.*
- symfony/yaml: 4.*|5.*
- tonybogdanov/memoize: ^2.0.1
Requires (Dev)
- symfony/var-dumper: 4.*|5.*
README
Installation
composer require tonybogdanov/magic-services-bundle
Configuration
Example:
magic_services: definitions: autowire: false autoconfigure: false path: '%kernel.project_dir%/config/magic_services.yaml' services: - '%kernel.project_dir%/src' aware: path: '%kernel.project_dir%/src/DependencyInjection/Aware' namespace: 'App\DependencyInjection\Aware' parameters: - regex: '/^kernel\.(.+)$/i' name: 'ParameterKernel$1' - regex: '/^app\.(.+)$/i' name: 'ParameterApp$1' tags: - regex: '/^twig\.(.+)$/i' name: 'TagKernel$1' - regex: '/^app\.(.+)$/i' name: 'TagApp$1' services: - type: 'Doctrine\Common\Annotations\Reader' service: '@Doctrine\Common\Annotations\Reader' name: 'AnnotationReader' - type: 'Psr\Log\LoggerInterface' service: '@logger' name: 'Logger' - 'Doctrine\ORM\EntityManager'
definitions.autowire
Set this to TRUE
to generate a _defaults.autowire: true
entry in the generated
service definitions.
Defaults to: FALSE
.
definitions.autoconfigure
Set this to TRUE
to generate a _defaults.autoconfigure: true
entry in the
generated service definitions.
Defaults to: FALSE
.
definitions.path
Path to the configuration file where generated magic service definitions will be
stored (must end with .yml
or .yaml
).
Make sure to load the definitions file.
Defaults to: '%kernel.project_dir%/config/magic_services.yaml'
.
definitions.services
An array of folders to scan when looking up magic service classes.
Defaults to: [ '%kernel.project_dir%/src' ]
aware.path
Path to the folder where aware interfaces and traits will be generated. It should be part of your package so that composer can autoload the files.
Defaults to: '%kernel.project_dir%/src/DependencyInjection/Aware'
aware.namespace
The namespace under which all generated aware interfaces and traits will live.
Example:
The final class name of an aware interface with the name FontManager
and
configured namespace App\DependencyInjection\Aware
will be
App\DependencyInjection\Aware\FontManager\FontManagerAwareInterface
.
Defaults to: 'App\DependencyInjection\Aware'
aware.parameters
An array of definitions for generating aware interfaces from container parameters.
Each entry must be an array, or when automatic generation of optional settings is
sufficient, you can also use a string (will be used as the regex
sub-setting).
Defaults to: []
aware.parameters.*.regex
A regular expression for matching one or more parameters defined in the container, to generate aware interfaces for.
Required, no default.
aware.parameters.*.name
An optional name for the generated aware interface.
You can also use capturing groups from the regular expression to insert matched parts here.
If this is omitted, a name will be automatically selected by prepending the name of
the matched parameter with a parameter
prefix.
For example, for the kernel.project_dir
parameter, the following name will be used:
ParameterKernelProject_Dir
.
The final aware name will be normalized (see Normalization).
aware.tags
An array of definitions for generating aware interfaces from tagged services.
Each entry must be an array, or when automatic generation of optional settings is
sufficient, you can also use a string (will be used as the regex
sub-setting).
Defaults to: []
aware.tags.*.regex
A regular expression for matching one or more tags defined in the container, to generate aware interfaces for.
Required, no default.
aware.parameters.*.name
An optional name for the generated aware interface.
You can also use capturing groups from the regular expression to insert matched parts here.
If this is omitted, a name will be automatically selected by prepending the name of
the matched parameter with a parameter
prefix.
For example, for the kernel.project_dir
parameter, the following name will be used:
ParameterKernelProject_Dir
.
The final aware name will be normalized (see Normalization).
aware.services
An array of definitions for generating aware interfaces from services.
Each entry must be an array, or when automatic generation of optional settings is
sufficient, you can also use a string (will be used as the type
sub-setting).
Defaults to: []
aware.services.*.type
The type of the object an aware interface is being generated for. This should be a full class or interface name.
Required, no default.
aware.services.*.service
An optional name of a service, of the configured type, to be used for dependency injection.
If this is omitted, a service with the name of the configured type will be assumed. This is useful when using a magic service, or an interface.
aware.services.*.name
An optional name for the generated aware interface.
The final aware name will be normalized (see Normalization).
If this is omitted, a name will be automatically selected from the base name of the
configured type after stripping an Interface
suffix (if such is present).
For example, for a configured type Doctrine\Common\Annotations\Reader
the selected
name will be Reader
.
Use this to specify more concrete names to avoid duplication.
This name will be used when generating the final aware interface and trait, as well as the getters / setters.
For example, for an AnnotationReader
name & Doctrine\Common\Annotations\Reader
type, the following aware interface & trait will be generated:
Configured\Aware\Namespace\AnnotationReader\AnnotationReaderAwareInterface; Configured\Aware\Namespace\AnnotationReader\AnnotationReaderAwareTrait;
and the following getters / setters:
getAnnotationReader(): \Doctrine\Common\Annotations\Reader; setAnnotationReader( \Doctrine\Common\Annotations\Reader $annotationReader );
Commands
services:aware:dump
Dumps a table of resources to have aware interfaces & traits generated for them,
depending on the configured parameters in magic_services.aware.parameters
and
services in magic_services.aware.services
.
Use --parameters
or -p
to dump parameters.
Use --services
or -s
to dump services.
Use -ps
to dump both.
services:aware:generate
Generates aware interfaces and traits for parameters & services as discovered &
described in services:aware:dump
.
Use --parameters
or -p
to generate parameters.
Use --services
or -s
to generate services.
Use -ps
to dump both.
services:definitions:dump
Dumps a table of detected magic services depending on the configured paths in
magic_services.definitions.services
.
Use --previews
or -p
to preview the to be generated definitions.
services:definitions:generate
Generates service definitions for services as discovered & described in
services:definitions:dump
.
Dumps the definitions in the path specified by magic_services.definitions.path
.
Annotations
TonyBogdanov\MagicServices\Annotation\MagicService
Add this annotation to any class you want to have service definition generated for.
If your class uses aware interfaces or implements
TonyBogdanov\MagicServices\Aware\ServiceAwareInterface
, you don't need to also
add the annotation.
The annotation, however, allows you to further customize the generated definition:
@MagicService(ignore=true)
This will mark the inspected class as ignored by the magic services definition generator.
This could be useful when you need to write the definition yourself, but the class still implements the ServiceAwareInterface (or uses aware interfaces) and thus is considered for generation.
@MagicService(setters=false)
This will mark the service as not supporting magic setters and that it must have all of its dependencies injected as constructor arguments instead.
@MagicService(tags={"console.command","another_tag"}
This allows you to specify tags for the service.
@MagicService(public=true)
This will mark the generated service as public.
Normalization
When generating the final aware interface / trait name, a normalization process is performed on the input. When it is a class / interface name, only the base name is used.
The sequence is split into words, where each word may only contain lowercase or uppercase latin letters, numbers and an underscore. Everything else is replaced with a single space. The first letters of all words are then capitalized and the spaces are removed, but underscores are kept.
Example:
kernel.project_dir
becomesKernelProject_Dir
App\Service\FontManager
becomesFontManager
.
Aware interfaces / traits will use this name as both a folder and a class name,
adding an additional AwareInterface
and AwareTrait
suffix respectively.
Pseudo-Console
Sometimes you might need to use the magic services generation capabilities outside of a Symfony application. An example of this would be during the development of a bundle, if you don't have a corresponding bootstrapped Symfony app.
To ease the use of this tool, it comes with a built-in bootstrapped micro installation of Symfony, exposing only the magic services commands.
To use it simply locate the ./bin/console
executable within this package and use it
as you would use Symfony's console, specifying a path to a YAML file containing your
magic services configuration.
Example:
./vendor/magic-services-bundle/bin/console /path/to/config/services.yaml services:aware:dump -ps
NOTE
If you are using this method you have to keep in mind that any parameters or services you try to reference in the configuration file will be resolved in the context of the micro-kernel.
For example, a
%kernel.project_dir%
parameter will resolve to the project directory of the magic services bundle and not the bundle / project invoking the console.To be able to unambiguously reference local paths, you can use the magic parameters (only available with this custom console)
%__file__%
and%__dir__%
resolving to, respectively, the path to the configuration file and the folder of the configuration file, e.g./path/to/config/services.yaml
and/path/to/config
.