Functional test and sfWidgetFormChoice with multiple true - symfony1

I want to test a user editing a form, and in that form there is a <select multiple="multiple">. How do I select or unselect <option>values from that form widget in the functional test?
Form setup:
'regions_list' => new sfWidgetFormDoctrineChoice(array(
'multiple' => true,
'model' => 'Region'
)),
Functional Test:
$browser->
getRoute('profile')->
//setField('profile[regions_list]', '[9][8]')-> // tried syntaxmany combinations
click('Save Profile', array(
'profile' => array(
// 'regions_list' => ???,
// I've tried many combinations even with setField and none made sense and where testable so far
)
))->
with('form')->begin()->
hasErrors(0)->
hasGlobalError(0)->
end()
;

I've never put the with('form') around the click() and this is working on my tests:
$browser->
getRoute('profile')->
click('Save Profile', array(
'profile' => array('regions_list' => array(8,9)
// with: <option value="8">something</option><option value="9">else</option>
// ... and other fields
)
))->
end()->
with('form')->begin()->
debug() -> // added this line so you can see what is happening
hasErrors(0)->
hasGlobalError(0)->
end()
;

Well, after digging in the click() process, I can't get the result I expect.
The solutions follows the problem:
in a <select multiple> tag, I expect that if I don't post any values, it's going to repost it as is, and if I do specify values, it will post only those and not try to control on/off by values.
The way it's reacting now is that the initial values and the chosen values are merged together and the initial values keys matching the chosen values keys are replaced which doesn't make sense to me because those keys or their order are irrelevant. I only care about the option values chosen.
The answer to my question is: You can't do what you expect with the current implementation.
The solution:
Override (or submit a patch if you have time) the doClickElement function in sfBrowserBase class which could look like this: ( look for the 3 comments // fix for select multiple and the last 2 methods to add )
public function doClickElement(DOMElement $item, $arguments = array(), $options = array())
{
$method = strtolower(isset($options['method']) ? $options['method'] : 'get');
if ('a' == $item->nodeName)
{
if (in_array($method, array('post', 'put', 'delete')))
{
if (isset($options['_with_csrf']) && $options['_with_csrf'])
{
$arguments['_with_csrf'] = true;
}
return array($item->getAttribute('href'), $method, $arguments);
}
else
{
return array($item->getAttribute('href'), 'get', $arguments);
}
}
else if ('button' == $item->nodeName || ('input' == $item->nodeName && in_array($item->getAttribute('type'), array('submit', 'button', 'image'))))
{
// add the item's value to the arguments
$this->parseArgumentAsArray($item->getAttribute('name'), $item->getAttribute('value'), $arguments);
// use the ancestor form element
do
{
if (null === $item = $item->parentNode)
{
throw new Exception('The clicked form element does not have a form ancestor.');
}
}
while ('form' != $item->nodeName);
}
// form attributes
$url = $item->getAttribute('action');
if (!$url || '#' == $url)
{
$url = $this->stack[$this->stackPosition]['uri'];
}
$method = strtolower(isset($options['method']) ? $options['method'] : ($item->getAttribute('method') ? $item->getAttribute('method') : 'get'));
// merge form default values and arguments
$defaults = array();
$arguments = sfToolkit::arrayDeepMerge($this->fields, $arguments);
// fix for select multiple
$select_multiple_to_check = array();
$xpath = $this->getResponseDomXpath();
foreach ($xpath->query('descendant::input | descendant::textarea | descendant::select', $item) as $element)
{
if ($element->hasAttribute('disabled'))
{
continue;
}
$elementName = $element->getAttribute('name');
$nodeName = $element->nodeName;
$value = null;
if ($nodeName == 'input' && ($element->getAttribute('type') == 'checkbox' || $element->getAttribute('type') == 'radio'))
{
// fix for select multiple
if (substr($elementName, -2) == '[]')
{
$select_multiple_to_check[$elementName] = true;
}
if ($element->getAttribute('checked'))
{
$value = $element->hasAttribute('value') ? $element->getAttribute('value') : '1';
}
}
else if ($nodeName == 'input' && $element->getAttribute('type') == 'file')
{
$filename = array_key_exists($elementName, $arguments) ? $arguments[$elementName] : sfToolkit::getArrayValueForPath($arguments, $elementName, '');
if (is_readable($filename))
{
$fileError = UPLOAD_ERR_OK;
$fileSize = filesize($filename);
}
else
{
$fileError = UPLOAD_ERR_NO_FILE;
$fileSize = 0;
}
unset($arguments[$elementName]);
$this->parseArgumentAsArray($elementName, array('name' => basename($filename), 'type' => '', 'tmp_name' => $filename, 'error' => $fileError, 'size' => $fileSize), $this->files);
}
else if ('input' == $nodeName && !in_array($element->getAttribute('type'), array('submit', 'button', 'image')))
{
$value = $element->getAttribute('value');
}
else if ($nodeName == 'textarea')
{
$value = '';
foreach ($element->childNodes as $el)
{
$value .= $this->getResponseDom()->saveXML($el);
}
}
else if ($nodeName == 'select')
{
if ($multiple = $element->hasAttribute('multiple'))
{
// fix for select multiple
$select_multiple_to_check[$elementName] = true;
$elementName = str_replace('[]', '', $elementName);
$value = array();
}
else
{
$value = null;
}
$found = false;
foreach ($xpath->query('descendant::option', $element) as $option)
{
if ($option->getAttribute('selected'))
{
$found = true;
if ($multiple)
{
$value[] = $option->getAttribute('value');
}
else
{
$value = $option->getAttribute('value');
}
}
}
$option = $xpath->query('descendant::option', $element)->item(0);
if (!$found && !$multiple && $option instanceof DOMElement)
{
$value = $option->getAttribute('value');
}
}
if (null !== $value)
{
$this->parseArgumentAsArray($elementName, $value, $defaults);
}
}
// fix for select multiple
foreach($select_multiple_to_check as $elementName => $uselessbool)
{
$path = array_filter(preg_split('/(\[ | \[\] | \])/x', $elementName), create_function('$s', 'return $s !== "";'));
if ($this->findInArrayByArrayPath($arguments, $path) !== false)
{
$this->unsetInArrayByArrayPath($defaults, $path);
}
}
$arguments = sfToolkit::arrayDeepMerge($defaults, $arguments);
if (in_array($method, array('post', 'put', 'delete')))
{
return array($url, $method, $arguments);
}
else
{
$queryString = http_build_query($arguments, null, '&');
$sep = false === strpos($url, '?') ? '?' : '&';
return array($url.($queryString ? $sep.$queryString : ''), 'get', array());
}
}
// fix for select multiple
// taken from http://stackoverflow.com/questions/3145068/set-multi-dimensional-array-by-key-path-from-array-values/3145199#3145199
public function findInArrayByArrayPath(&$array, &$path, $_i=0) {
// sanity check
if ( !(is_array($array) && is_array($path)) ) return false;
$c = count($path); if ($_i >= $c) return false;
if ($_i==0) {$path = array_values($path);} // to make sure we don't get skipped numeric keys which does happens in the preg_split above
$k = $path[$_i];
if (array_key_exists($k, $array))
return ($_i == $c-1) ? $array[$k] : $this->findInArrayByArrayPath($array[$k], $path, $_i+1);
else
return false;
}
// fix for select multiple
public function unsetInArrayByArrayPath(&$array, &$path, $_i=0) {
// sanity check
if ( !(is_array($array) && is_array($path)) ) return false;
$c = count($path); if ($_i >= $c) return false;
if ($_i==0) {$path = array_values($path);} // to make sure we don't get skipped numeric keys which does happens in the preg_split above
$k = $path[$_i];
if (array_key_exists($k, $array))
if ($_i == $c-1) {
unset($array[$k]);
return true;
} else {
return $this->unsetInArrayByArrayPath($array[$k], $path, $_i+1);
}
else
return false;
}
And Now:
'profile' => array('regions_list' => array(8,9)) works for me.

Related

GravityForms Dynamic Confirmation Redirects

I have set up a gravity form with a single line text field. I am using it to check for zip codes and cities. If someone types in the correct zip code it will redirect to a specific page. Also if someone types in a zip code or city and there is no matching value it will also redirect to a certain page. I have tried this code. But I can not seem to get it to work correctly. It works if I have one number but if I add multiple numbers separated by a comma it does not work. Please help if possible.
<?php
function de_gforms_confirmation_dynamic_redirect( $confirmation, $form, $entry, $ajax ) {
if ( $form['id'] == '38' ) {
if ( $entry['1'] == '89103,80205,91030' ) {
$confirmation = array( 'redirect' => 'https://google.com' );
} else if ( $entry['1'] == '90210,89554,90454' ) {
$confirmation = array( 'redirect' => 'https://yahoo.com' );
} else if ( $entry['1'] == '56678,89004,78896' ) {
$confirmation = array( 'redirect' => 'https://test.com' );
}
}
return $confirmation;
}
add_filter( 'gform_confirmation', 'de_gforms_confirmation_dynamic_redirect', 10, 4 );
?>
You need to use the or operator "||" instead of the array of zipcodes
<?php
function de_gforms_confirmation_dynamic_redirect( $confirmation, $form, $entry, $ajax ) {
if ( $form['id'] == '38' ) {
if ( $entry['1'] == '89103' || $entry['1'] == '80205' || $entry['1'] == '91030' ) {
$confirmation = array( 'redirect' => 'https://google.com' );
} else if ( $entry['1'] == '90210' || $entry['1'] == '89554' || $entry['1'] == '90454' ) {
$confirmation = array( 'redirect' => 'https://yahoo.com' );
} else if ( $entry['1'] == '56678' || $entry['1'] == '89004' || $entry['1'] == '78896' ) {
$confirmation = array( 'redirect' => 'https://test.com' );
}
}
return $confirmation;
}
There's a lot of ways you could do this. I would probably try to turn your zip codes/redirect into an associative array (https://wtools.io/convert-csv-to-php-array) that you could loop through like this:
function de_gforms_confirmation_dynamic_redirect( $confirmation, $form, $entry, $ajax ) {
$zip_group = array("1234","2345","3456");
$count_group = count($zip_group);
for($i=0;$i<$count_group;$i++){
$redirect[$i]='https://google.com';
}
$zip_condition = array_combine( $zip_group , $redirect );
if( $form['id'] == '38' ) {
foreach($zip_condition as $zip => $condition) {
if ( $entry['1'] == $zip ) {
$confirmation = array( 'redirect' => $condition );
}
}
}
return $confirmation;
}

Route not loading

I'm having issues with a route in Zend Framework 2. For instance, in module.config.php I have it set up as follows:
'user' => array(
'type' => 'Segment',
'options' => array(
'route' => 'user[/:action][/:store_id]',
'defaults' => array(
'controller' => 'Application\Controller\User',
'action' => 'index',
),
),
),
Now, I have a function in JavaScript that calls the route part [/:store_id] when a image is clicked on.
function viewStore(id) {
if (typeof id !== undefined) {
$.getJSON('/user/store/' + id, function(data) {
document.getElementById('view-store-modal').style.display = 'block';
$.each(data, function(i) {
$('#main-store-name').html(data[i].store_name);
$("#main-store-image").prop('src', data[i].store_image);
$("#main-store-image").addClass("w3-padding").addClass("w3-round");
$('#main-store-image').attr('style', 'width: 400px; height: 200px; display: block');
$('#main-store-description').html("Store Description: " + data[i].store_description);
$('#main-store-category').html("Store Category: " + data[i].store_category);
if (data[i].number_of_items === null) {
$('#main-store-items').html("No items exist for this store yet, go add some!");
} else {
$('#main-store-items').html("Number Of Items: " + data[i].number_of_items);
}
});
});
}
}
Here is the controller code:
public function storeAction()
{
$layout = $this->layout();
$layout->setTerminal(true);
$view_model = new ViewModel();
$view_model->setTerminal(true);
$id = $this->params()->fromRoute('store_id');
if ($id !== null) {
try {
echo json_encode($this->getUserService()->getStoreFromId((int)$id));
} catch (\Exception $e) {
echo json_encode(array('failure' => $e->getMessage()));
}
}
return $view_model;
}
And this is the method that retrieves the rows:
public function getStoreFromId(int $store_id) : array
{
if ($store_id != 0 || $store_id !== null) {
$query = $this->sql->getAdapter()->getDriver()->getConnection()->execute("SELECT COUNT(i.store_id) AS number_of_items,
stores.store_name, stores.store_description, stores.store_category, stores.store_image FROM items AS i
INNER JOIN stores ON stores.store_id = i.store_id WHERE stores.store_id = " . $store_id);
if ($query->count() > 0) {
$row = [];
foreach ($query as $value) {
$row[] = $value;
}
return $row;
} else {
$select = $this->select->columns(array('store_id', 'store_name', 'store_description', 'store_category', 'store_image'))
->from('stores')
->where(array('store_id' => $store_id));
$query = $this->sql->getAdapter()->query(
$this->sql->buildSqlString($select),
Adapter::QUERY_MODE_EXECUTE
);
if ($query->count() > 0) {
$row = [];
foreach ($query as $value) {
$row[] = $value;
}
return $row;
} else {
throw new \Exception("Could not locate store.");
}
}
} else {
throw new \Exception("Invalid store id given.");
}
}
When I call it, it is like this:
<img src="<?php echo $this->basePath() . $store['store_image']; ?>" alt="Your Store" style="width: 100%;" onclick="viewStore(<?php echo $store['store_id']; ?>);">
Now, that does show all the store ids but when I click on any id but the first image, I am getting this response (shown in screenshots)
https://imgur.com/a/4XFbKFI
I'm not sure why any of the ids that are not 23 do not load. Right now, all are listed from the stores table but only the id 23 actually works.
Any help would be appreciated.
Thanks!
The issue was with the query. I changed it to this:
SELECT stores.store_id,
(SELECT count(b.store_id) FROM items b WHERE b.store_id = " . $store_id . " and stores.store_id = b.store_id) AS number_of_items, stores.store_name, stores.store_description, stores.store_category, stores.store_image FROM stores
WHERE stores.store_id = " . $store_id
and it worked just fine.

Hook::exec is not working for a particular module

I am facing an issue regarding the hook::exec in my prestashop application, where module and hook method is installed properly. But when I tried to execute this module, it return false. Kindly suggest me. Module and hook method is showing in "Modules and Services / Positions" as well as ps_hook table in database.
Module base file is defined as :
public function __construct()
{
$this->name = 'callback';
$this->tab = 'front_office_features';
$this->version = '1.0';
$this->author = 'Amit Jha';
$this->need_instance = 0;
$this->ps_versions_compliancy = array('min' => '1.6', 'max' => _PS_VERSION_);
$this->bootstrap = true;
parent::__construct();
$this->displayName = $this->l( 'Call Back' );
$this->description = $this->l( '....' );
$this->confirmUninstall = $this->l( 'Are you sure you want to uninstall? .... ' );
}
And Install method is as below:
if ( parent::install() && $this->registerHook( 'displayCallBack' ) && $this->registerHook( 'displayHeader' ) && $this->registerHook( 'displayCallBackCart' ) && $this->registerHook( 'displayCallBackLinkOnCartPopup' ) && $this->registerHook( 'displayCallBackLinkOnCartPopupWishlist' ) ) {
if ( !$this->alterTable( 'add' ) ) {
return false;
}
return true;
}
Hook Method:
public function hookDisplayCallBack( $params )
{
$results = CallBackServiceCore::searchDetail();
if ( count( $results ) <= 0 ) {
return;
}
foreach ( $results as $item ) {
$this->context->smarty->assign( array(
'description_text' => $item["description_text"],
'recall_promise' => $item["recall_promise"]
) );
}
$arrDate = $this->getCallingTime();
$this->context->smarty->assign( array(
'arrTimeList' => $arrDate,
'product_id' => $params["product"]->id,
'product_name' => $params["product"]->name,
'category' => $params["product"]->category
)
);
return $this->display( __file__, 'display.tpl' );
}
Please suggest where I made mistake.

How to hook tags to displayTopColumn in prestashop 1.6

Can somebody tell me how to display tags in TopColumn in prestashop 1.6?
I know that I must edit blogtags.php but I don't know how to do it - my PHP is too weak.
Of course I tried - now can I can hook tag in admin panel but not on website. What have I done?
.
.
.
function install()
{
$success = (parent::install() && $this->registerHook('header') && **$this->registerHook('displayTopColumn')** && Configuration::updateValue('BLOCKTAGS_NBR', 10));
if ($success)
.
.
.
public function hookdisplayTop($params)
{
return $this->hookdisplayTopColumn($params);
}
.
.
.
Full blogtags.php
if (!defined('_PS_VERSION_'))
exit;
define('BLOCKTAGS_MAX_LEVEL', 3);
class BlockTags extends Module
{
function __construct()
{
$this->name = 'blocktags';
$this->tab = 'front_office_features';
$this->version = '1.2.1';
$this->author = 'PrestaShop';
$this->need_instance = 0;
$this->bootstrap = true;
parent::__construct();
$this->displayName = $this->l('Tags block');
$this->description = $this->l('Adds a block containing your product tags.');
$this->ps_versions_compliancy = array('min' => '1.6', 'max' => _PS_VERSION_);
}
function install()
{
$success = (parent::install() && $this->registerHook('header') && $this->registerHook('displayTopColumn') && Configuration::updateValue('BLOCKTAGS_NBR', 10));
if ($success)
{
// Hook the module either on the left or right column
$theme = new Theme(Context::getContext()->shop->id_theme);
if ((!$theme->default_left_column || !$this->registerHook('leftColumn'))
&& (!$theme->default_right_column || !$this->registerHook('rightColumn'))
&& $this->registerHook('displayTopColumn'))
{
// If there are no colums implemented by the template, throw an error and uninstall the module
$this->_errors[] = $this->l('This module need to be hooked in a column and your theme does not implement one');
parent::uninstall();
return false;
}
}
return $success;
}
public function getContent()
{
$output = '';
if (Tools::isSubmit('submitBlockTags'))
{
if (!($tagsNbr = Tools::getValue('BLOCKTAGS_NBR')) || empty($tagsNbr))
$output .= $this->displayError($this->l('Please complete the "Displayed tags" field.'));
elseif ((int)($tagsNbr) == 0)
$output .= $this->displayError($this->l('Invalid number.'));
else
{
Configuration::updateValue('BLOCKTAGS_NBR', (int)$tagsNbr);
$output .= $this->displayConfirmation($this->l('Settings updated'));
}
}
return $output.$this->renderForm();
}
/**
* Returns module content for left column
*
* #param array $params Parameters
* #return string Content
*
*/
function hookLeftColumn($params)
{
$tags = Tag::getMainTags((int)($params['cookie']->id_lang), (int)(Configuration::get('BLOCKTAGS_NBR')));
$max = -1;
$min = -1;
foreach ($tags as $tag)
{
if ($tag['times'] > $max)
$max = $tag['times'];
if ($tag['times'] < $min || $min == -1)
$min = $tag['times'];
}
if ($min == $max)
$coef = $max;
else
{
$coef = (BLOCKTAGS_MAX_LEVEL - 1) / ($max - $min);
}
if (!sizeof($tags))
return false;
foreach ($tags AS &$tag)
$tag['class'] = 'tag_level'.(int)(($tag['times'] - $min) * $coef + 1);
$this->smarty->assign('tags', $tags);
return $this->display(__FILE__, 'blocktags.tpl');
}
function hookRightColumn($params)
{
return $this->hookLeftColumn($params);
}
function hookHeader($params)
{
$this->context->controller->addCSS(($this->_path).'blocktags.css', 'all');
}
public function hookdisplayTop($params)
{
return $this->hookdisplayTopColumn($params);
}
public function renderForm()
{
$fields_form = array(
'form' => array(
'legend' => array(
'title' => $this->l('Settings'),
'icon' => 'icon-cogs'
),
'input' => array(
array(
'type' => 'text',
'label' => $this->l('Displayed tags'),
'name' => 'BLOCKTAGS_NBR',
'class' => 'fixed-width-xs',
'desc' => $this->l('Set the number of tags you would like to see displayed in this block.')
),
),
'submit' => array(
'title' => $this->l('Save'),
)
),
);
$helper = new HelperForm();
$helper->show_toolbar = false;
$helper->table = $this->table;
$lang = new Language((int)Configuration::get('PS_LANG_DEFAULT'));
$helper->default_form_language = $lang->id;
$helper->allow_employee_form_lang = Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG') ? Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG') : 0;
$helper->identifier = $this->identifier;
$helper->submit_action = 'submitBlockTags';
$helper->currentIndex = $this->context->link->getAdminLink('AdminModules', false).'&configure='.$this->name.'&tab_module='.$this->tab.'&module_name='.$this->name;
$helper->token = Tools::getAdminTokenLite('AdminModules');
$helper->tpl_vars = array(
'fields_value' => $this->getConfigFieldsValues(),
'languages' => $this->context->controller->getLanguages(),
'id_language' => $this->context->language->id
);
return $helper->generateForm(array($fields_form));
}
public function getConfigFieldsValues()
{
return array(
'BLOCKTAGS_NBR' => Tools::getValue('BLOCKTAGS_NBR', Configuration::get('BLOCKTAGS_NBR')),
);
}
}
Change this:
public function hookdisplayTop($params)
{
return $this->hookdisplayTopColumn($params);
}
To that:
public function hookdisplayTopColumn($params)
{
return $this->hookLeftColumn($params);
}

description isnt displaying for zf2 form element

I am trying to add a description to my form element. I am expecting to get my description in p tags.
<?php
namespace CsnCms\Form;
use Zend\Form\Form;
class ArticleForm extends Form
{
public function __construct($name = null)
{
parent::__construct('article');
$this->setAttribute('method', 'post');
$this->add(array(
'name' => 'currency',
'attributes' => array(
'type' => 'text',
'placeholder' =>'Currency',
),
'options' => array(
'label' => ' ',
'description' => 'Currency code: ie. USD',
),
));
}
}
unfortunately I am only getting this as an output
<label><span> </span><input name="currency" type="text" placeholder="Currency" value=""></label>
any advice?
Maybe this will work
$form = $this->form;
$element = $form->get("currency");
echo $this->formInput($element);
echo $element->getOption("description"); // <-------
?>
zf2 form elements don't have native description option u need to add it manually :
$this->add(array(
'name' => 'catMachineName',
'type' => 'Zend\Form\Element\Text',
'options' => array(
'label' => 'Category Machine Name',
'description' => 'Machine name can only contain English Alphabets and Numbers and _ and no space and no number at the beginning'
),
));
and render it in view like with something like this:
echo $form->get('catMachineName')->getOption('description);
Thanks I wrote my own view helper. I also added a class="error" in the error tags.
Thanks for the help guys.
<?php
namespace User\View\Helper;
use Zend\View\Helper\AbstractHelper;
use Zend\Form\View\Helper\FormRow;
use Zend\Form\ElementInterface;
class FormRowWithDescription extends FormRow
{
/**
* Utility form helper that renders a label (if it exists), an element and errors
*
* #param ElementInterface $element
* #throws \Zend\Form\Exception\DomainException
* #return string
*/
public function render(ElementInterface $element)
{ $escapeHtmlHelper = $this->getEscapeHtmlHelper();
$labelHelper = $this->getLabelHelper();
$elementHelper = $this->getElementHelper();
$elementErrorsHelper = $this->getElementErrorsHelper();
$label = $element->getLabel();
$inputErrorClass = $this->getInputErrorClass();
if (isset($label) && '' !== $label) {
// Translate the label
if (null !== ($translator = $this->getTranslator())) {
$label = $translator->translate(
$label, $this->getTranslatorTextDomain()
);
}
}
// Does this element have errors ?
if (count($element->getMessages()) > 0 && !empty($inputErrorClass)) {
$classAttributes = ($element->hasAttribute('class') ? $element->getAttribute('class') . ' ' : '');
$classAttributes = $classAttributes . $inputErrorClass;
$element->setAttribute('class', $classAttributes);
}
if ($this->partial) {
$vars = array(
'element' => $element,
'label' => $label,
'labelAttributes' => $this->labelAttributes,
'labelPosition' => $this->labelPosition,
'renderErrors' => $this->renderErrors,
);
return $this->view->render($this->partial, $vars);
}
if ($this->renderErrors) {
$elementErrorsHelper
->setMessageOpenFormat('<ul%s><li class="error">')
->setMessageSeparatorString('</li><li class="error">');
$elementErrors = $elementErrorsHelper->render($element);
}
$elementString = $elementHelper->render($element);
$description = $element->getOption('description');
$elementString.="<p class='description'>".$description."</p>";
if (isset($label) && '' !== $label) {
$label = $escapeHtmlHelper($label);
$labelAttributes = $element->getLabelAttributes();
if (empty($labelAttributes)) {
$labelAttributes = $this->labelAttributes;
}
// Multicheckbox elements have to be handled differently as the HTML standard does not allow nested
// labels. The semantic way is to group them inside a fieldset
$type = $element->getAttribute('type');
if ($type === 'multi_checkbox' || $type === 'radio') {
$markup = sprintf(
'<fieldset><legend>%s</legend>%s</fieldset>',
$label,
$elementString);
} else {
if ($element->hasAttribute('id')) {
$labelOpen = '';
$labelClose = '';
$label = $labelHelper($element);
} else {
$labelOpen = $labelHelper->openTag($labelAttributes);
$labelClose = $labelHelper->closeTag();
}
if ($label !== '' && !$element->hasAttribute('id')) {
$label = '<span>' . $label . '</span>';
}
// Button element is a special case, because label is always rendered inside it
if ($element instanceof Button) {
$labelOpen = $labelClose = $label = '';
}
switch ($this->labelPosition) {
case self::LABEL_PREPEND:
$markup = $labelOpen . $label . $elementString . $labelClose;
break;
case self::LABEL_APPEND:
default:
$markup = $labelOpen . $elementString . $label . $labelClose;
break;
}
}
if ($this->renderErrors) {
$markup .= $elementErrors;
}
} else {
if ($this->renderErrors) {
$markup = $elementString . $elementErrors;
} else {
$markup = $elementString;
}
}
return $markup;
}
}

Resources