delolmo / class-finder
Find classes within a specific directory
Requires
- php: ^8.3
- nikic/php-parser: ^4.19 || ^5.0
- symfony/finder: ^7.1
Requires (Dev)
- ext-xdebug: *
- dg/bypass-finals: ^1.7
- doctrine/coding-standard: ^12.0
- ergebnis/composer-normalize: ^2.42
- infection/infection: ^0.27
- php-parallel-lint/php-parallel-lint: ^1.4
- phpstan/phpstan: ^1.11
- phpstan/phpstan-deprecation-rules: ^1.1
- phpstan/phpstan-mockery: ^1.1
- phpstan/phpstan-phpunit: ^1.3
- phpstan/phpstan-strict-rules: ^1.5
- phpunit/phpunit: ^10.5 || ^11.2
- rector/rector: ^1.1
- roave/security-advisories: dev-latest
- squizlabs/php_codesniffer: ^3.8
- vimeo/psalm: ^5.24
This package is auto-updated.
Last update: 2024-10-30 07:15:34 UTC
README
A few design decisions
Dependencies explained
The project relies on several key dependencies:
- PHP:
^8.3
- The latest PHP version compatible with the project. - cuyz/valinor:
^1.12
- Facilitates writing strongly-typed DTOs from loosely-typed sources. - delolmo/valinor-console:
^1.7.1
- Allows using console inputs as sources for cuyz/valinor. - doctrine/orm:
^3.2
- The Object-Relational Mapper (ORM) of the library. - giggsey/libphonenumber-for-php:
^8.13
- To validate phone numbers in Doctrine embeddables. - nikic/php-parser:
^4.19
- To parse PHP files within some library tools. - pragmarx/google2fa:
^8.0
- To generate secret key for 2FA authentication. - psr/container:
^2.0
- Used for a basic ContainerInterface implementation that ensures reusability. - ramsey/uuid:
^4.7
- Enables creation of UUIDs as primary keys for entities. - ramsey/uuid-doctrine:
^2.1
- Adds 'uuid' and 'uuid_binary' Doctrine types. - simpod/doctrine-utcdatetime:
^0.3
- Converts all DateTime objects to the UTC timezone. - symfony/cache:
^7.0
- Required by doctrine/orm. - symfony/console:
^7.0
- Used to manage the command-line interface. - webmozart/assert:
^1.11
- To perform basic assertions in Doctrine embeddables.
Entities
- Standalone Objects: All entities are single, standalone objects, valid from the moment of instantiation.
- UUID Primary Keys: Primary keys are UUIDs for consistency and performance.
- Unidirectional Associations: No bidirectional associations are allowed to enhance performance.
- Unique Fields: Each entity must have a unique field in addition to the primary key to facilitate querying.
- Date/Time Fields: Should always be of type
\DateTimeImmutable
and shifted to UTC. This is automatically managed by overriding the default 'datetime_immutable' field. - Class and Method Constraints: Entity classes cannot be
final
, but, by default, all entity methods should befinal
andprivate
, and entity properties should bereadonly
. Deviations must be justified by business logic.
Commands
- Data Transfer Objects (DTOs): Commands are DTOs processed by Handlers. All Commands should extend
DelOlmoPro\Command\Command
and be declaredfinal
andreadonly
. - Entity Passing: If an entity is passed through a query, the Command object should pass one of the entity's primary keys.
- Attributes: console commands, arguments and options are configured through the
Attribute\AsCommand
,Attribute\AsArgument
andAttribute\AsOption
annotation classes, respectively. TheCommandReader
is able to read through these attributes and configure the root consoleCommand
with this information.
Handlers
- Single Responsibility: Handlers should perform only one function and accept a single Command in the __invoke function.
- Dependencies: Handler dependencies should be loaded using dependency injection.
- Final Class: Handlers should be declared
final
.
Exceptions
- Root Exception: All exceptions inherit from
DelOlmoPro\Exception\Exception
, which extends\Exception
. - Specialized Exceptions:
EntityNotFound
andEntityAlreadyExists
exceptions are defined for common use cases. - Generic Commands: Exception querys are kept generic to ensure the library's role in preserving data integrity.
Dependency injection
This library includes a very simple implementation of the Psr\Container\ContainerInterface
to manage dependencies. Basically, services get registered through the set
method - and that is that.
The whole idea is to not boostrap the project through a custom Psr\Container\ContainerInterface
, but to allow others to integrate the library into other projects that use their own dependency injection components.
Internally, some utility classes have been provided to facilitate the task of defining services:
CommandLoader
: Loads console commands from a directory and adds them to the Symfony Console Application.DescriptorLoader
: Loads descriptors from a directory and registers them in the dependency container. Assumes descriptors don't have any dependencies.DocumentLoader
: Nothing more than a DocumentManaget factory that allows adding several entity paths and adding document prefixes on a per namespace basis.EntityLoader
: Nothing more than an EntityManager factory that allows adding several entity paths and adding table prefixes on a per namespace basis.HandlerLoader
: Loads query handlers from a directory and registers them in the dependency container. Handler arguments are loaded from the container using simple autowiring.
Unfortunately, the HandlerLoader
and DescriptorLoader
classes uses the specific implementation of the Container because it requires that set
method. However, both handlers and descriptors may be easily autowired when using other dependency injection libraries.
The CommandLoader
, however, is more flexible. To load the library's commands to your own app:
- The CommandLoader reads attributes from the Commands to configure a one-stop command for the entire library.
$reader = new CommandReader($container); // pass on the PSR-11 compliant container of your choosing $reader->load('./src'); // specify the directory on which to look for Command objects
- Make sure the PSR-11 compliant container includes the definition for every handler and descriptor. The one-stop command will try to load them from the container.
- Check the command execution workflow using the verbosity modifiers (
-vvv
).