I created a simple form in typical ZF2 application. The form class code is just a modified code provided by Zend's Album example.
<?php
namespace Admin\Form;
use Zend\Form\Form;
class CityForm extends Form
{
public function __construct($name = null)
{
parent::__construct('city');
$this->setAttribute('method', 'post');
$this->add(array(
'name' => 'id',
'attributes' => array(
'type' => 'hidden',
),
));
$this->add(array(
'name' => 'name',
'attributes' => array(
'type' => 'text'
),
'options' => array(
'label' => 'Name',
),
));
$this->add(array(
'name' => 'province',
'attributes' => array(
'type' => 'text'
),
'options' => array(
'label' => 'Province',
),
));
$this->add(array(
'name' => 'country',
'attributes' => array(
'type' => 'text'
),
'options' => array(
'label' => 'Country',
),
));
$this->add(array(
'name' => 'coordinate',
'attributes' => array(
'type' => 'text'
),
'options' => array(
'label' => 'Coordinate',
),
));
$this->add(array(
'name' => 'submit',
'attributes' => array(
'type' => 'submit',
'value' => 'Save',
'id' => 'submitButton',
),
));
}
}
And call it like this in CityController, a typical controller extends AbstractActionController:
public function addAction()
{
$form = new CityForm();
$viewData = array(
'form' => $form
);
return new ViewModel($viewData);
}
Finally in view I echo it like this:
<?php $title = 'Add New City'; ?>
<?php $this->headtitle($title); ?>
<h1><?php echo $this->escapehtml($title); ?></h1>
<?php $form = $this->form; ?>
<?php $form->setAttribute('action', $this->url('city', array('action' => 'add'))); ?>
<?php $form->prepare(); ?>
<?php
echo $this->form()->openTag($form);
echo $this->formHidden($form->get('id'));
echo $this->formRow($form->get('name'));
echo $this->formRow($form->get('province'));
echo $this->formRow($form->get('country'));
echo $this->formRow($form->get('coordinate'));
echo $this->formSubmit($form->get('submit'));
echo $this->form()->closeTag();
?>
What I expected to see is a vertical form like this:
But what i got is an ugly form like this:
What's wrong with my code? Please help.
EDIT:
When I inspect element, the form generated is strange. The <input> element is inside the <label> element.
<form id="city" name="city" method="post" action="/karciscus/public/admin/city/add">
<input type="hidden" value="" name="id">
<label>
<span>Name</span><input type="text" value="" name="name">
</label>
<label>
<span>Province</span><input type="text" value="" name="province">
</label>
<label>
<span>Country</span><input type="text" value="" name="country">
</label>
<label>
<span>
Coordinate</span><input type="text" value="" name="coordinate">
</label>
<input type="submit" value="Save" id="submitButton" name="submit">
</form>
I'm pretty sure it is the cause of my ugly rendered form. I think it is not supposedly like that. How to fix it?
That's something you have to do in your css.
Give your label a fixed width/length will align them correctly.
If you want to achieve your example above, add display:block for labels then they will each take a full line, like a block element.
Fixed. For other who has the same experience with me, just add element id in form class:
$this->add(array(
'name' => 'name',
'attributes' => array(
'type' => 'text',
'id' => 'name', // Must have id, will render strange otherwise!
),
'options' => array(
'label' => 'Name',
),
));
This fixes the issue for me.
Use the built in twitter bootstrap css which comes with Zf2. Use divs to render your form elements. I understand that everyone thinks about the form data that you set on your .html is pure php data and you cant align it.
<div class="row">
<?php $title = 'Add New City'; ?>
<div>
<div class="row">
<?php $this->headtitle($title); ?>
<h1><?php echo $this->escapehtml($title); ?></h1>
<?php $form = $this->form; ?>
<?php $form->setAttribute('action', $this->url('city', array('action' => 'add'))); ?>
<?php $form->prepare(); ?>
<?php
echo $this->form()->openTag($form);
echo $this->formHidden($form->get('id'));
echo $this->formRow($form->get('name'));
echo $this->formRow($form->get('province'));
echo $this->formRow($form->get('country'));
echo $this->formRow($form->get('coordinate'));
echo $this->formSubmit($form->get('submit'));
echo $this->form()->closeTag();
?>
</div>
Thats the sample....try doing what you like just like what i have shown above and you are good to go.
Related
I want to upload an image in zf2 with the use of HTTP adapter and then rename it while saving to database and display it accordingly in view page. please help me out regarding this
Here is my form:
<?php
namespace Employee\Form;
use Zend\Form\Form;
class EmployeeForm extends Form{
public function __construct($name=null){
parent::__construct($name);
$this->setAttribute('enctype','multipart/form-data');
//$this->setAttribute('method', 'post');
$this->add(array(
'name' => 'imageupload',
'attributes' => array(
'type' => 'file',
),
'options' => array(
'label' => 'Image Upload',
),
));
$this->add(array(
'name' => 'submit',
'attributes' => array(
'type' => 'submit',
'value' => 'Add',
'id' => 'submitbutton',
),
));
}
}
here is my view file:
<?php $form->prepare(); ?>
<?php echo $this->form()->openTag($form); ?>
<?php echo $this->formRow($form->get('imageupload')); ?>
<?php echo $this->formRow($form->get('submit')); ?>
<?php echo $this->form()->closeTag(); ?>
here is the code in controller action:
if($request->isPost()){
$files = $request->getFiles()->toArray();
$httpadapter = new \Zend\File\Transfer\Adapter\Http();
$httpadapter->setDestination('public/images/profile');
$httpadapter->receive($files['file']['name']);
Now I want to save only image name in database with newname(rename) and view image with certain validation of that image like size and type. thank you
I am learning Zend by following Getting Started with Zend Framework 2 tutorial but I am facing a prolem with the form layout, it's broken:
How do I fix this issue to make it likes the form in the tutorial:
AlbumForm code:
public function __construct($name = null)
{
// we want to ignore the name passed
parent::__construct('album');
$this->add(array(
'name' => 'id',
'type' => 'Hidden',
));
$this->add(array(
'name' => 'title',
'type' => 'Text',
'options' => array(
'label' => 'Title',
),
));
$this->add(array(
'name' => 'artist',
'type' => 'Text',
'options' => array(
'label' => 'Artist',
),
));
$this->add(array(
'name' => 'submit',
'type' => 'Submit',
'attributes' => array(
'value' => 'Go',
'id' => 'submitbutton',
),
));
}
and the view code:
<?php
// module/Album/view/album/album/add.phtml:
$title = 'Add new album';
$this->headTitle($title);
?>
<h1><?php echo $this->escapeHtml($title); ?></h1>
<?php
$form->setAttribute('action', $this->url('album', array('action' => 'add')));
$form->prepare();
echo $this->form()->openTag($form);
echo $this->formHidden($form->get('id'));
echo $this->formRow($form->get('title'));
echo $this->formRow($form->get('artist'));
echo $this->formSubmit($form->get('submit'));
echo $this->form()->closeTag();
Zend Framework has possibility to change style in elements. to add "clear:both;" style I think will solve problem?
<div class="form_element">
<?php
$artist = $form->get('artist');
echo $this->formRow($artist);
?></div>
<div style="clear:left;"></div>
<div class="form_element">
<?php
$title = $form->get('title');
echo $this->formRow($title);
?></div>
echo '<div style="clear:both;"> </div>';
echo $this->formRow($form->get('title'));
echo '<div style="clear:both;"> </div>';
echo $this->formRow($form->get('artist'));
echo '<div style="clear:both;"> </div>';
echo $this->formSubmit($form->get('submit'));
echo '<div style="clear:both;"> </div>';
The easiest and fastest way is to add this css..
form label
{
display: block;
}
Note that it will be slightly different from the tutorial.
Here's my form
<?php $form=$this->beginWidget('booster.widgets.TbActiveForm',array(
'id'=>'listing-main-form',
'enableAjaxValidation'=>false,
'action'=>Yii::app()->createUrl('site/search'),
'method'=>'get',
)); ?>
<div class="form-group" style="padding-bottom:0px;border:none">
<label class="control-label" for="selecttype">Type</label>
<?php echo $form->dropDownListGroup(
$model,
'prp',
array(
'wrapperHtmlOptions' => array(
'class' => 'col-sm-5',
),
'widgetOptions' => array(
'data' => CHtml::listData(Type::model()->findAll(), 'id', 'type'),
'htmlOptions' => array('id'=>'selecttype'),
),
'label' => ''
)
); ?>
</div>
<div class="form-group">
<div id="resproperties">
<div class="resdv">
<?php echo $form->checkboxListGroup(
$model,
'rs',
array(
'widgetOptions' => array(
'data' =>CHtml::listData(ResourceCategory::model()->findAll(), 'id', 'res_category'),
),
'label' => ''
)
); ?>
</div>
</div>
............
............
When the form is submitted, I can read all the field's data fine. But the url appears with Model[field] for each fields and looks very ugly (see below). Is there any where I can remove the model name from there?
index.php?r=site/search&ItemModel[prp]=1&ItemModel[rs]=&ItemModel[rs][]=2&ItemModel[rs][]=3&ItemModel[rs][]=4&ItemModel[cm] ............
You can explicitly set input name.
...
'htmlOptions' => array(
'id'=>'selecttype',
'name' => 'fieldname'
)
...
Also you can override CHtml and CActiveForm classes.
In your array for each element, add
'name'=>'your_custom_name'
So...
<?php echo $form->dropDownListGroup(
$model,
'prp',
array(
'wrapperHtmlOptions' => array(
'class' => 'col-sm-5',
),
'widgetOptions' => array(
'data' => CHtml::listData(Type::model()->findAll(), 'id', 'type'),
'htmlOptions' => array('id'=>'selecttype'),
),
'label' => '',
'name' => 'customName'
)
); ?>
I have created a form with nested Collection Customer(Form) -> Categories(Collection/Fieldset) -> Tags(Collection/Fieldset).
It's:
One(Customer) -> Many(Categories)
One(Catogrie) -> Many(Tags)
After bind the customer to the Form it looks like everything is working fine. The Hydrator get the object and the elements where created in Tags.
But in the View the Tag-Elements have no value...
I have checked the Hydrator for typos but everything is fine I copy/paste the index to make sure. When i var_dump the Tags-Collection the objects with value are binded.
I really dont know where the error is, thats why i dont enter some code here I think it would be to much. When you have an idea I can show you the code where you guess the error can be.
Greetings.
Tiega.
EDIT:
Okay I will try to do my best to give you readable code :)
class KontakteController extends AbstractActionController {
public function getKontaktAction()
{
$formManager = $this->serviceLocator->get('FormElementManager');
$kontaktForm = $formManager->get('KontakteManager\Form\KontakteForm');
$id = $this->params()->fromRoute('id');
$kontakt = $this->getKontakte()->getKontakt($id);
if (!$id || !$kontakt) {
return $this->redirect()->toRoute('kontakte', array(
'action' => 'addKontakt'
));
}
$kontakt->initFirmaKommunikation($this->getKommunikation());
$kontakt->initAdressen($this->getAdressen());
$kontakt->initAnsprechpartner($this->getKontakte());
$kontakt->initBankverbindungen($this->getBankverbindung());
$kontakt->initFirmaKategorien($this->getKontakteKategorie());
$kontakt->initPersonKategoiern($this->getKontakteKategorie());
$kontaktForm->bind($kontakt);
return new ViewModel(array(
'kontaktForm' => $kontaktForm,
'geloescht' => $kontakt->geloescht,
'tags' => $this->ladeTags(),
));
}
CustomerFieldset:
class KontakteForm extends Form implements InputFilterProviderInterface {
public function __construct()
{
parent::__construct('kontakt');
$this->setHydrator(new KontaktHydrator())
->setObject(new Kontakt());
$this->add(array(
'type' => 'Zend\Form\Element\Collection',
'name' => 'firmaKategorien',
'options' => array(
'count' => 0,
'allow_add' => true,
'allow_remove' => true,
'should_create_template' => false,
'target_element' => array(
'type' => 'KontakteManager\Form\KontaktKategorieFieldset'
)
)
));
}
/**
* #return array
\*/
public function getInputFilterSpecification()
{
return array();
}
The CategorieFieldset:
class KontaktKategorieFieldset extends Fieldset {
public function __construct()
{
parent::__construct('kontakteKategorie');
$this->setHydrator(new KontaktKategorieFieldsetHydrator())
->setObject(new KontaktKategorie());
$this->add(array(
'name' => 'id',
'type' => 'Zend\Form\Element\Hidden',
'attributes' => array(
'class' => 'form-control',
),
));
$this->add(array(
'name' => 'bezeichnung',
'type' => 'Zend\Form\Element\Text',
'attributes' => array(
'class' => 'form-control',
),
'options' => array(
'label' => 'Kategorie',
),
));
$this->add(array(
'type' => 'Zend\Form\Element\Collection',
'name' => 'tags',
'options' => array(
'count' => 0,
'allow_add' => true,
'allow_remove' => true,
'should_create_template' => false,
'target_element' => array(
'type' => 'KontakteManager\Form\TagFieldset'
)
)
));
}
And the TagFielset:
class TagFieldset extends Fieldset implements InputFilterProviderInterface {
public function __construct()
{
parent::__construct('Tag');
$this->setHydrator(new TagHydrator())
->setObject(new Tag());
$this->add(array(
'name' => 'id',
'type' => 'Zend\Form\Element\Hidden',
'attributes' => array(
'class' => 'form-control',
),
));
$this->add(array(
'name' => 'mehrsprachig',
'type' => 'Zend\Form\Element\Hidden',
'attributes' => array(
'class' => 'form-control',
),
'options' => array(
'label' => 'Mehrsprachig',
),
));
$this->add(array(
'name' => 'kategorieID',
'type' => 'Zend\Form\Element\Hidden',
'attributes' => array(
'class' => 'form-control',
),
));
$this->add(array(
'name' => 'bezeichnung',
'type' => 'Zend\Form\Element\Text',
'attributes' => array(
'class' => 'form-control',
'readonly' => 'readonly',
),
'options' => array(
'label' => 'Bezeichnung',
),
));
}
/**
* #return array
\*/
public function getInputFilterSpecification()
{
return array();
}
And the View code how i try to display the collections
<h5 class="text-primary"><strong>Kategorien</strong></h5>
<hr>
<?php foreach($kontaktForm->get('firmaKategorien') as $element): ?>
<div class="row">
<div class="col-lg-12">
<div class="col-lg-6">
<?php echo $this->formElement($element->get('bezeichnung')); ?>
</div>
<div class="col-lg-6">
<?php foreach($element->get('tags') as $tag): ?>
<?php echo $this->formElement($tag->get('bezeichnung')); ?>
<?php endforeach; ?>
</div>
</div>
</div>
<?php endforeach; ?>
and here an example result:
<h5 class="text-primary"><strong>Kategorien</strong></h5>
<hr>
<div class="row">
<div class="col-lg-12">
<div class="col-lg-6">
<input type="text" name="firmaKategorien[0][bezeichnung]" class="form-control" value="Druckerei">
</div>
<div class="col-lg-6">
<input type="text" name="firmaKategorien[0][tags][0][bezeichnung]" class="form-control" readonly="readonly" value="">
<input type="text" name="firmaKategorien[0][tags][1][bezeichnung]" class="form-control" readonly="readonly" value="">
</div>
</div>
See if this will make any changes
$kontaktForm->bind($kontakt);
//Add this line
$kontaktForm->setData((Array)$kontakt);
Please post back the error you get
CakePHP's FormHelper is how you generate forms when making CakePHP applications. As one might assume, this includes generating input elements, like so:
$this->Form->input('abc');
Which will produce HTML something like this:
<div class="input text">
<label for="ModelAbc">Abc</label>
<input name="data[Model][Abc]" class="" maxlength="250" type="text" id="ModelAbc">
</div>
Now, sadly, Bootstrap wants something like the following:
<div class="control-group">
<label for="ModelAbc" class="control-label">Abc</label>
<div class="controls">
<input name="data[Model][Abc]" class="" maxlength="250" type="text" id="ModelAbc">
</div>
</div>
How do I make CakePHP produce this output?
Inspired by lericson's answer, this is my final solution for CakePHP 2.x:
<?php echo $this->Form->create('ModelName', array(
'class' => 'form-horizontal',
'inputDefaults' => array(
'format' => array('before', 'label', 'between', 'input', 'error', 'after'),
'div' => array('class' => 'control-group'),
'label' => array('class' => 'control-label'),
'between' => '<div class="controls">',
'after' => '</div>',
'error' => array('attributes' => array('wrap' => 'span', 'class' => 'help-inline')),
)));?>
<fieldset>
<?php echo $this->Form->input('Fieldname', array(
'label' => array('class' => 'control-label'), // the preset in Form->create() doesn't work for me
)); ?>
</fieldset>
<?php echo $this->Form->end();?>
Which produces:
<form...>
<fieldset>
<div class="control-group required error">
<label for="Fieldname" class="control-label">Fieldname</label>
<div class="controls">
<input name="data[Fieldname]" class="form-error" maxlength="255" type="text" value="" id="Fieldname"/>
<span class="help-inline">Error message</span>
</div>
</div>
</fieldset>
</form>
I basically added the 'format' and 'error' keys, and added the control-label class to the label element.
Here's a solution for Bootstrap 3
<?php echo $this->Form->create('User', array(
'class' => 'form-horizontal',
'role' => 'form',
'inputDefaults' => array(
'format' => array('before', 'label', 'between', 'input', 'error', 'after'),
'div' => array('class' => 'form-group'),
'class' => array('form-control'),
'label' => array('class' => 'col-lg-2 control-label'),
'between' => '<div class="col-lg-3">',
'after' => '</div>',
'error' => array('attributes' => array('wrap' => 'span', 'class' => 'help-inline')),
))); ?>
<fieldset>
<legend><?php echo __('Username and password'); ?></legend>
<?php echo $this->Form->input('username'); ?>
<?php echo $this->Form->input('password'); ?>
</fieldset>
<?php echo $this->Form->end(__('Login')); ?>
In case a field needs its own label:
<?php echo $this->Form->input('username', array('label' => array('text' => 'Your username', 'class' => 'col-lg-2 control-label'))); ?>
Here's one way:
<?php echo $this->Form->create(null, array(
'inputDefaults' => array(
'div' => array('class' => 'control-group'),
'label' => array('class' => 'control-label'),
'between' => '<div class="controls">',
'after' => '</div>',
'class' => '')
)); ?>
Your answer is correct, but for the benefit of other users there's some other tweaks you can do to take advantage of the error/help text:
Add form-horizontal to class in the Form->create() for more compact forms (labels on the left of the input, rather than on top)
Here's how to put help text underneath a field (has to be done for each field), not forgetting to close the </div>.
echo $this->Form->input('field_name', array(
'after'=>'<span class="help-block">This text appears
underneath the input.</span></div>'));
and to correctly display errors:
// cake 2.0
echo $this->Form->input('abc', array(
'error' => array('attributes' => array('class' => 'controls help-block'))
));
Outputs:
<div class="control-group required error">
<label for="ModelAbc" class="control-label">Abc</label>
<div class="controls">
<input name="data[Model][Abc]" class="" maxlength="250" type="text" id="ModelAbc">
</div>
<!-- error message -->
<div class="controls help-block">This is the error validation message.</div>
<!-- error message -->
</div>
It's extra mark-up and not as neat as bootstrap but it's a quick fix. The alternative is to do each error message individually.
and it lines up nicely. I haven't discovered an easy way to make use of inline messages yet however.
Applying the same principle as above to the form->end function as follows:
<?php echo $this->Form->end(array(
'label' => __('Submit'),
'class' => 'btn',
'div' => array(
'class' => 'control-group',
),
'before' => '<div class="controls">',
'after' => '</div>'
));?>
To produce:
<div class="control-group">
<div class="controls">
<input class="btn" type="submit" value="Submit">
</div>
</div>
small add for another comments:
if you whant add class and change label base text, you can write next
<?php echo $this->Form->input('Fieldname', array(
'label' => array('class' => 'control-label','text'=>'HERE YOU LABEL TEXT')
)); ?>
I had the same problem using slywalker / cakephp-plugin-boost_cake, I open a ticket and he had it fix in a few hours, he updated to 1,03 and told me to use it like this
<?php echo $this->Form->input('email', array(
'label' => array(
'text' => __('Email:'),
),
'beforeInput' => '<div class="input-append">',
'afterInput' => '<span class="add-on"><i class="icon-envelope"></i></span></div>'
)); ?>
I hope it helps some one else too
To get it working with a horizontal form in bootstrap with bootswatch I had to use:
echo $this->Form->create(
'User',
array(
'action' => 'add',
'admin' => 'false',
'class' => 'form-horizontal',
'inputDefaults' => array(
'format' => array( 'before', 'label', 'between',
'input', 'error', 'after' ),
'class' => 'form-control',
'div' => array( 'class' => 'form-group' ),
'label' => array( 'class' => 'col-lg-2 control-label' ),
'between' => '<div class="col-lg-10">',
'after' => '</div>',
'error' => array( 'attributes' => array( 'wrap' => 'span',
'class' => 'text-danger' ) ),
)
)
);
Then you can just use it as normal:
echo $this->Form->input( 'User.username' );
Luc Franken posted this link in his comment: http://github.com/slywalker/cakephp-plugin-boost_cake
It took me a while to notice it, so for those who are still looking for the simplest solution:
Simply add the CakePHP Bootstrap plugin from GitHub and let the helper do the job for you!