ZEND - decorators and position of elements? - zend-framework

I've got a problem with zend decorators and can't figure out how to place an element in form where i want to have him.
I got a form where decorators are putting my data into a table, but i want to have my submit out of the table. For now i have something like that:
for ($i = 0; $i < $numRows; $i++) {
$select = new Zend_Form_Element_Select('article' . $i);
$select->setAttrib('style', 'margin-top:10px;width:200px;');
$select->addMultiOption('1', $this->translate->_('Zatwierdzony do druku'));
$select->addMultiOption('0', $this->translate->_('Niezatwierdzony do druku'));
$select->setValue($rows[$i]['reviewed']);
$select->setDecorators(
array(
'ViewHelper',
array(
array('data' => 'HtmlTag'),
array('tag' => 'td', 'class' => 'padding5 tdcenter')
),
array(
'AnyMarkup',
array(
'markup' => $this->_getMarkupForRow($i, $rows),
'placement' => 'PREPEND',
)
),
array(
array('row' => 'HtmlTag'),
array('tag' => 'tr', 'openOnly'=>true)
),
),
array('submit'),
false
);
$this->addElement($select);
}
$submit = new Zend_Form_Element_Submit('updatetoprint');
$submit->setAttrib('id', 'updatetoprint');
$submit->setLabel('Zapisz');
$submit->setDecorators(
array(
'ViewHelper',
array(
array('data' => 'HtmlTag')
),
array(
array('row' => 'HtmlTag'),
array('tag' => 'div', 'closeOnly'=>true,'style' => 'float:left;')
)
//here i dont know how to get my submit on the bottom under the table...?
),
array('submit')
);
$this->addElement($submit);
On site that looks like this:
And i'd like to have my submit on the bottom under the table... Please help me :)

I don't see where you are assigning your form to the view or if your form is a Zend_Form or not so I'm going to make some assumptions.
I'm going to assume you are using Zend_Form to build your form and I'm going to assume you are assigning your form to the view in the traditional manner inside a controller action $this->view->form = $form;
So with that being said, in your view script you have access to each individual element simply by <?php echo $this->form->elemenetName ?> where elementName is the name you have given your element in your case your submit button has the name 'updatetoprint'.
With this in mind if you need to create a table or any other layout you could simply create generic elements in your form and just add them as needed to any view script. Might prevent you from performing all those gymnastics with decorators.
For example view.phtml might look like:
<form action="<?php echo $this->form->getAction() ?>" method="<?php echo $this->form->getMethod() ?>">
<table>
<tr>
<th>Dodal</th>
<th>Tutyl</th>
<th>Status</th>
</tr>
<!--you should probably put the next 5 lines into a partial and use partialLoop($data)-->
<tr>
<td><?php echo $this->form->dodal ?></td>
<td><?php echo $this->form->tutyl ?></td>
<td><?php echo $this->form->status ?></td>
</tr>
</table>
<?php echo $this->form->updatetoprint ?>
</form>
Then just style with css.
To setup the form to use the viewscript just use:
$form->setDecorators(array(
'PrepareElements',
array('ViewScript', array('viewScript' => 'form.phtml')),
));
where form.phtml is your viewscript name
[Edit]
After further consideration I realized that diplaying form elements in this manner has one serious drawback. The form is never initialized...the form tags are never sent. This edit is to correct that issue.
Sorry it took so long

I'd suggest adding all your elements apart from the submit button to a display group. You then give the display group a HtmlTag decorator (with the tag set to table), which will wrap all your elements with a table, making your HTML valid and giving you the layout you want.

I'm seeing lots of <tr> and <td> tags, but no <table> tag. What I think you are looking for is markup roughly like this:
<table>
<tr><td>info</td><td>more info</td><td>select element</td></tr>
<tr><td>info</td><td>more info</td><td>select element</td></tr>
<tr><td>info</td><td>more info</td><td>select element</td></tr>
</table>
<div>
<input type="submit">
</div>
What seems to be missing from your code are any decorators that produce the <table> and </table> tags. So, on the first iteration of the loop, use the AnyMarkup decorator to prepend a <table> and your header row. On the last iteration, add a decorator that appends the </table> tag.
Then your submit button (which is added last) should sit right underneath.

Related

understanding grid layout in zend

I'm a bit confused with designing forms in zend.
I understood that I have the fields in my form class and the look should be done in the views.
In the index view which is nearly plain html I don't have problems, but in the add and edit views which show my form I have problems to change the look.
I have a viewscript like follows:
<?php
$title = 'AVB ändern';
$this->headTitle($title);
?>
<h1><?= $this->escapeHtml($title) ?></h1>
<?php
$id= $form->get('id');
$id->setAttribute('class', 'form-control');
$id->setAttribute('placeholder', 'id');
$avbname= $form->get('avbname');
$avbname->setAttribute('class', 'form-control');
$avbname->setAttribute('placeholder', 'avbname');
$vbedingungen= $form->get('vbedingungen');
$vbedingungen->setAttribute('class', 'form-control');
$vbedingungen->setAttribute('placeholder', 'vbedingungen');
$versichererid= $form->get('versichererid');
$versichererid->setAttribute('class', 'form-control');
$versichererid->setAttribute('placeholder', 'versichererid');
$aktiv= $form->get('aktiv');
$aktiv->setAttribute('class', 'form-control');
$aktiv->setAttribute('placeholder', 'aktiv');
$submit = $form->get('submit');
$submit->setAttribute('class', 'btn btn-primary');
$form->prepare();
echo $this->form()->openTag($form);
?>
<div class="form-group">
<?= $this->formElement($id) ?>
<?= $this->formElementErrors()->render($id, ['class' => 'help-block']) ?>
</div>
<div class="form-group">
<?= $this->formLabel($avbname) ?>
<?= $this->formElement($avbname) ?>
<?= $this->formElementErrors()->render($avbname, ['class' => 'help-block']) ?>
</div>
<div class="form-group">
<?= $this->formLabel($vbedingungen) ?>
<?= $this->formElement($vbedingungen) ?>
<?= $this->formElementErrors()->render($vbedingungen, ['class' => 'help-block']) ?>
</div>
<div class="form-group">
<?= $this->formLabel($versichererid) ?>
<?= $this->formElement($versichererid) ?>
<?= $this->formElementErrors()->render($versichererid, ['class' => 'help-block']) ?>
</div>
<div class="form-group">
<?= $this->formLabel($aktiv) ?>
<?= $this->formElement($aktiv) ?>
<?= $this->formElementErrors()->render($aktiv, s['class' => 'help-block']) ?>
</div>
<?php
echo $this->formSubmit($submit);
echo $this->formHidden($form->get('id'));
$form->setAttribute('action', $this->url('typavb', ['action' => 'edit']));
echo $this->form()->closeTag();
Of course it shows one field beneath the other.
How can I show two fields in a row (with the labels) ?
I really would appreciate an example or a tip to a good tutorial, which shows how to do it properly with this zend3 concept.
Is it even the right place to do it in the view or do I need a new layout.phtml for this case?
To print parts of Elements separately, there's several functions pre-defined in ZF. You can find all of them in \Zend\Form\ConfigProvider->getViewHelperConfig(), see here on Github.
In your case, your already using formLabel, formElement and formElementErrors.
These are handy for separte use if you have something like Currency, where you'd like a user to both fill in an amount and choose a currency but only use a single label, e.g.:
$this->formLabel($form->get('amount'));
$this->formElement($form->get('amount'));
$this->formElementErrors($form->get('amount'));
$this->formElement($form->get('currency'));
$this->formElementErrors($form->get('currency'));
An entire "form row" is made up out of:
A label (optional)
Element
ElementErrors (if present after server-side validation)
So, as in this example you need the entire "amount" bit, you could shorten the above to:
$this->formRow($form->get('amount')); // prints all elements for the row
$this->formElement($form->get('currency'));
$this->formElementErrors($form->get('currency'));
If you look closely through the linked ConfigProvider of 'zendframework/zend-form', you might've noticed there's also a form ViewHelper. This can be used to print an entire form in a single go, like so:
file: add-foo.phtml
<?= $this->form($form) ?>
And that's it. It prints the whole form. Of course it uses the ZF defined ViewHelpers, as such also with that layout and classes applied.
If you wish, can take that config and override it in your own projects.
For example, your question code shows you add <div class="form-group"></div> around each row. Presumably for Bootstrap 4. To do this magically so you need not do:
<div class="form-group">
<?= $this->formRow($form->get('foo')) ?>
</div>
We can adjust the formRow ViewHelper. Simply follow these steps:
Create a FormRow.php in your own project, e.g. module/Foo/src/View/Helper/FormRow.phtml
Make sure to extend it from ZF's FormRow and copy in the original (ZF) render function, like so:
use Zend\Form\View\Helper\FormRow as ZendFormRow;
class FormRow extends ZendFormRow
{
public function render(ElementInterface $element, $labelPosition = null)
{
// its content
}
}
We want to add a wrapper (form-group class div), so define it in the class, like so:
class FormRow extends ZendFormRow
{
protected $inputRow = '<div class="form-group">%s</div>';
// the other stuff
}
At the bottom of the render function, you'll find the following code (before the else):
if ($this->renderErrors) {
$markup .= $elementErrors;
}
Place after the above:
$markup = sprintf(
$this->inputRow,
$markup,
);
Register your new ViewHelper, using the same aliases as ZF so as to overwrite the values:
'view_helpers' => [
'aliases' => [
'formrow' => FormRow::class,
'form_row' => FormRow::class,
'formRow' => FormRow::class,
'FormRow' => FormRow::class,
],
'factories' => [
FormRow::class => InvokableFactory::class,
],
],
Done.
Now when you do $this->form($form) the FormElement ViewHelper from ZendFramework will receive your custom formRow ViewHelper when it its Factory does ->get('formRow'), as the config is overwritten to your own. As such, all rows will now automagically have the surrounding div.
Bit more than you asked for, but have fun ;) I'm gonna stop avoiding work now O:)

Get result from left join in fuelphp

I has a table name "Account". It has three columns named "Id", "Name", "primary_user_id".
I want to show id, name and name corresponding to user id. I mean I have t use left join.
I get collection using
$data['accounts'] = Model_Account::find('first', array(
'related' => array(
'accounts' => array(
'join_type' => 'inner',
'where' => array(
array('primary_user_id', 'id')
),
'order_by' => array('id' => 'desc'),
),
),
));
In model:-
protected static $_has_many =array('accounts');
In view:-
<?php foreach ($accounts as $account): // echo "<pre>"; print_r($users);?>
<tr>
<td><?php echo $account->id; ?></td>
<td><?php echo $account->name; ?></td>
<td></td>
</tr>
<?php endforeach; ?>
I am trying to get value of name corresponding to primary_user_id. Please help me how can I achieve it.
If you are using the ORM you should not be manually constructing your queries like that. You will want to set up a relation between your Account and User models. There is plenty of documentation about relations in the main fuelphp docs.

How to make a selectbox the label of a radio button in Zend Fw

Not my idea, but I need a set of radio buttons, where the last buttons value is a select box. Visual explanation:
o Opt 1
o Opt 2
o |___SelectBox|
What it would look like in HTML:
<input type="radio" name="radioSet">Opt1
</input>
<input type="radio" name="radioSet">Opt2
</input>
<input type="radio" name="radioSet"><!-- Opt 3 -->
<select>
<option value="a"> aaa</option>
<option value="b"> bbb</option>
</select>
</input>
What I've done in ZF so far:
$picker = new Zend_Form_Element_Select('selectBox', array(
'multiOptions' => array('a'=>'aaa', 'b' =>'bbb'),
'decorators' => array(
array('Label', array('escape'=>false))
)
));
$this->addElement(
'radio',
'radioSet',
array(
'multioptions' => array(
'x'=>'Opt1',
'y'=>'Opt2',
'z'=>$picker //'Dropdown picker'
),
'label' => 'My Title:',
'decorators' => array(
'ViewHelper',
'Errors',
array('Description', array('escape' => false)),
'Label',
array('HtmlTag', array('tag'=>'div')),
),
)
);
But this returns just the 3 radio buttons, as well as the labels "Opt1" and "Opt2", but nothing after the third radio button.
I WANT it to be like the HTML code shown above, but this ZF code does not return it. Anyone an idea how this can be accomplished?
Thanks!
unfortunately you probably going to have to write a decorator to replace the label tag with a select. Looking at the code for the Zend_Form_Element_Radio() it specifically adds the label tag to the radio.
Thanks for your advices. I'm quite new to Zend, so I checked up how to make a custom view helper decorator, I couldn't manage to get it to work like that, but it helped me in another problem though.
I came to the solution, that it's easier to just add the select box as an individual element afterwards, and style it to the desired position with css.
Thanks again.

Creating a submit button

I can create the regular submit button in the form api but what if I want to do something like this
$form['required_text'] = array(
'#markup' => '<button name="submit" value="submit" type="submit" class="primary-submit submit" id="edit-submit">Submit - markup
<img src="/img/arrow.png">
</button>',
);
This does not send the form. What do I need to do or does it need to be an input field?
You might wahnt to use an image_button type instead. Also at the moment you're not really using the form API properly, you can just add markup to the form like you're doing but it doesn't register the element in the form and thus won't run submit/validate handlers. Something like this would work:
$form['required_text'] = array(
'#type' => 'image_button',
'#value' => 'submit',
'#src' => '/img/arrow.png'
);
With that element you'll get a an <input type="image" /> with the correct image loaded in to it's source.
Hope that helps

Using ViewScript Decorator on Nested Subforms (Zend Form)

I want to use a view script to render my zend form as it seems to be the best way to
control the layout/design of the form while still using the Zend_Elements classes.
From the view script, I render the element with $this->element->getElement('elementName') .
I'm having problems with the names of the elements. This is actually a sub-form inside a sub-form inside a form.
When I used the FormElements decorators , the fully qualified name of the elements was form[subForm][subForm][element] , which was good.
Wehn I moved to the viewScript decorators, it changed to subForm[subForm][element].
I understood that I need to use the PrepareElements decorator to fix this, but this caused the name to change form[subForm][form][subForm][subForm][elements] (it doubled the first two names in the start).
Any ideas how I should handle this?
Thanks.
UPDATE: I tried to debug PrepareElements and I really don't understand what is doing.
It seems like it works ok in the first iteration, but then it adds again the form[subform] prefix when running on one of the middle subforms.
When I'm not using the PrepareElements decorator, I'm just missing the "form" prefix in the names (i.e., instead of form[subForm][element], I get only subForm[element]).
May be I can just fix this somehow?
I tried to change the belongsTo but that only replaced the "subForm" prefix .
It actually seems like what is missing is a belongsTo method on the subForm.
Again, this is all because of the ViewScript decorator. It works fine with the FormElements decorators.
UPDATE 2: Just to clarify, I wouldn't mind this name change, but it causes my fields to not populate when I call form->populate .
Edit: I think that I've narrowed the problem to this: when I get my values back in setDefaults, they are ordered like this:
array(
\"formElements1-name\" => value1... \"subFormName\" => array(
\"parentFormName\" => array(
\"subFormName\" => subForm-values-array
)
)
...
The main problem here is the "parentFormName" => "subFormNAme".. what does it repeat itself? I'm already in the main form. I'm guessing this is caused because I've set the setElementsBelongTo(formName[subFormName]) , but if I wouldn't do that, then I would get my subform values completely separate from the form,
i.e.
values array = array(
\"formName\" => array(
formValues
), \"subFormNAme\" => array(
subFormValues
)
, while I exepct it to be
array(
formName => array(
subFormNAme => values-array
)
)...
Is it even possible to make this work?
Are you just trying to output your form using <?php echo $this->form; ?> from your view script?
That works well for simple forms, but for my more complex forms I tend to render each element individually but don't need to use ViewScript decorator on each individual element to do this. Just try something like this from your view script:
<div class="form">
<fieldset>
<legend>Some Form Name</legend>
<form action="<?php echo $this->escape($this->form->getAction()) ?>"
method="<?php echo $this->escape($this->form->getMethod()) ?>"
enctype="multipart/form-data">
<?php echo $this->form->id; // render the id element here ?>
<div class="half">
<?php echo $this->form->name; // render the user name field here ?>
</div>
<div class="half">
<?php echo $this->form->description; // render the description element here ?>
</div>
<div class="clear"></div>
<div class="half">
<?php echo $this->form->address1; // render the address ?>
</div>
<div class="half">
<?php echo $this->form->address2; // render address2 ?>
</div>
<div class="clear"></div>
<div class="third">
<?php echo $this->form->zip; // render zip code ?>
</div>
<div class="third">
<?php echo $this->form->city; // render city ?>
</div>
<div class="third">
<?php echo $this->form->state; // render state ?>
</div>
<div class="clear"></div>
<div class="half">
<?php echo $this->form->country; // render country ?>
</div>
<div class="clear"></div>
<?php echo $this->form->submit; ?>
</form>
</fieldset>
</div>
That is how I do most of my forms because I want to have some elements take up half the width and others the full width.
Surprisingly, the reference guide doesn't tell you that you can do this. I seem to remember a page about it in the past but cannot find it now. When I got started with Zend Framework, I thought the only way I could get my form to output exactly how I wanted was to create complex decorators, but that is not the case.
Matthew Weier O'Phinney has a great blog post on rendering Zend_Form decorators individually which explains what I did above. I hope they add this to the first page of Zend Form because that was discouraging to me at first. The fact is, 90% of my forms render elements individually instead of just echo'ing the form itself.
Note: To stop ZF from enclosing my form elements in the dt and dd tags, I apply this decorator to all of my standard form elements. I have a base form class that I extend all of my forms from so I don't have to repeat this everywhere. This is the decorator for the element so I can use tags to enclose my elements.
public $elementDecorators = array(
'ViewHelper',
'Errors',
array('Description', array('tag' => 'p', 'class' => 'description')),
array('HtmlTag', array('tag' => 'div', 'class' => 'form-div')),
array('Label', array('class' => 'form-label', 'requiredSuffix' => '*'))
);
For my submit buttons I use
public $buttonDecorators = array(
'ViewHelper',
array('HtmlTag', array('tag' => 'div', 'class' => 'form-button'))
);
The current solution is to use the PrepareElements decorator on the subforms with one change - remove the recursive call in the PrepareElements code. Also, no "setElementsBelongTo" is required.
This seem to generate the correct names and ids.
The solution would be to use the belongsTo() form element property.
Example :
new Zend_Form_Element_Text('<elementName>', array('belongsTo' => '<subformName>'))
In this way, the render() method will use a form element name like
name="<subformName>[<elementName>]"
I had the same problem and i solved it with a decorator
1 : Create a generic subform with elements
2 : Using a specific decorator with PrepareElements
3 : Change form to an array with setIsArray(true)
Example :
Form
$i = 4;
for($i = 0; $i < $nbReclam ; $i++)
{
$rowForm = new Zend_Form_SubForm($i);
$name= new Zend_Form_Element_Textarea('name');
$rowForm->addElement($name);
$this->addSubForm($rowForm, $i);
}
$this->setDecorators(array(
'PrepareElements',
array('ViewScript', array('viewScript' => 'myDecorator.phtml')),
));
$this->setIsArray(true);
Decorator
<table>
<thead>
<tr>
<th>N°</th>
<th>Name</th>
</tr>
</thead>
<tbody>
<?php foreach ($this->element->getSubForms() as $subForm) : ?>
<tr>
<td> <?php echo $i++?> </td>
<?php foreach ($subForm->getElements() as $row) : ?>
<td><?php echo $row ?></td>
<?php endforeach ?>
</tr>
<?php endforeach ?>
</tbody>
</table>
Enjoy
Sorry for my english, i am french