Using Twig renderer gives error:There are no registered paths for namespace "app"

Following shows how I tried to use Twig renderer in my Mezzio app:

<?php

declare(strict_types=1);

namespace App\Login;

use Mezzio\Twig\TwigRenderer;
use Psr\Container\ContainerInterface;

class LoginHandlerFactory
{
    public function __invoke(ContainerInterface $container): LoginHandler
    {
        $renderer  = new TwigRenderer();
        $path      = 'src/App/templates';
        $namespace = 'App';
        $renderer->addPath($path, $namespace);
        return new LoginHandler($renderer);
    }
}

I am not sure above is the right approach for passing renderer. Actually, it should be created once and available everywehere. Please let me the right place where I should place the congiuration.
Secondly, even in above usage I get the error(though the app folder is there under App namespace):
‘There are no registered paths for namespace “app”.’

The reason you are having trouble is that you are working against the application instead of working with it :slight_smile: . You are trying to configure something that is already autowired. Every time you install a Mezzio component the first thing you should do is check its ConfigProvider class. Configuration in Mezzio is aggregated and merged with later configuration winning. This is why your App ConfigProvider is loaded after the components in /config/config.php. Thanks to the abstraction of mezzio/mezzio-template and given the correct configuration being present in your ConfigProvider laminas-view and twig should use the same signature for rendering.

The first step in being able to use laminas/mezzio components is figuring out how to call the service you need to inject. If you look here:

You will see the twig package sets up an “alias” that points TemplateRendererInterface to the TwigRenderer service. You call ALL supported underlying TemplateRendererInterface implementers using this alias. This is what allows them to be swapped without any further changes to the application. So, given the ConfigProvider I linked you to from the twig package it shows us that it does not matter if we are using laminas-view or twig in our factories we call the service by the interface ie:

$renderer = $container->get(TemplateRendererInterface::class);

In laminas/mezzio this is a critical point to understand. All of the packages follow this same pattern of usage. Then, once you see which factory is responsible for the renderer instance creation you can then review it to see how it consumes the config service to see what options it supports. The twig package provides three Factories. One for the TwigRenderer, one for TwigExtension and one for TwigEnvironment. With Environment probably being the most relevant.

Here is where the default twig environment is built:

With that information in mind you can then cross reference the mezzio-twig docs for usage examples:

Another key point, is that the ‘paths’ key returned from $this->getTemplates() in the skeleton is correct. This is where you add your paths. Not in the factory for the handler. It aggregates and merges all template ‘paths’ from all modules and makes them available to the Renderer.

When you see the getTemplates() method it returns an array with a top level key of ‘paths’. The ‘paths’ key holds an array as well. With keys being your “namespace” which should point to a directory (app) inside the template directory and the values are the relative path to that directory.

This way when you call the renderer you can then pass the namespace and template name. For example if you have a template name of login.html.twig (with html.twig) being your default extension then in your LoginHandler it should render like this.

return new HtmlResponse(
            $this->template->render(
                'app::login',
            )
        );

Notice that we have wrapped the rendered template in a Laminas\Diactoros\Response\HtmlResponse
This is because the framework expects the returned response object to implement the correct interface.

Hope this helps with more than just the template issue.

1 Like