Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laminas Mvc Laravel Package

laminas/laminas-mvc

Laminas MVC is a modular, event-driven MVC framework for PHP applications. It provides routing, controllers, view integration, dependency injection, and configuration management, helping you build scalable, maintainable web apps and APIs on top of Laminas components.

View on GitHub
Deep Wiki
Context7

Upgrading to 2.7

Middleware

laminas-mvc now registers Laminas\Mvc\MiddlewareListener as a dispatch listener at a priority higher than Laminas\Mvc\DispatchListener, allowing dispatch of PSR-7 middleware. Read the middleware chapter for details on how to use this new feature.

Application

The constructor signature of Laminas\Mvc\Application has changed. Previously, it was:

__construct($configuration, ServiceManager $serviceManager)

and internally, it pulled the services EventManager, Request, and Response from the provided $serviceManager during initialization.

The new constructor signature provides optional arguments for injecting the event manager, request, and response:

__construct(
    $configuration,
    ServiceManager $serviceManager,
    EventManager $events = null,
    RequestInterface $request = null,
    ResponseInterface $response = null
)

This change makes all dependencies explicit. Starting in v3.0, the new arguments will be required.

The factory Laminas\Mvc\Service\ApplicationFactory was updated to follow the new signature.

This change should only affect users who are manually instantiating the Application instance.

EventManagerAware initializers

laminas-mvc provides two mechanisms for injecting event managers into EventManagerAware objects. One is the "EventManagerAwareInitializer" registered in Laminas\Mvc\Service\ServiceManagerConfig, and the other is the Laminas\Mvc\Controller\ControllerManager::injectEventManager() initializer. In both cases, the logic was updated to be forwards compatible with laminas-eventmanager v3.

Previously each would check if the instance's getEventManager() method returned an event manager instance, and, if so, inject the shared event manager:

$events = $instance->getEventManager();
if ($events instanceof EventManagerInterface) {
    $events->setSharedManager($container->get('SharedEventManager'));
}

In laminas-eventmanager v3, event managers are now injected with the shared manager at instantiation, and no setter exists for providing the shared manager. As such, the above logic changed to:

$events = $instance->getEventManager();
if (! $events || ! $events->getSharedManager()) {
    $instance->setEventManager($container->get('EventManager'));
}

In other words, it re-injects with a new event manager instance if the instance pulled does not have a shared manager composed.

This likely will not cause regressions in existing code, but may be something to be aware of if you were previously depending on lazy-loaded event manager state.

ServiceLocatorAware initializers

laminas-servicemanager v3.0 removes Laminas\ServiceManager\ServiceLocatorAwareInterface. Since laminas-mvc provides initializers around that interface, they needed updates to allow both forwards compatibility with laminas-servicemanager v3 as well as backwards compatibility with existing applications.

This was accomplished in two ways:

  • The abstract controller implementations no longer implement ServiceLocatorAwareInterface, but continue to define the methods that the interface defines (namely setServiceLocator() and getServiceLocator().
  • The initializers registered by Laminas\Mvc\Service\ServiceManagerConfig and Laminas\Mvc\Controller\ControllerManager now use duck-typing to determine if an instance requires container injection; if so it will do so.

However, we also maintain that service locator injection is an anti-pattern; dependencies should be injected directly into instances instead. As such, starting in 2.7.0, we now emit a deprecation notice any time an instance is injected by one of these initializers, and we plan to remove the initializers for version 3.0. The deprecation notice includes the name of the class, to help you identify what instances you will need to update before the laminas-mvc v3 release.

To prepare your code, you will need to do the following within your controller:

  • Find all cases where you call getServiceLocator(), and identify the services they retrieve.
  • Update your controller to accept these services via the constructor.
  • If you have not already, create a factory class for your controller.
  • In the factory, pull the appropriate services and pass them to the controller's constructor.

As an example, consider the following code from a controller:

$db = $this->getServiceLcoator()->get('Db\ApplicationAdapter');

To update your controller, you will:

  • Add a $db property to your class.
  • Update the constructor to accept the database adapter and assign it to the $db property.
  • Change the above line to either read $db = $this->db; or just use the property directly.
  • Add a factory that pulls the service and pushes it into the controller.

The controller then might look like the following:

use Laminas\Db\Adapter\AdapterInterface;
use Laminas\Mvc\Controller\AbstractActionController;

class YourController extends AbstractActionController
{
    private $db;

    public function __construct(AdapterInterface $db)
    {
        $this->db = $db;
    }

    public function someAction()
    {
        $results = $this->db->query(/* ... */);
        /* ... */
    }
}

A factory would look like the following:

use Interop\Container\ContainerInterface;

class YourControllerFactory
{
    public function __invoke(ContainerInterface $container)
    {
        return new YourController($container->get('Db\ApplicationAdapter'));
    }
}

You then also need to ensure the controller manager knows about the factory. It likely already does, as an invokable; you will redefine it as a factory in your module.config.php:

return [
    'controllers' => [
        'factories' => [
            YourController::class => YourControllerFactory::class,
            /* ... */
        ],
        /* ... */
    ],
    /* ... */
];

While this may seem like more steps, doing so ensures your code has no hidden dependencies, improves the testability of your code, and allows you to substitute alternatives for either the dependencies or the controller itself.

Optional dependencies

In some cases, you may have dependencies that are only required for some execution paths, such as forms, database adapters, etc. In these cases, you have two approaches you can use:

  • Split your controller into separate responsibilities, and use the more specific controllers. This way you don't need to inject dependencies that are only used in some actions. (We recommend doing this regardless, as it helps keep your code more maintainable.)
  • Use lazy services. When you configure these, laminas-servicemanager gives you a proxy instance that, on first access, loads the full service. This allows you to delay the most expensive operations until absolutely needed.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport
twbs/bootstrap4
php-http/client-implementation
phpcr/phpcr-implementation
cucumber/gherkin-monorepo
haydenpierce/class-finder
psr/simple-cache-implementation