How to include module's .phtml from layout?

Hello.

Idea:

<?php // layout.phtml

...

<body>

<?= $this->partial('sidebar') ?>

<?= $this->content ?>

</body>

?>

Problem: partial() does not work.

How to include static .phtml from current module directory?
Zend Framework 3.

The partial actually works, this is from my codebase:

somewhere in the layout.phtml
<?= $this->partial('partial/js_translations.tpl.php'); ?>

Works for Application, not modules.

Try following.
Add in module’s config key to the partial file

'view_manager'    => [
    'template_path_stack' => [
        __DIR__ . '/../view',
    ],
    'template_map'        => [
        'partial-key'     => __DIR__ . '/../view/module/partial/partial.phtml',
    ],
],

and than in layout.phtml

<?= $this->partial('partial-key'); ?>

I predict this will only work for the last module in the global /config/modules.config.php. I want each module to have a separate partial.phtml.

Actually it will be merged, so just add different key in every config array.

I will be compelled to pass it in each method of the controller? is there an easy way to get the name of the current module in the layout?

Yes there is :slight_smile: I created a module for that zend-current-route
so you can just install it and use:

$this->currentRoute()->getModule(); // return current module name

Never!

An option is a listener. Short example:

Listener:

namespace Application\Listener;

use Zend\EventManager\AbstractListenerAggregate;
use Zend\EventManager\EventManagerInterface;
use Zend\Mvc\MvcEvent;

class MyListener extends AbstractListenerAggregate
{
    public function attach(EventManagerInterface $events, $priority = 1)
    {
        $this->listeners['addSidebar'] = $events->attach(
            MvcEvent::EVENT_RENDER,
            [
                $this,
                'addSidebar',
            ]
        );
    }

    public function addSidebar(MvcEvent $event)
    {
        $serviceManager = $event->getApplication()->getServiceManager();

        /** @var \Zend\Mvc\View\Http\ViewManager $viewManager */
        $viewManager = $serviceManager->get('ViewManager');
        $viewManager->getViewModel()->addChild(
            (new \Zend\View\Model\ViewModel(
                [
                    'foo' => 'bar',
                ]
            ))->setTemplate('sidebar'),
            'sidebar'
        );
    }
}

Add to your module config:

'service_manager' => [
    'factories'  => [
        // ...
        Application\Listener\MyListener::class => Zend\ServiceManager\Factory\InvokableFactory::class,
    ],
],

Add to your module class:

public function onBootstrap(EventInterface $e)
{
    $application = $e->getApplication();

    $aggregate = $application->getServiceManager()->get(
        MyListener::class
    );
    $aggregate->attach($application->getEventManager());

    return [];
}

Create the sidebar.phtml and add in your layout:

<?= $this->sidebar ?>
1 Like

Not bad.
May be need zend-module-config? Where module’s settings will overlap Application.

Thank you!
Don’t you think that’s too much?

It’s your choice. You can copy the same code in every controller or create one listener. :wink:

With this type of listener you can also create a guard that verifies user access, you can set ACL to the navigation view helpers and so on.

Btw. this is only one idea / suggestion.

I cant understand, view helper have not access to Request object?

This is not a view helper, it is a listener which can be added in a mvc-based application. More infos can be found in the “mvc event” section of the documentation.

Btw. you can copy the code, add to your application and test it yourself.

About listener i understand.
Is it possible to solve this problem by view helper?
“Display” task by view way.
Thank you!

I cant understand, view helper have not access to Request object?

Yes it has.

You can use module that I sent you - just “plug & play it”.

I certainly encourage you to take a look at the code.
In the CurrentRouteFactory.php you can see

$routeMatch = $container->get('Application')->getMvcEvent()->getRouteMatch();

this is what you need