Skip to content

Laminas View Integration

Sakya edited this page Jan 21, 2021 · 10 revisions

To integrate with Laminas View and PhpRenderer, add below configuration and class to your project.
Remember to change <ProjectNamespace> to your root namespace.

By using Laminas View you can fully use Laminas Form in your project. All form helper will be available except for csrf.

CsrfHelper is coupled tightly with Laminas Session which also coupled tightly with their Laminas Dependency Container.
Laminas Dependency Container not compatible with PSR container, so it is not supported.

Install composer dependency

composer require laminas/laminas-view

Change view configuration file in your project.

<?php

namespace <ProjectNamespace>;

return [
    "view" => [
        "class" => View\LaminasView::class,
        "renderer" => View\Renderer\LaminasPhpRenderer::class
        ...
    ]
];

Add LaminasView Service Factory in service configuration file.

<?php

namespace <ProjectNamespace>;

return [
    "service" => [
        "factories" => [
            View\Renderer\LaminasPhpRenderer::class => View\Renderer\Factory\LaminasPhpRendererFactory::class,
            ...
        ]
    ]
];

Create LaminasView.php class in your project.

<?php
namespace <ProjectNamespace>\View;

use Laminas\View\View as LaminasViewView;
use Laminas\View\ViewEvent as LaminasViewEvent;
use Laminas\View\Model\ViewModel as LaminasViewModel;
use Itseasy\View\ViewInterface;
use Psr\Http\Message\ResponseInterface as Response;

class LaminasView implements ViewInterface
{
    protected $view;
    protected $renderer;
    protected $scripts = [];

    public function __construct()
    {
        $this->view = new LaminasViewView();
    }

    // Call registered ViewHelper in the renderer
    public function __call($function, $args)
    {
        $helper = $this->renderer->getHelperPluginManager();
        $function = $helper->get($function);
        return call_user_func_array($function, $args);
    }

    public function setRenderer($renderer)
    {
        $this->renderer = $renderer;
        $this->view->getEventManager()->attach(
            LaminasViewEvent::EVENT_RENDERER,
            static function () use ($renderer) {
                return $renderer;
            }
        );
    }

    public function appendScript($type, $path, array $options = []):void
    {
        if (in_array($type, ["js", "css"])) {
            $path = ltrim($path, "/");

            $script = new \StdClass();
            $script->type = $type;
            $script->path = sprintf("/%s", $path);
            $script->options = $options;
            $this->scripts[] = $script;
        }
    }

    public function appendScripts(array $scripts = []):void
    {
        foreach ($scripts as $script) {
            if (count($script) == 2) {
                list($type, $path) = $script;
                $options = [];
            } elseif (count($script) == 3) {
                list($type, $path, $options) = $script;
            } else {
                continue;
            }
            $this->appendScript($type, $path, $options);
        }
    }

    public function setLayout(string $layout)
    {
        $this->layout = $layout;
    }

    public function render(Response $response, string $template, array $variables = [], string $layout = "")
    {
        $layoutvars = (empty($variables["layout"]) ? [] : $variables["layout"]);
        $layoutvars = array_merge_recursive($layoutvars, ["scripts" => $this->scripts]);
        $variables = array_diff_key($variables, ["layout" => ["header" => []]]);

        $viewModel = new LaminasViewModel();
        $viewModel->setTemplate($template);
        $viewModel->setVariables($variables);

        $layout = $layout ? : $this->layout;
        $layoutModel = new LaminasViewModel();
        $layoutModel->setTemplate($layout);
        $layoutModel->setVariables($layoutvars);

        $layoutModel->setOption('has_parent', true);
        $layoutModel->addChild($viewModel);

        $response->getBody()->write($this->view->render($layoutModel));
        return $response;
    }
}
?>

Create LaminasPhpRendererFactory.php class in your project.

<?php

namespace <ProjectNamespace>\View\Renderer\Factory;

use Psr\Container\ContainerInterface;
use Laminas\View\Resolver\TemplatePathStack;
use Laminas\View\Renderer\PhpRenderer;
use Laminas\View\HelperPluginManager;
use Laminas\Form\View\HelperConfig as LaminasFormHelperConfig;

class LaminasPhpRendererFactory {
    public function __invoke(ContainerInterface $container) {
        $config = $container->get("Config")->getConfig();
        $viewConfig = $config["view"];
        $viewHelperConfig = $config["view_helpers"];

        $templateResolver = new TemplatePathStack([
            'script_paths' => [$viewConfig["template_path"]],
            'default_suffix' => $viewConfig["default_template_suffix"]
        ]);

        // Create the renderer
        $renderer = new PhpRenderer();
        $renderer->setResolver($templateResolver);
        $renderer->setHelperPluginManager(new HelperPluginManager($container));

        $pluginManager = $renderer->getHelperPluginManager();

        foreach ($viewHelperConfig["aliases"] as $alias => $class) {
            $pluginManager->setAlias($alias, $class);
        }

        foreach ($viewHelperConfig["factories"] as $name => $factory) {
            $pluginManager->setFactory($name, $factory);
        }

        // Include Form Helper
        $formConfig = new LaminasFormHelperConfig();
        $formConfig->configureServiceManager($pluginManager);

        return $renderer;
    }
}
?>

Clone this wiki locally