Note: The package requires Doctrine ORM. Still, it can be used in applications which do not integrate Doctrine.

So, first thing first, the problem.

You have a Laminas / Mezzio application with a bunch of services that you need to use in a, let’s say, controller class or in any other class, and you are tired of building, updating, and maintaining factories every time you add a new dependency to your class.

DotKernel has you covered. We built a tool to autowire those dependencies in your class. There is no need for factories for every class you make. Just use one “factory” class that you tie to your custom class in the config, and that’s it.

Sounds easy, right? Let’s finish with the chat and speak some code, first showing the problem and then the solution.

The examples below are from the DotKernel API framework, but the pattern applies to all laminas and mezzio applications and to all PSR-11 applications.

class UserHandler implements RequestHandlerInterface
{
    public function __construct(
        protected UserServiceInterface $userService,
        protected array $config,
    ) {
    }
}

Above, we have a UserHandler (Controller), and we have the required dependencies: UserService and config. Normally, we would build a factory for this to get things from the container and put them in the config provider like this:

class UserHandlerFactory
{
    /**
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     */
    public function __invoke(ContainerInterface $container)
    {
        $userService = $container->get(UserService::class);
        assert($userService instanceof UserService);
        
        $config = $container->get('config');

        return new UserHandler($userService, $config);
    }
}

And in the config provider, we would have the following:

public function getDependencies(): array
{
    return [
        'factories' => [
            UserHandler::class => UserHandlerFactory::class,
        ]
    ];
}

In one more example, let’s look at the real-world required dependencies for UserService, the dependency that is required for UserHandle.

class UserService implements UserServiceInterface
{
    public function __construct(
        protected UserRoleServiceInterface $userRoleService,
        protected MailService $mailService,
        protected TemplateRendererInterface $templateRenderer,
        protected OAuthAccessTokenRepository $oAuthAccessTokenRepository,
        protected OAuthRefreshTokenRepository $oAuthRefreshTokenRepository,
        protected UserRepository $userRepository,
        protected UserDetailRepository $userDetailRepository,
        protected UserResetPasswordRepository $userResetPasswordRepository,
        protected LoggerInterface $logger,
        protected array $config = [],
    ) {
    }
}

Now consider that we need to build the factory for this and update it when we add a new dependency, and so on. Also to build the logic in the factory to handle any dependencies missing from the container. Painful right?

Now let’s use DotKernel’s dot-dependency-injection package to inject the required dependency into your class.

After you install the package, your class needs to use Dot\DependencyInjection\Attribute\Inject , then you need to add the #[Inject(...)] attribute to the constructor definition to specify which dependencies should be injected.

use Dot\DependencyInjection\Attribute\Inject;

class UserHandler implements RequestHandlerInterface
{
    #[Inject(
        UserServiceInterface::class,
        "config",
    )]
    public function __construct(
        protected UserServiceInterface $userService,
        protected array $config,
    ) {
    }
}

Add the Dot\DependencyInjection\Factory\AttributedServiceFactory class to your ConfigProvider

public function getDependencies(): array
{
    return [
        'factories' => [
            UserHandler::class => AttributedServiceFactory::class
        ]
    ];
}

That’s right, the `AttributedServiceFactory `class is the only one you need to add to your config, so you are ready to go. This class will “build” the factory for you and will handle all the logic if any dependencies are not found in the container with appropriate exceptions and messages.

One more time, let’s see how the UserService will look now.

class UserService implements UserServiceInterface
{
    use Dot\DependencyInjection\Attribute\Inject;
    
    #[Inject(
            UserRoleServiceInterface::class,
            MailService::class,
            TemplateRendererInterface::class,
            OAuthAccessTokenRepository::class,
            OAuthRefreshTokenRepository::class,
            UserRepository::class,
            UserDetailRepository::class,
            UserResetPasswordRepository::class,
            "dot-log.default_logger",
            "config",
        )]
    public function __construct(
        protected UserRoleServiceInterface $userRoleService,
        protected MailService $mailService,
        protected TemplateRendererInterface $templateRenderer,
        protected OAuthAccessTokenRepository $oAuthAccessTokenRepository,
        protected OAuthRefreshTokenRepository $oAuthRefreshTokenRepository,
        protected UserRepository $userRepository,
        protected UserDetailRepository $userDetailRepository,
        protected UserResetPasswordRepository $userResetPasswordRepository,
        protected LoggerInterface $logger,
        protected array $config = [],
    ) {
    }

}

And, that’s not all.

If you use doctrine and repository pattern and you don’t want to get your repository from EntityManager and want to inject it into your service, this package covers that too. The principle is the same, and for more insight about this, you can check the package documentation at dot-dependency-injection.


Looking for PHP, Laminas or Mezzio Support?

As part of the Laminas Commercial Vendor Program, Apidemia offers expert technical support and services for:

  • Modernising Legacy Applications
  • Migration from any version of Zend Framework to Laminas
  • Migration from legacy Laminas API Tools (formerly Apigility) to Dotkernel API
  • Mezzio and Laminas Consulting and Technical Audit
  • Leave a Reply

    Your email address will not be published. Required fields are marked *

    You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>