[RFC] laminas-form Twig integration

Goal

Integrate laminas-form with Twig template.

How:

Extend Twig with the laminas-form functions and helpers.
I’m not sure if some parts of laminas-view are required to make the integration works.

Demo:

I did a small demo but I couldn’t make it work, all it renders is form labels.
It was inspired from @akrabat demo (outdated)

Hi everybody, I made it work, I hope it is the right way to do it, I updated the repository:


// ... get twig environment

$helper = new FormElement();
$renderer = new PhpRenderer();

$helpers = $renderer->getHelperPluginManager();
$config  = new HelperConfig();
$serviceManager = $config->configureServiceManager($helpers);

$helper->setView($renderer);

$twigEnvironment->registerUndefinedFunctionCallback(function($name) use($serviceManager){
	
	$helper = $serviceManager->get($name);
	$callable = [$helper, '__invoke'];
	$options  = ['is_safe' => ['html']];
	$fn = new TwigFunction($name, $callable, $options);
	
	return $fn;

});

An example of this integration as a twig extensions could be like the following:

class LaminasFromTwigExtension extends AbstractExtension
{
	private $formElement;
	private $renderer;
	private $config;

	/**	
	 * @inherit
	 */
	public function __construct(FormElement $formElement, PhpRenderer $renderer, HelperConfig $config)
	{
		$this->formElement = $formElement;
		$this->renderer = $renderer;
		$this->config = $config;
	}

	public function getFunctions()
    {
		$fns = [];
		$pluginManager = $this->pluginManager();
		$serviceManager = $this->serviceManager($pluginManager);
		$aliases = $this->configure($serviceManager);
		$options  = ['is_safe' => ['html']];
		foreach ($aliases as $name => $definition) {
			if ($serviceManager->has($name)) {
				$plugin = $serviceManager->get($name);
				$callable = [$plugin, '__invoke'];
				$fns[] = new TwigFunction($name, $callable, $options);
			}
		}
		return $fns;
	}

	private function pluginManager(): HelperPluginManager
	{
		return $this->renderer->getHelperPluginManager();
	}

	private function serviceManager(HelperPluginManager $pluginManager): ServiceManager
	{
		$this->renderer->setHelperPluginManager($this->config->configureServiceManager($pluginManager));
		return $this->config->configureServiceManager($pluginManager);
	}


	private function configure(ServiceManager $serviceManager): array
	{
		$this->renderer->setHelperPluginManager($serviceManager);
		$this->formElement->setView($this->renderer);
		$config = $this->config->toArray();
		return $config['aliases'];
	}
}

Is this still required? It’s more work than Twig+Form with ZF3.

Do you mean there’s another easy way to do the integration?

Using laminas-form with plates is pretty much the same:

<?php

declare(strict_types=1);

namespace Common\Plates;

use Laminas\Form\View\Helper\FormElement;
use Laminas\Form\View\HelperConfig;
use Laminas\ServiceManager\ServiceManager;
use Laminas\View\HelperPluginManager;
use Laminas\View\Renderer\PhpRenderer;
use League\Plates\Engine;
use League\Plates\Extension\ExtensionInterface;

class LaminasFormExtension implements ExtensionInterface
{
	private $formElement;
	private $renderer;
	private $config;

	public function __construct(FormElement $formElement, PhpRenderer $renderer, HelperConfig $config)
	{
		$this->formElement = $formElement;
		$this->renderer = $renderer;
		$this->config = $config;
	}

	/**
	 * @return void
	 */
	public function register(Engine $engine)
	{
		$pluginManager = $this->pluginManager();
		$serviceManager = $this->serviceManager($pluginManager);
		$aliases = $this->configure($serviceManager);
		foreach ($aliases as $name => $definition) {
			if (!strpos($name, '/') && !strpos($name, '\\')) {
				if ($serviceManager->has($name)) {
					$plugin = $serviceManager->get($name);
					$callable = [$plugin, '__invoke'];
					$engine->registerFunction($name, $callable);
				}
			}
		}
	}

	/**
	 * 
	 */
	private function pluginManager(): HelperPluginManager
	{
		return $this->renderer->getHelperPluginManager();
	}

	private function serviceManager(HelperPluginManager $pluginManager): ServiceManager
	{
		$this->renderer->setHelperPluginManager($this->config->configureServiceManager($pluginManager));
		return $this->config->configureServiceManager($pluginManager);
	}


	private function configure(ServiceManager $serviceManager): array
	{
		$this->renderer->setHelperPluginManager($serviceManager);
		$this->formElement->setView($this->renderer);
		$config = $this->config->toArray();
		return $config['aliases'];
	}
}