Exemple #1
0
 /**
  * {@inheritdoc}
  */
 public function searchAndRenderBlock(FormView $view, $blockNameSuffix, array $variables = array())
 {
     $renderOnlyOnce = 'row' === $blockNameSuffix || 'widget' === $blockNameSuffix;
     if ($renderOnlyOnce && $view->isRendered()) {
         return '';
     }
     // The cache key for storing the variables and types
     $viewCacheKey = $view->vars[self::CACHE_KEY_VAR];
     $viewAndSuffixCacheKey = $viewCacheKey . $blockNameSuffix;
     // In templates, we have to deal with two kinds of block hierarchies:
     //
     //   +---------+          +---------+
     //   | Theme B | -------> | Theme A |
     //   +---------+          +---------+
     //
     //   form_widget -------> form_widget
     //       ^
     //       |
     //  choice_widget -----> choice_widget
     //
     // The first kind of hierarchy is the theme hierarchy. This allows to
     // override the block "choice_widget" from Theme A in the extending
     // Theme B. This kind of inheritance needs to be supported by the
     // template engine and, for example, offers "parent()" or similar
     // functions to fall back from the custom to the parent implementation.
     //
     // The second kind of hierarchy is the form type hierarchy. This allows
     // to implement a custom "choice_widget" block (no matter in which theme),
     // or to fallback to the block of the parent type, which would be
     // "form_widget" in this example (again, no matter in which theme).
     // If the designer wants to explicitly fallback to "form_widget" in his
     // custom "choice_widget", for example because he only wants to wrap
     // a <div> around the original implementation, he can simply call the
     // widget() function again to render the block for the parent type.
     //
     // The second kind is implemented in the following blocks.
     if (!isset($this->blockNameHierarchyMap[$viewAndSuffixCacheKey])) {
         // INITIAL CALL
         // Calculate the hierarchy of template blocks and start on
         // the bottom level of the hierarchy (= "_<id>_<section>" block)
         $blockNameHierarchy = array();
         foreach ($view->vars['block_prefixes'] as $blockNamePrefix) {
             $blockNameHierarchy[] = $blockNamePrefix . '_' . $blockNameSuffix;
         }
         $hierarchyLevel = count($blockNameHierarchy) - 1;
         $hierarchyInit = true;
     } else {
         // RECURSIVE CALL
         // If a block recursively calls searchAndRenderBlock() again, resume rendering
         // using the parent type in the hierarchy.
         $blockNameHierarchy = $this->blockNameHierarchyMap[$viewAndSuffixCacheKey];
         $hierarchyLevel = $this->hierarchyLevelMap[$viewAndSuffixCacheKey] - 1;
         $hierarchyInit = false;
     }
     // The variables are cached globally for a view (instead of for the
     // current suffix)
     if (!isset($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;
     }
     // Load the resource where this block can be found
     $resource = $this->engine->getResourceForBlockNameHierarchy($view, $blockNameHierarchy, $hierarchyLevel);
     // Update the current hierarchy level to the one at which the resource was
     // found. For example, if looking for "choice_widget", but only a resource
     // is found for its parent "form_widget", then the level is updated here
     // to the parent level.
     $hierarchyLevel = $this->engine->getResourceHierarchyLevel($view, $blockNameHierarchy, $hierarchyLevel);
     // The actually existing block name in $resource
     $blockName = $blockNameHierarchy[$hierarchyLevel];
     // Escape if no resource exists for this block
     if (!$resource) {
         throw new FormException(sprintf('Unable to render the form as none of the following blocks exist: "%s".', implode('", "', array_reverse($blockNameHierarchy))));
     }
     // 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);
     // In order to make recursive calls possible, we need to store the block hierarchy,
     // the current level of the hierarchy and the variables so that this method can
     // resume rendering one level higher of the hierarchy when it is called recursively.
     //
     // We need to store these values in maps (associative arrays) because within a
     // call to widget() another call to widget() can be made, but for a different view
     // object. These nested calls should not override each other.
     $this->blockNameHierarchyMap[$viewAndSuffixCacheKey] = $blockNameHierarchy;
     $this->hierarchyLevelMap[$viewAndSuffixCacheKey] = $hierarchyLevel;
     // We also need to store the variables for the view so that we can render other
     // blocks for the same view using the same variables as in the outer block.
     $this->variableStack[$viewCacheKey][] = $variables;
     // Do the rendering
     $html = $this->engine->renderBlock($view, $resource, $blockName, $variables);
     // Clear the stack
     array_pop($this->variableStack[$viewCacheKey]);
     // Clear the caches if they were filled for the first time within
     // this function call
     if ($hierarchyInit) {
         unset($this->blockNameHierarchyMap[$viewAndSuffixCacheKey]);
         unset($this->hierarchyLevelMap[$viewAndSuffixCacheKey]);
     }
     if ($varInit) {
         unset($this->variableStack[$viewCacheKey]);
     }
     if ($renderOnlyOnce) {
         $view->setRendered();
     }
     return $html;
 }
Exemple #2
0
 /**
  * Renders a template.
  *
  * 1. This function first looks for a block named "_<view id>_<section>",
  * 2. if such a block is not found the function will look for a block named
  *    "<type name>_<section>",
  * 3. the type name is recursively replaced by the parent type name until a
  *    corresponding block is found
  *
  * @param FormView  $view       The form view
  * @param string    $section    The section to render (i.e. 'row', 'widget', 'label', ...)
  * @param array     $variables  Additional variables
  *
  * @return string The html markup
  *
  * @throws FormException if no template block exists to render the given section of the view
  */
 protected function render(FormView $view, $section, array $variables = array())
 {
     $mainTemplate = in_array($section, array('widget', 'row'));
     if ($mainTemplate && $view->isRendered()) {
         return '';
     }
     if (null === $this->template) {
         $this->template = reset($this->resources);
         if (!$this->template instanceof \Twig_Template) {
             $this->template = $this->environment->loadTemplate($this->template);
         }
     }
     $custom = '_' . $view->get('id');
     $rendering = $custom . $section;
     $blocks = $this->getBlocks($view);
     if (isset($this->varStack[$rendering])) {
         $typeIndex = $this->varStack[$rendering]['typeIndex'] - 1;
         $types = $this->varStack[$rendering]['types'];
         $this->varStack[$rendering]['variables'] = array_replace_recursive($this->varStack[$rendering]['variables'], $variables);
     } else {
         $types = $view->get('types');
         $types[] = $custom;
         $typeIndex = count($types) - 1;
         $this->varStack[$rendering] = array('variables' => array_replace_recursive($view->all(), $variables), 'types' => $types);
     }
     do {
         $types[$typeIndex] .= '_' . $section;
         if (isset($blocks[$types[$typeIndex]])) {
             $this->varStack[$rendering]['typeIndex'] = $typeIndex;
             // we do not call renderBlock here to avoid too many nested level calls (XDebug limits the level to 100 by default)
             ob_start();
             $this->template->displayBlock($types[$typeIndex], $this->varStack[$rendering]['variables'], $blocks);
             $html = ob_get_clean();
             if ($mainTemplate) {
                 $view->setRendered();
             }
             unset($this->varStack[$rendering]);
             return $html;
         }
     } while (--$typeIndex >= 0);
     throw new FormException(sprintf('Unable to render the form as none of the following blocks exist: "%s".', implode('", "', array_reverse($types))));
 }
 /**
  * Renders a template.
  *
  * 1. This function first looks for a function named "_<view id>_<section>",
  * 2. if such a block is not found the function will look for a block named
  *    "<type name>_<section>",
  * 3. the type name is recursively replaced by the parent type name until a
  *    corresponding block is found
  *
  * @param FormView $view    The form view
  * @param string   $section The section to render (i.e. 'row', 'widget',
  * 'label', ...)
  * @param array $variables Additional variables
  *
  * @return string The html markup
  *
  * @throws FormException if no template block exists to render the given section of the view
  */
 protected function render(FormView $view, \Smarty_Internal_Template $template, $section, array $variables = array())
 {
     $mainTemplate = in_array($section, array('widget', 'row'));
     if ($mainTemplate && $view->isRendered()) {
         return '';
     }
     $this->loadTemplates($view, $template);
     $custom = '_' . $view->get('id');
     $rendering = $custom . $section;
     if (isset($this->varStack[$rendering])) {
         $typeIndex = $this->varStack[$rendering]['typeIndex'] - 1;
         $types = $this->varStack[$rendering]['types'];
         $this->varStack[$rendering]['variables'] = array_replace_recursive($this->varStack[$rendering]['variables'], $variables);
     } else {
         $types = $view->get('types');
         $types[] = $custom;
         $typeIndex = count($types) - 1;
         $this->varStack[$rendering] = array('variables' => array_replace_recursive($view->all(), $variables), 'types' => $types);
     }
     do {
         $function = $types[$typeIndex] .= '_' . $section;
         $template = $this->lookupTemplateFunction($function);
         if ($template) {
             $this->varStack[$rendering]['typeIndex'] = $typeIndex;
             ob_start();
             $functionExists = $this->engine->renderTemplateFunction($template, $function, $this->varStack[$rendering]['variables']);
             $html = ob_get_clean();
             if ($functionExists) {
                 unset($this->varStack[$rendering]);
                 if ($mainTemplate) {
                     $view->setRendered();
                 }
                 return $html;
             }
         }
     } while (--$typeIndex >= 0);
     throw new FormException(sprintf('Unable to render the form as none of the following functions exist: "%s".', implode('", "', array_reverse($types))));
 }
 /**
  * Renders a template.
  *
  * 1. This function first looks for a block named "_<view id>_<section>",
  * 2. if such a block is not found the function will look for a block named
  *    "<type name>_<section>",
  * 3. the type name is recursively replaced by the parent type name until a
  *    corresponding block is found
  *
  * @param FormView  $view       The form view
  * @param string    $section    The section to render (i.e. 'row', 'widget', 'label', ...)
  * @param array     $variables  Additional variables
  *
  * @return string The html markup
  *
  * @throws FormException if no template block exists to render the given section of the view
  */
 protected function renderSection(FormView $view, $section, array $variables = array())
 {
     $mainTemplate = in_array($section, array('row', 'widget'));
     if ($mainTemplate && $view->isRendered()) {
         return '';
     }
     $template = null;
     $custom = '_' . $view->get('id');
     $rendering = $custom . $section;
     if (isset($this->varStack[$rendering])) {
         $typeIndex = $this->varStack[$rendering]['typeIndex'] - 1;
         $types = $this->varStack[$rendering]['types'];
         $variables = array_replace_recursive($this->varStack[$rendering]['variables'], $variables);
     } else {
         $types = $view->get('types');
         $types[] = $custom;
         $typeIndex = count($types) - 1;
         $variables = array_replace_recursive($view->all(), $variables);
         $this->varStack[$rendering]['types'] = $types;
     }
     $this->varStack[$rendering]['variables'] = $variables;
     do {
         $types[$typeIndex] .= '_' . $section;
         $template = $this->lookupTemplate($view, $types[$typeIndex]);
         if ($template) {
             $this->varStack[$rendering]['typeIndex'] = $typeIndex;
             $this->context[] = array('variables' => $variables, 'view' => $view);
             $html = $this->engine->render($template, $variables);
             array_pop($this->context);
             unset($this->varStack[$rendering]);
             if ($mainTemplate) {
                 $view->setRendered();
             }
             return $html;
         }
     } while (--$typeIndex >= 0);
     throw new FormException(sprintf('Unable to render the form as none of the following blocks exist: "%s".', implode('", "', array_reverse($types))));
 }
Exemple #5
0
 /**
  * Renders a template.
  *
  * 1. This function first looks for a block named "_<view id>_<section>",
  * 2. if such a block is not found the function will look for a block named
  *    "<type name>_<section>",
  * 3. the type name is recursively replaced by the parent type name until a
  *    corresponding block is found
  *
  * @param FormView  $view       The form view
  * @param string    $section    The section to render (i.e. 'row', 'widget', 'label', ...)
  * @param array     $variables  Additional variables
  *
  * @return string The html markup
  *
  * @throws FormException if no template block exists to render the given section of the view
  */
 protected function render(FormView $view, $section, array $variables = array())
 {
     $mainTemplate = in_array($section, array('widget', 'row'));
     if ($mainTemplate && $view->isRendered()) {
         return '';
     }
     $templates = $this->getTemplates($view);
     $blocks = $view->get('types');
     array_unshift($blocks, '_' . $view->get('id'));
     foreach ($blocks as &$block) {
         $block = $block . '_' . $section;
         if (isset($templates[$block])) {
             $this->varStack[$view] = array_replace($view->all(), isset($this->varStack[$view]) ? $this->varStack[$view] : array(), $variables);
             $html = $templates[$block]->renderBlock($block, $this->varStack[$view]);
             if ($mainTemplate) {
                 $view->setRendered();
             }
             unset($this->varStack[$view]);
             return $html;
         }
     }
     throw new FormException(sprintf('Unable to render form as none of the following blocks exist: "%s".', implode('", "', $blocks)));
 }
Exemple #6
0
 public function testFinishViewWhenFormBlockIsRoot()
 {
     $formLayoutBuilder = $this->getMock('Oro\\Bundle\\LayoutBundle\\Layout\\Form\\FormLayoutBuilderInterface');
     $type = new FormType($formLayoutBuilder);
     $formName = 'form';
     $view = new BlockView();
     $block = $this->getMock('Oro\\Component\\Layout\\BlockInterface');
     $formAccessor = $this->getMock('Oro\\Bundle\\LayoutBundle\\Layout\\Form\\FormAccessorInterface');
     $context = new LayoutContext();
     $formView = new FormView();
     $view->vars['form'] = $formView;
     $formView->children['field1'] = new FormView($formView);
     $formView->children['field2'] = new FormView($formView);
     $field3View = new FormView($formView);
     $formView->children['field3'] = $field3View;
     $field3View->children['field31'] = new FormView($field3View);
     $field3View->children['field32'] = new FormView($field3View);
     $view->children['block1'] = new BlockView($view);
     $view->children['block1']->vars['form'] = $formView['field1'];
     $view->children['block3'] = new BlockView($view);
     $view->children['block3']->vars['form'] = $field3View['field31'];
     $this->setLayoutBlocks(['root' => $view]);
     $context->set('form', $formAccessor);
     $block->expects($this->once())->method('getContext')->will($this->returnValue($context));
     $formAccessor->expects($this->once())->method('getProcessedFields')->will($this->returnValue(['field1' => 'block1', 'field2' => 'block2', 'field3.field31' => 'block3', 'field3.field32' => 'block4']));
     $type->finishView($view, $block, ['form_name' => $formName]);
     $this->assertFalse($formView->isRendered());
     $this->assertFalse($formView['field1']->isRendered());
     $this->assertTrue($formView['field2']->isRendered());
     $this->assertFalse($formView['field3']['field31']->isRendered());
     $this->assertTrue($formView['field3']['field32']->isRendered());
 }
 protected function serializeBlock(\DOMElement $parentElement, FormView $view, $blockName)
 {
     $variables = $view->vars;
     $type = null;
     foreach ($variables['block_prefixes'] as $blockPrefix) {
         if (in_array($blockPrefix, static::$baseTypes)) {
             $type = $blockPrefix;
             // We use the last found
         }
     }
     if ($view->isRendered()) {
         return;
     }
     if ('rest' == $blockName) {
         $this->serializeRestWidget($parentElement, $view, $variables);
     } else {
         switch ($type) {
             case 'text':
                 $this->serializeWidgetSimple($parentElement, $view, $variables);
                 break;
             case 'textarea':
                 $this->serializeTextareaWidget($parentElement, $view, $variables);
                 break;
             case 'email':
                 $this->serializeEmailWidget($parentElement, $view, $variables);
                 break;
             case 'integer':
                 $this->serializeIntegerWidget($parentElement, $view, $variables);
                 break;
             case 'number':
                 $this->serializeNumberWidget($parentElement, $view, $variables);
                 break;
             case 'password':
                 $this->serializePasswordWidget($parentElement, $view, $variables);
                 break;
             case 'percent':
                 $this->serializePercentWidget($parentElement, $view, $variables);
                 break;
             case 'search':
                 $this->serializeSearchWidget($parentElement, $view, $variables);
                 break;
             case 'url':
                 $this->serializeUrlWidget($parentElement, $view, $variables);
                 break;
             case 'choice':
                 $this->serializeChoiceWidget($parentElement, $view, $variables);
                 break;
             case 'hidden':
                 $this->serializeHiddenWidget($parentElement, $view, $variables);
                 break;
             case 'collection':
                 $this->serializeCollectionWidget($parentElement, $view, $variables);
                 break;
             case 'checkbox':
                 $this->serializeCheckboxWidget($parentElement, $view, $variables);
                 break;
             case 'radio':
                 $this->serializeRadioWidget($parentElement, $view, $variables);
                 break;
             case 'datetime':
                 $this->serializeDatetimeWidget($parentElement, $view, $variables);
                 break;
             case 'date':
                 $this->serializeDateWidget($parentElement, $view, $variables);
                 break;
             default:
                 switch ($blockName) {
                     case 'widget':
                         $this->serializeFormWidget($parentElement, $view, $variables);
                         break;
                     case 'row':
                         $this->serializeFormRow($parentElement, $view, $variables);
                         break;
                     default:
                         throw new \RuntimeException(__METHOD__ . ' Oups ' . $view->vars['name'] . ' // ' . $blockName);
                 }
         }
     }
     $view->setRendered();
 }
Exemple #8
0
    /**
     * Renders a template.
     *
     * 1. This function first looks for a block named "_<view id>_<section>",
     * 2. if such a block is not found the function will look for a block named
     *    "<type name>_<section>",
     * 3. the type name is recursively replaced by the parent type name until a
     *    corresponding block is found
     *
     * @param FormView  $view       The form view
     * @param string    $section    The section to render (i.e. 'row', 'widget', 'label', ...)
     * @param array     $variables  Additional variables
     *
     * @return string The html markup
     *
     * @throws FormException if no template block exists to render the given section of the view
     */
    protected function renderSection(FormView $view, $section, array $variables = array())
    {
        $mainTemplate = in_array($section, array('row', 'widget'));
        if ($mainTemplate && $view->isRendered()) {

                return '';
        }

        $template = null;
        $types = $view->get('types');
        $types[] = '_'.$view->get('proto_id', $view->get('id'));

        for ($i = count($types) - 1; $i >= 0; $i--) {
            $types[$i] .= '_'.$section;
            $template = $this->lookupTemplate($types[$i]);

            if ($template) {
                $html = $this->render($view, $template, $variables);

                if ($mainTemplate) {
                    $view->setRendered();
                }

                return $html;
            }
        }

        throw new FormException(sprintf('Unable to render form as none of the following blocks exist: "%s".', implode('", "', $types)));
    }
Exemple #9
0
    /**
     * Renders a template.
     *
     * 1. This function first looks for a block named "_<view id>_<section>",
     * 2. if such a block is not found the function will look for a block named
     *    "<type name>_<section>",
     * 3. the type name is recursively replaced by the parent type name until a
     *    corresponding block is found
     *
     * @param FormView  $view       The form view
     * @param string    $section    The section to render (i.e. 'row', 'widget', 'label', ...)
     * @param array     $variables  Additional variables
     *
     * @return string The html markup
     *
     * @throws FormException if no template block exists to render the given section of the view
     */
    protected function render(FormView $view, $section, array $variables = array())
    {
        $mainTemplate = in_array($section, array('widget', 'row'));
        if ($mainTemplate && $view->isRendered()) {

                return '';
        }

        if (null === $this->template) {
            $this->template = reset($this->resources);
            if (!$this->template instanceof \Twig_Template) {
                $this->template = $this->environment->loadTemplate($this->template);
            }
        }

        $blocks = $this->getBlocks($view);
        $types = $view->get('types');
        $types[] = '_'.$view->get('proto_id', $view->get('id'));

        for ($i = count($types) - 1; $i >= 0; $i--) {
            $types[$i] .= '_'.$section;

            if (isset($blocks[$types[$i]])) {

                $this->varStack[$view] = array_replace(
                    $view->all(),
                    isset($this->varStack[$view]) ? $this->varStack[$view] : array(),
                    $variables
                );

                $html = $this->template->renderBlock($types[$i], $this->varStack[$view], $blocks);

                if ($mainTemplate) {
                    $view->setRendered();
                }

                unset($this->varStack[$view]);

                return $html;
            }
        }

        throw new FormException(sprintf('Unable to render form as none of the following blocks exist: "%s".', implode('", "', $types)));
    }
 protected function render(FormView $view, $section, array $variables = array())
 {
     $mainTemplate = in_array($section, array('widget', 'row'));
     if ($mainTemplate && $view->isRendered()) {
         return '';
     }
     $id = '_' . $view->get('proto_id', $view->get('id'));
     $template = $id . $section;
     $renderer = $this->getRenderer();
     if (isset($this->varStack[$template])) {
         $typeIndex = $this->varStack[$template]['typeIndex'] - 1;
         $types = $this->varStack[$template]['types'];
         $this->varStack[$template]['variables'] = array_replace_recursive($this->varStack[$template]['variables'], $variables);
     } else {
         $types = $view->get('types');
         $types[] = $id;
         $typeIndex = count($types) - 1;
         $this->varStack[$template] = array('variables' => array_replace_recursive($view->all(), $variables), 'types' => $types);
     }
     do {
         $types[$typeIndex] .= '_' . $section;
         if (isset($renderer[$types[$typeIndex]])) {
             $this->varStack[$template]['typeIndex'] = $typeIndex;
             $html = $renderer[$types[$typeIndex]]->render($view, $this->varStack[$template]['variables'], $this);
             if ($mainTemplate) {
                 $view->setRendered();
             }
             unset($this->varStack[$template]);
             return $html;
         }
     } while (--$typeIndex >= 0);
     throw new FormException(sprintf('Unable to render the form as none of the following renderer exist: "%s".', implode('", "', array_reverse($types))));
 }
Exemple #11
0
 /**
  * Renders a template.
  *
  * 1. This function first looks for a block named "_<view id>_<section>",
  * 2. if such a block is not found the function will look for a block named
  *    "<type name>_<section>",
  * 3. the type name is recursively replaced by the parent type name until a
  *    corresponding block is found
  *
  * @param FormView  $view       The form view
  * @param string    $section    The section to render (i.e. 'row', 'widget', 'label', ...)
  * @param array     $variables  Additional variables
  *
  * @return string The html markup
  *
  * @throws FormException if no template block exists to render the given section of the view
  */
 protected function renderSection(FormView $view, $section, array $variables = array())
 {
     $mainTemplate = in_array($section, array('row', 'widget'));
     if ($mainTemplate && $view->isRendered()) {
         return '';
     }
     $template = null;
     $blocks = $view->get('types');
     array_unshift($blocks, '_' . $view->get('id'));
     foreach ($blocks as &$block) {
         $block = $block . '_' . $section;
         $template = $this->lookupTemplate($block);
         if ($template) {
             break;
         }
     }
     if (!$template) {
         throw new FormException(sprintf('Unable to render form as none of the following blocks exist: "%s".', implode('", "', $blocks)));
     }
     $html = $this->render($view, $template, $variables);
     if ($mainTemplate) {
         $view->setRendered();
     }
     return $html;
 }