CPS-IT/handlebars

View on GitHub
Classes/DependencyInjection/HandlebarsHelperPass.php

Summary

Maintainability
A
0 mins
Test Coverage
F
0%
<?php

declare(strict_types=1);

/*
 * This file is part of the TYPO3 CMS extension "handlebars".
 *
 * Copyright (C) 2020 Elias Häußler <e.haeussler@familie-redlich.de>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
 */

namespace Fr\Typo3Handlebars\DependencyInjection;

use Fr\Typo3Handlebars\Renderer\HelperAwareInterface;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;

/**
 * HandlebarsHelperPass
 *
 * @author Elias Häußler <e.haeussler@familie-redlich.de>
 * @license GPL-2.0-or-later
 * @internal
 * @codeCoverageIgnore
 */
final class HandlebarsHelperPass implements CompilerPassInterface
{
    /**
     * @var string
     */
    private $helperTagName;

    /**
     * @var string
     */
    private $rendererTagName;

    /**
     * @var Definition[]
     */
    private $rendererDefinitions = [];

    public function __construct(string $helperTagName, string $rendererTagName)
    {
        $this->helperTagName = $helperTagName;
        $this->rendererTagName = $rendererTagName;
    }

    public function process(ContainerBuilder $container): void
    {
        $this->fetchRendererDefinitions($container);

        // Register tagged Handlebars helper at all Helper-aware renderers
        foreach ($container->findTaggedServiceIds($this->helperTagName) as $serviceId => $tags) {
            $container->findDefinition($serviceId)->setPublic(true);

            foreach (array_filter($tags) as $attributes) {
                $this->validateTag($serviceId, $attributes);
                $this->registerHelper(
                    $attributes['identifier'],
                    [new Reference($serviceId), $attributes['method']]
                );
            }
        }
    }

    /**
     * @param array{0: string|Reference, 1: string} $callable
     */
    private function registerHelper(string $name, array $callable): void
    {
        foreach ($this->rendererDefinitions as $rendererDefinition) {
            $rendererDefinition->addMethodCall('registerHelper', [$name, $callable]);
        }
    }

    protected function fetchRendererDefinitions(ContainerBuilder $container): void
    {
        $this->rendererDefinitions = [];

        foreach (array_keys($container->findTaggedServiceIds($this->rendererTagName)) as $serviceId) {
            $rendererDefinition = $container->findDefinition($serviceId);
            $rendererClass = $rendererDefinition->getClass();

            if ($rendererClass !== null && \in_array(HelperAwareInterface::class, class_implements($rendererClass) ?: [])) {
                $this->rendererDefinitions[] = $rendererDefinition;
            }
        }
    }

    /**
     * @param array<string, string> $tagAttributes
     */
    private function validateTag(string $serviceId, array $tagAttributes): void
    {
        if (!\array_key_exists('identifier', $tagAttributes) || (string)$tagAttributes['identifier'] === '') {
            throw new \InvalidArgumentException(
                sprintf('Service tag "%s" requires an identifier attribute to be defined, missing in: %s', $this->helperTagName, $serviceId),
                1606236820
            );
        }
        if (!\array_key_exists('method', $tagAttributes) || (string)$tagAttributes['method'] === '') {
            throw new \InvalidArgumentException(
                sprintf('Service tag "%s" requires an method attribute to be defined, missing in: %s', $this->helperTagName, $serviceId),
                1606245140
            );
        }
    }
}