Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00% covered (danger)
0.00%
0 / 1
50.00% covered (danger)
50.00%
4 / 8
CRAP
88.89% covered (warning)
88.89%
72 / 81
FormRenderer
0.00% covered (danger)
0.00%
0 / 1
50.00% covered (danger)
50.00%
4 / 8
33.40
88.89% covered (warning)
88.89%
72 / 81
 __construct
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
3 / 3
 getEngine
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 setTheme
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
2 / 2
 renderCsrfToken
0.00% covered (danger)
0.00%
0 / 1
6
0.00% covered (danger)
0.00%
0 / 3
 renderBlock
0.00% covered (danger)
0.00%
0 / 1
8.06
90.48% covered (success)
90.48%
19 / 21
 searchAndRenderBlock
0.00% covered (danger)
0.00%
0 / 1
16.08
93.18% covered (success)
93.18%
41 / 44
 humanize
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 encodeCurrency
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
6 / 6
<?php
/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace Symfony\Component\Form;
use Symfony\Component\Form\Exception\BadMethodCallException;
use Symfony\Component\Form\Exception\LogicException;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Twig\Environment;
/**
 * Renders a form into HTML using a rendering engine.
 *
 * @author Bernhard Schussek <bschussek@gmail.com>
 */
class FormRenderer implements FormRendererInterface
{
    const CACHE_KEY_VAR = 'unique_block_prefix';
    private $engine;
    private $csrfTokenManager;
    private $blockNameHierarchyMap = [];
    private $hierarchyLevelMap = [];
    private $variableStack = [];
    public function __construct(FormRendererEngineInterface $engine, CsrfTokenManagerInterface $csrfTokenManager = null)
    {
        $this->engine = $engine;
        $this->csrfTokenManager = $csrfTokenManager;
    }
    /**
     * {@inheritdoc}
     */
    public function getEngine()
    {
        return $this->engine;
    }
    /**
     * {@inheritdoc}
     */
    public function setTheme(FormView $view, $themes, bool $useDefaultThemes = true)
    {
        $this->engine->setTheme($view, $themes, $useDefaultThemes);
    }
    /**
     * {@inheritdoc}
     */
    public function renderCsrfToken(string $tokenId)
    {
        if (null === $this->csrfTokenManager) {
            throw new BadMethodCallException('CSRF tokens can only be generated if a CsrfTokenManagerInterface is injected in FormRenderer::__construct().');
        }
        return $this->csrfTokenManager->getToken($tokenId)->getValue();
    }
    /**
     * {@inheritdoc}
     */
    public function renderBlock(FormView $view, string $blockName, array $variables = [])
    {
        $resource = $this->engine->getResourceForBlockName($view, $blockName);
        if (!$resource) {
            throw new LogicException(sprintf('No block "%s" found while rendering the form.', $blockName));
        }
        $viewCacheKey = $view->vars[self::CACHE_KEY_VAR];
        // The variables are cached globally for a view (instead of for the
        // current suffix)
        if (!isset($this->variableStack[$viewCacheKey])) {
            $this->variableStack[$viewCacheKey] = [];
            // The default variable scope contains all view variables, merged with
            // the variables passed explicitly to the helper
            $scopeVariables = $view->vars;
            $varInit = true;
        } else {
            // Reuse the current scope and merge it with the explicitly passed variables
            $scopeVariables = end($this->variableStack[$viewCacheKey]);
            $varInit = false;
        }
        // Merge the passed with the existing attributes
        if (isset($variables['attr']) && isset($scopeVariables['attr'])) {
            $variables['attr'] = array_replace($scopeVariables['attr'], $variables['attr']);
        }
        // Merge the passed with the exist *label* attributes
        if (isset($variables['label_attr']) && isset($scopeVariables['label_attr'])) {
            $variables['label_attr'] = array_replace($scopeVariables['label_attr'], $variables['label_attr']);
        }
        // Do not use array_replace_recursive(), otherwise array variables
        // cannot be overwritten
        $variables = array_replace($scopeVariables, $variables);
        $this->variableStack[$viewCacheKey][] = $variables;
        // Do the rendering
        $html = $this->engine->renderBlock($view, $resource, $blockName, $variables);
        // Clear the stack
        array_pop($this->variableStack[$viewCacheKey]);
        if ($varInit) {
            unset($this->variableStack[$viewCacheKey]);
        }
        return $html;
    }
    /**
     * {@inheritdoc}
     */
    public function searchAndRenderBlock(FormView $view, string $blockNameSuffix, array $variables = [])
    {
        $renderOnlyOnce = 'row' === $blockNameSuffix || 'widget' === $blockNameSuffix;