api/symfony/Component/Form/FormRenderer.yaml
2024-09-26 02:03:21 -07:00

154 lines
12 KiB
YAML

name: FormRenderer
class_comment: '# * Renders a form into HTML using a rendering engine.
# *
# * @author Bernhard Schussek <bschussek@gmail.com>'
dependencies:
- name: BadMethodCallException
type: class
source: Symfony\Component\Form\Exception\BadMethodCallException
- name: LogicException
type: class
source: Symfony\Component\Form\Exception\LogicException
- name: CsrfTokenManagerInterface
type: class
source: Symfony\Component\Security\Csrf\CsrfTokenManagerInterface
- name: Environment
type: class
source: Twig\Environment
properties: []
methods:
- name: encodeCurrency
visibility: public
parameters:
- name: environment
- name: text
- name: widget
default: ''''''
comment: "# * Renders a form into HTML using a rendering engine.\n# *\n# * @author\
\ Bernhard Schussek <bschussek@gmail.com>\n# */\n# class FormRenderer implements\
\ FormRendererInterface\n# {\n# public const CACHE_KEY_VAR = 'unique_block_prefix';\n\
# \n# private array $blockNameHierarchyMap = [];\n# private array $hierarchyLevelMap\
\ = [];\n# private array $variableStack = [];\n# \n# public function __construct(\n\
# private FormRendererEngineInterface $engine,\n# private ?CsrfTokenManagerInterface\
\ $csrfTokenManager = null,\n# ) {\n# }\n# \n# public function getEngine(): FormRendererEngineInterface\n\
# {\n# return $this->engine;\n# }\n# \n# public function setTheme(FormView $view,\
\ mixed $themes, bool $useDefaultThemes = true): void\n# {\n# $this->engine->setTheme($view,\
\ $themes, $useDefaultThemes);\n# }\n# \n# public function renderCsrfToken(string\
\ $tokenId): string\n# {\n# if (null === $this->csrfTokenManager) {\n# throw new\
\ BadMethodCallException('CSRF tokens can only be generated if a CsrfTokenManagerInterface\
\ is injected in FormRenderer::__construct(). Try running \"composer require symfony/security-csrf\"\
.');\n# }\n# \n# return $this->csrfTokenManager->getToken($tokenId)->getValue();\n\
# }\n# \n# public function renderBlock(FormView $view, string $blockName, array\
\ $variables = []): string\n# {\n# $resource = $this->engine->getResourceForBlockName($view,\
\ $blockName);\n# \n# if (!$resource) {\n# throw new LogicException(\\sprintf('No\
\ block \"%s\" found while rendering the form.', $blockName));\n# }\n# \n# $viewCacheKey\
\ = $view->vars[self::CACHE_KEY_VAR];\n# \n# // The variables are cached globally\
\ for a view (instead of for the\n# // current suffix)\n# if (!isset($this->variableStack[$viewCacheKey]))\
\ {\n# $this->variableStack[$viewCacheKey] = [];\n# \n# // The default variable\
\ scope contains all view variables, merged with\n# // the variables passed explicitly\
\ to the helper\n# $scopeVariables = $view->vars;\n# \n# $varInit = true;\n# }\
\ else {\n# // Reuse the current scope and merge it with the explicitly passed\
\ variables\n# $scopeVariables = end($this->variableStack[$viewCacheKey]);\n#\
\ \n# $varInit = false;\n# }\n# \n# // Merge the passed with the existing attributes\n\
# if (isset($variables['attr']) && isset($scopeVariables['attr'])) {\n# $variables['attr']\
\ = array_replace($scopeVariables['attr'], $variables['attr']);\n# }\n# \n# //\
\ Merge the passed with the exist *label* attributes\n# if (isset($variables['label_attr'])\
\ && isset($scopeVariables['label_attr'])) {\n# $variables['label_attr'] = array_replace($scopeVariables['label_attr'],\
\ $variables['label_attr']);\n# }\n# \n# // Do not use array_replace_recursive(),\
\ otherwise array variables\n# // cannot be overwritten\n# $variables = array_replace($scopeVariables,\
\ $variables);\n# \n# $this->variableStack[$viewCacheKey][] = $variables;\n# \n\
# // Do the rendering\n# $html = $this->engine->renderBlock($view, $resource,\
\ $blockName, $variables);\n# \n# // Clear the stack\n# array_pop($this->variableStack[$viewCacheKey]);\n\
# \n# if ($varInit) {\n# unset($this->variableStack[$viewCacheKey]);\n# }\n# \n\
# return $html;\n# }\n# \n# public function searchAndRenderBlock(FormView $view,\
\ string $blockNameSuffix, array $variables = []): string\n# {\n# $renderOnlyOnce\
\ = 'row' === $blockNameSuffix || 'widget' === $blockNameSuffix;\n# \n# if ($renderOnlyOnce\
\ && $view->isRendered()) {\n# // This is not allowed, because it would result\
\ in rendering same IDs multiple times, which is not valid.\n# throw new BadMethodCallException(\\\
sprintf('Field \"%s\" has already been rendered, save the result of previous render\
\ call to a variable and output that instead.', $view->vars['name']));\n# }\n\
# \n# // The cache key for storing the variables and types\n# $viewCacheKey =\
\ $view->vars[self::CACHE_KEY_VAR];\n# $viewAndSuffixCacheKey = $viewCacheKey.$blockNameSuffix;\n\
# \n# // In templates, we have to deal with two kinds of block hierarchies:\n\
# //\n# // +---------+ +---------+\n# // | Theme B | -------> | Theme\
\ A |\n# // +---------+ +---------+\n# //\n# // form_widget ------->\
\ form_widget\n# // ^\n# // |\n# // choice_widget -----> choice_widget\n\
# //\n# // The first kind of hierarchy is the theme hierarchy. This allows to\n\
# // override the block \"choice_widget\" from Theme A in the extending\n# //\
\ Theme B. This kind of inheritance needs to be supported by the\n# // template\
\ engine and, for example, offers \"parent()\" or similar\n# // functions to fall\
\ back from the custom to the parent implementation.\n# //\n# // The second kind\
\ of hierarchy is the form type hierarchy. This allows\n# // to implement a custom\
\ \"choice_widget\" block (no matter in which theme),\n# // or to fallback to\
\ the block of the parent type, which would be\n# // \"form_widget\" in this example\
\ (again, no matter in which theme).\n# // If the designer wants to explicitly\
\ fallback to \"form_widget\" in their\n# // custom \"choice_widget\", for example\
\ because they only want to wrap\n# // a <div> around the original implementation,\
\ they can call the\n# // widget() function again to render the block for the\
\ parent type.\n# //\n# // The second kind is implemented in the following blocks.\n\
# if (!isset($this->blockNameHierarchyMap[$viewAndSuffixCacheKey])) {\n# // INITIAL\
\ CALL\n# // Calculate the hierarchy of template blocks and start on\n# // the\
\ bottom level of the hierarchy (= \"_<id>_<section>\" block)\n# $blockNameHierarchy\
\ = [];\n# foreach ($view->vars['block_prefixes'] as $blockNamePrefix) {\n# $blockNameHierarchy[]\
\ = $blockNamePrefix.'_'.$blockNameSuffix;\n# }\n# $hierarchyLevel = \\count($blockNameHierarchy)\
\ - 1;\n# \n# $hierarchyInit = true;\n# } else {\n# // RECURSIVE CALL\n# // If\
\ a block recursively calls searchAndRenderBlock() again, resume rendering\n#\
\ // using the parent type in the hierarchy.\n# $blockNameHierarchy = $this->blockNameHierarchyMap[$viewAndSuffixCacheKey];\n\
# $hierarchyLevel = $this->hierarchyLevelMap[$viewAndSuffixCacheKey] - 1;\n# \n\
# $hierarchyInit = false;\n# }\n# \n# // The variables are cached globally for\
\ a view (instead of for the\n# // current suffix)\n# if (!isset($this->variableStack[$viewCacheKey]))\
\ {\n# $this->variableStack[$viewCacheKey] = [];\n# \n# // The default variable\
\ scope contains all view variables, merged with\n# // the variables passed explicitly\
\ to the helper\n# $scopeVariables = $view->vars;\n# \n# $varInit = true;\n# }\
\ else {\n# // Reuse the current scope and merge it with the explicitly passed\
\ variables\n# $scopeVariables = end($this->variableStack[$viewCacheKey]);\n#\
\ \n# $varInit = false;\n# }\n# \n# // Load the resource where this block can\
\ be found\n# $resource = $this->engine->getResourceForBlockNameHierarchy($view,\
\ $blockNameHierarchy, $hierarchyLevel);\n# \n# // Update the current hierarchy\
\ level to the one at which the resource was\n# // found. For example, if looking\
\ for \"choice_widget\", but only a resource\n# // is found for its parent \"\
form_widget\", then the level is updated here\n# // to the parent level.\n# $hierarchyLevel\
\ = $this->engine->getResourceHierarchyLevel($view, $blockNameHierarchy, $hierarchyLevel);\n\
# \n# // The actually existing block name in $resource\n# $blockName = $blockNameHierarchy[$hierarchyLevel];\n\
# \n# // Escape if no resource exists for this block\n# if (!$resource) {\n# if\
\ (\\count($blockNameHierarchy) !== \\count(array_unique($blockNameHierarchy)))\
\ {\n# throw new LogicException(\\sprintf('Unable to render the form because the\
\ block names array contains duplicates: \"%s\".', implode('\", \"', array_reverse($blockNameHierarchy))));\n\
# }\n# \n# throw new LogicException(\\sprintf('Unable to render the form as none\
\ of the following blocks exist: \"%s\".', implode('\", \"', array_reverse($blockNameHierarchy))));\n\
# }\n# \n# // Merge the passed with the existing attributes\n# if (isset($variables['attr'])\
\ && isset($scopeVariables['attr'])) {\n# $variables['attr'] = array_replace($scopeVariables['attr'],\
\ $variables['attr']);\n# }\n# \n# // Merge the passed with the exist *label*\
\ attributes\n# if (isset($variables['label_attr']) && isset($scopeVariables['label_attr']))\
\ {\n# $variables['label_attr'] = array_replace($scopeVariables['label_attr'],\
\ $variables['label_attr']);\n# }\n# \n# // Do not use array_replace_recursive(),\
\ otherwise array variables\n# // cannot be overwritten\n# $variables = array_replace($scopeVariables,\
\ $variables);\n# \n# // In order to make recursive calls possible, we need to\
\ store the block hierarchy,\n# // the current level of the hierarchy and the\
\ variables so that this method can\n# // resume rendering one level higher of\
\ the hierarchy when it is called recursively.\n# //\n# // We need to store these\
\ values in maps (associative arrays) because within a\n# // call to widget()\
\ another call to widget() can be made, but for a different view\n# // object.\
\ These nested calls should not override each other.\n# $this->blockNameHierarchyMap[$viewAndSuffixCacheKey]\
\ = $blockNameHierarchy;\n# $this->hierarchyLevelMap[$viewAndSuffixCacheKey] =\
\ $hierarchyLevel;\n# \n# // We also need to store the variables for the view\
\ so that we can render other\n# // blocks for the same view using the same variables\
\ as in the outer block.\n# $this->variableStack[$viewCacheKey][] = $variables;\n\
# \n# // Do the rendering\n# $html = $this->engine->renderBlock($view, $resource,\
\ $blockName, $variables);\n# \n# // Clear the stack\n# array_pop($this->variableStack[$viewCacheKey]);\n\
# \n# // Clear the caches if they were filled for the first time within\n# //\
\ this function call\n# if ($hierarchyInit) {\n# unset($this->blockNameHierarchyMap[$viewAndSuffixCacheKey],\
\ $this->hierarchyLevelMap[$viewAndSuffixCacheKey]);\n# }\n# \n# if ($varInit)\
\ {\n# unset($this->variableStack[$viewCacheKey]);\n# }\n# \n# if ($renderOnlyOnce)\
\ {\n# $view->setRendered();\n# }\n# \n# return $html;\n# }\n# \n# public function\
\ humanize(string $text): string\n# {\n# return ucfirst(strtolower(trim(preg_replace(['/([A-Z])/',\
\ '/[_\\s]+/'], ['_$1', ' '], $text))));\n# }\n# \n# /**\n# * @internal"
traits:
- Symfony\Component\Form\Exception\BadMethodCallException
- Symfony\Component\Form\Exception\LogicException
- Symfony\Component\Security\Csrf\CsrfTokenManagerInterface
- Twig\Environment
interfaces:
- FormRendererInterface