Zend Framework 2 formInput or formElement ID tag not rendering - forms

In Zend framework 2, when I use the view's formRow method like so
$this->formRow($form->get('product_name'));
it will generate HTML like this
<label for="product_name">
<span>Name</span>
<input type="text" id="product_name" name="product_name">
</label>
but if I use formInput
<div class="control-group">
<?php echo $this->formLabel($form->get('product_name')->setLabelAttributes(array('class'=>'control-label'))); ?>
<div class="controls">
<?php echo $this->formInput($form->get('product_name')); ?>
</div>
</div>
$this->formInput($form->get('product_name'));
i don't get the id tag
<input type="" name="product_name">
I've tried with formElement with same results.
How can I get it to render just the input with all attributes and values?
This is how my Zend Framework 2 View looks like (simplified)
<?php echo $this->form()->openTag($form); ?>
<div class="control-group">
<?php echo $this->formLabel($form->get('product_name')->setLabelAttributes(array('class'=>'control-label'))); ?>
<div class="controls"><?php echo $this->formInput($form->get('product_name')); ?></div>
</div>
<div class="control-group">
<div class="controls"><?php echo $this->formSubmit($form->get('submit')); ?></div>
</div>
<?php echo $this->form()->closeTag(); ?>
and the Zend Framework 2 Form
<?php
namespace Product\Form;
use Zend\Form\Form;
class ProductForm extends Form
{
public function __construct($name = null)
{
// we want to ignore the name passed
parent::__construct('product');
$this->setAttribute('method', 'post');
$this->setAttribute('class','form-horizontal');
$this->add(array(
'name' => 'product_name',
'attributes' => array(
'type' => 'text',
),
'options' => array(
'label' => 'Name',
),
));
$this->add(array(
'name' => 'submit',
'attributes' => array(
'type' => 'submit',
'value' => 'Save',
'id' => 'submitbutton',
'class'=>'btn btn-success btn-large'
),
));
}
}
?>

Change:
$this->add(array(
'name' => 'product_name',
'attributes' => array(
'type' => 'text',
),
'options' => array(
'label' => 'Name',
),
));
to:
$this->add(array(
'name' => 'product_name',
'attributes' => array(
'type' => 'text',
'id' => 'product_name',
),
'options' => array(
'label' => 'Name',
),
));

Actually this code:
$this->add(array(
'type' => 'Zend\Form\Element\Text',
'name' => 'product_name',
'attributes' => array(
'id' => 'product_name',
'class' => 'span3',
),
'options' => array(
'label' => 'Your label',
),
));
could be used correctly by a css renderer like Bootstrap due to fact that the $this->formRow(...) form helper will produce:
<label for="product_name">Your label</label><input type="text" name="product_name" class="span3" id="product_name" value="">
which is more readable than the original formRow output (without id neither class attributes)

Related

In Cakephp 3.6 How do I get the size and type of an image to send it by form?

How do I get the size and type of an image to send it by form?
Well that, I want to save in the table of images the size and type of an image that is uploaded through a form. With Ajax, I can recover those data, but to pass them to PHP I can only do when sending the form, also directly with PHP:
if ($this->request->is('post')) {
$isData = $this->request->getdata();
$imagene->imagen = $isData['image_path'];
$imagene->tipo = $isData['type']
$imagene->tamano = $isData['size'];
...
But I want to do it before sending the form, which is when the insertion is done in the database.
Form:
<?= $this->Form->create($imagene, ['novalidate', 'id' => 'addimageform', 'class' => 'form addimageform']); ?>
<?= $this->Form->control('imagen', ['type' => 'file', 'class' => 'imagen-addimage']); ?>
<?= $this->Form->hidden('tipo', ['value' => $tipo, 'class' => 'tipo-addimage']); ?>
<?= $this->Form->hidden('$tipo', ['value' => $size, 'class' => 'tamano-addimage']); ?>
<?= $this->Form->button('Subir imagen', ['id' => 'submit', 'class' => 'submit-addimage']); ?>
<?= $this->Form->button('Omitir', ['id' => 'omitir', 'class' => 'omitir-addimage', 'redirect' => ['controller' => 'administracion', 'action' => 'index']]); ?>
<?= $this->Form->end(); ?>
Now I see that if I do a debug of $isData, the field: "imagen" does not appear:
'tabla' => 'users',
'id_tabla' => '22',
'tipo' => '',
'tamano' => ''
UPDATING
I've changed things in the form and the controller:
form:
<?= $this->Form->create($imagene, ['enctype' => 'multipart/form-data', 'novalidate', 'id' => 'addimageform', 'class' => 'form addimageform']); ?>
<?= $this->Form->control('imagen', ['type' => 'file', 'class' => 'imagen-addimage']); ?>
<div class="centrar-submit">
<?= $this->Form->button('Subir imagen', ['id' => 'submit', 'class' => 'submit-addimage']); ?>
<?= $this->Form->button('Omitir', ['id' => 'omitir', 'class' => 'omitir-addimage', 'redirect' => ['controller' => 'administracion', 'action' => 'index']]); ?>
</div>
<?= $this->Form->end(); ?>
Controller:
public function add($table, $idTable) {
$imagene = $this->Imagenes->newEntity();
if ($this->request->is('post')) {
$isData = $this->request->getdata();
debug($this->request->getData('imagen')); // <---- Is null
debug($isData); // <---- Is empty
...
Why? I don't know.
You should mentioned what type of form you used. That is file type you should use
echo $this->Form->create($article, ['type' => 'file']);
Hope this help you.

CakePHP saveMany doesnt save

I have the following Form Code.
<?php echo $this
->Form
->create(
'PagePhoto',
array(
'type' => 'file',
'url' => array(
'controller' => 'page_photos',
'action' => 'add'
)
)
); ?>
<div class="modal-body has-padding">
<div class="form-group">
<?php echo $this->Form->label('PagePhoto.0.filename', 'Photos:'); ?>
<br/><br/>
<?php echo $this->Form->file('PagePhoto.0.filename', array('required' => false)); ?>
<?php echo $this->Form->error('PagePhoto.0.filename', null, array('class' => 'label label-block label-danger text-left', 'wrap' => 'label')); ?>
<br/>
<?php echo $this->Form->file('PagePhoto.1.filename', array('required' => false)); ?>
<?php echo $this->Form->error('PagePhoto.1.filename', null, array('class' => 'label label-block label-danger text-left', 'wrap' => 'label')); ?>
<br/>
<?php echo $this->Form->file('PagePhoto.2.filename', array('required' => false)); ?>
<?php echo $this->Form->error('PagePhoto.2.filename', null, array('class' => 'label label-block label-danger text-left', 'wrap' => 'label')); ?>
<br/>
<?php echo $this->Form->file('PagePhoto.3.filename', array('required' => false)); ?>
<?php echo $this->Form->error('PagePhoto.3.filename', null, array('class' => 'label label-block label-danger text-left', 'wrap' => 'label')); ?>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-warning" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Upload Photos</button>
</div>
Which returns the following array to the add action
array(
'PagePhoto' => array(
(int) 0 => array(
'filename' => array(
'name' => 'IMG_1683.jpg',
'type' => 'image/jpeg',
'tmp_name' => '/Applications/MAMP/tmp/php/phpoIrbZ6',
'error' => (int) 0,
'size' => (int) 94131
)
),
(int) 1 => array(
'filename' => array(
'name' => 'IMG_1683.jpg',
'type' => 'image/jpeg',
'tmp_name' => '/Applications/MAMP/tmp/php/phpAcbXbC',
'error' => (int) 0,
'size' => (int) 94131
)
),
(int) 2 => array(
'filename' => array(
'name' => 'IMG_1683.jpg',
'type' => 'image/jpeg',
'tmp_name' => '/Applications/MAMP/tmp/php/phppCeN8G',
'error' => (int) 0,
'size' => (int) 94131
)
),
(int) 3 => array(
'filename' => array(
'name' => 'IMG_1683.jpg',
'type' => 'image/jpeg',
'tmp_name' => '/Applications/MAMP/tmp/php/php8Ib3bO',
'error' => (int) 0,
'size' => (int) 94131
)
)
)
)
Add Action
public function admin_add() {
if ($this->request->is('post')) {
debug($this->request->data);
$this->PagePhoto->create();
if ($this->PagePhoto->saveMany($this->request->data)) {
$this->Session->setFlash(__('The gallery has been saved.'), 'admin/flash_success');
// return $this->redirect(array('action' => 'view', $this->request->data['Gallery']['album_id']));
} else {
$this->Session->setFlash(__('The gallery could not be saved. Please, try again.'), 'admin/flash_error');
}
} else {
// $this->request->data['Gallery']['album_id'] = $album_id;
}
}
Error:
FAILURE: The gallery could not be saved. Please, try again.
$this->PagePhoto->saveMany($this->request->data['PagePhoto']);
Note: When saving multiple records of same model the records arrays should be just numerically indexed without the model key.

How to handle multiple forms in the same view?

I have a default form for my specific view.
Through an element I (dinamically) include another view (using view extension) in order to provide an upload form.
My problem is that the second form seems to submit the first one.
Default form
<div class="content-box-content">
<?php
echo $this->Form->create("WebSubject", array(
'inputDefaults' => array(
'error' => array(
'attributes' => array(
'wrap' => 'span',
'class' => 'input-notification error png_bg'
)
)
)
));
?>
<?=$this->Form->input('id', array('type' => 'hidden'))?>
<?=$this->Form->input('title', array('class' => "text-input small-input", 'label' => 'Denumire'))?>
<?=$this->Form->input('description', array('type' => 'textarea', 'label' => 'Descriere', 'id' => 'description'))?>
<?=$this->Form->input('description_long', array('type' => 'textarea', 'label' => 'Continut', 'id' => 'description_long'))?>
<?=$this->Form->submit('Salveaza', array('class' => "button"))?>
</div>
This way I include the element
<div class="tab-content default-tab" id="fotoUploadTab">
<?php
echo $this->element('file_upload_form', array(
'view' => 'upload_admin',
'webFileType' => 'image',
'redirect' => $SHT['here']
)
);
?>
<div class="tab-content default-tab">
Lista imagini
</div>
</div>
Element code
<?php
$view = (isset($view)) ? $view : "upload_admin";
$webFileType = (isset($webFileType)) ? $webFileType : "image";
$redirect = (isset($redirect)) ? $redirect : "/";
?>
<?php
$this->extend("/WebFiles/".$view);
?>
Extended View code
<div class="tab-content default-tab">
<?php echo $this->Form->create("WebFile", array('action' => '/', 'type' => 'file')); ?>
<input type="hidden" name="redirect" value="" />
<?php echo $this->Form->input('entity_id', array('type' => 'hidden')); ?>
<?php echo $this->Form->input('entity_table_name', array('type' => 'hidden')); ?>
<?php echo $this->Form->input('type', array('type' => 'hidden')); ?>
<?php echo $this->Form->input('title', array('class' => "text-input small-input", 'label' => 'Denumire')); ?>
<?php echo $this->Form->input('description', array('class' => "text-input small-input", 'label' => 'Descriere')); ?>
<?php echo $this->Form->submit('Upload', array('class' => 'button')); ?>
</div>
As seen in the last snippet, I tried to force the last form by providing an action url, but on submiting it, it sends data as the first one does.
How should I handle this ?
Thank you!
If you just want to have both forms, the one from parent and the other from the child view/element make sure you call $this->Form->end() in both templates and that you are not nesting a form inside the other. Probably, in your case, just by adding end() to both forms will solve your issue.
As a side note, you cannot have a parent view opening a Form with $this->Form->create() and inject fields into it using the child view, basically because you need create() to be called before any input is rendered and parent views are rendered after the child is executed.

How can I use zend form decorator to render errors inside my paragraph tag wrapping label and input

I would like to render the following markup:
<div class="row">
<p>
<label>Your Name</label>
<input type="text" class="text_field" name="name">
<ul class="errors">
<li>Waarde is vereist en kan niet leeg worden gelaten</li>
</ul>
</p>
</div>
This is my Zend form element + decorator:
$this->addElement('text', 'name', array(
'label' => 'Naam:',
'class' => 'text_field',
'required' => true,
'decorators' => array(
'ViewHelper',
'Label',
'Errors',
array(array('row' => 'HtmlTag'), array('tag' => 'p')),
array(array('content' => 'HtmlTag'), array('tag' => 'div', 'class' => 'row'))
)));
But this always renders the ul list below the p tag and never inside. It also adds an additional p tag below the list.
<div class="row">
<p>
<label class="required" for="name">Naam:</label>
<input type="text" class="text_field" value="" id="name" name="name">
</p>
<ul class="errors">
<li>Waarde is vereist en kan niet leeg worden gelaten</li>
</ul>
<p></p>
</div>
What am I doing wrong?
Found it! My stupid mistake. I did only check the final rendered output in my browser. I am using a template which also loads javascript and this changes the DOM which creates the unwanted result.
So the first decorator setup was working correct.
Try to do the following:
$this->addElement('text', 'name', array(
'label' => 'Naam:',
'class' => 'text_field',
'required' => true,
'decorators' => array(
'ViewHelper',
'Label',
'Errors',
array(array('content' => 'HtmlTag'), array('tag' => 'p')),
array(array('content' => 'HtmlTag'), array('tag' => 'div', 'class' => 'row'))
)));

How to get rid of the Zend_Form dl, dt, dd tags?

I would like to get rid of the definition list format of my Zend_Form. This is the layout that I'm going for:
<form>
<p>
<label for="email" class="required">Your email address:</label>
<input type="text" name="email" id="email" value="">
</p>
<p>
<input type="submit" name="submit" id="submit" value="Subscribe">
</p>
<input type="hidden" name="active" value="true" id="active">
<input type="hidden" name="signupDate" value="" id="signupDate">
</form>
What do I need to do to my form in order to get this layout?
class Default_Form_Subscribe extends Zend_Form
{
public function init()
{
$this->setMethod('post');
$this->addElement('text', 'email', array(
'label' => 'Email address:',
'required' => true,
'filters' => array('StringTrim'),
'validators' => array('EmailAddress')
));
$this->addElement('submit', 'submit', array(
'label' => 'Subscribe',
'ignore' => true
));
$this->addElement('hidden', 'active', array(
'value'=>'true'
));
$this->addElement('hidden', 'signupDate', array(
'value' => Zend_Date::now()->toString('YYYY-MM-dd')
));
}
}
Ah, beat me to it... I went with the approach of creating a custom definition that can be applied to specific elements. Also had to reset the decorators on the form itself to remove the default 'dl' wrapper, seems to do exactly what you need:
class Default_Form_Subscribe extends Zend_Form
{
public function init()
{
$this->setMethod('post');
// reset form decorators to remove the 'dl' wrapper
$this->setDecorators(array('FormElements','Form'));
// custom decorator definition for form elements
$customElementDecorators = array(
'ViewHelper',
'Errors',
array(
'Description',
array('tag' => 'p','class' => 'description')
),
array(
'Label',
array('separator' => ' ')
),
array(
array('data' => 'HtmlTag'),
array('tag' => 'p')
)
);
$this->addElement('text', 'email', array(
'label' => 'Email address:',
'required' => true,
'filters' => array('StringTrim'),
'validators' => array('EmailAddress'),
'decorators' => $customElementDecorators
));
$this->addElement('submit', 'submit', array(
'label' => 'Subscribe',
'ignore' => true,
'decorators' => $customElementDecorators
));
$this->addElement('hidden', 'active', array(
'value'=>'true',
'decorators' => array('ViewHelper')
));
$this->addElement('hidden', 'signupDate', array(
'value' => Zend_Date::now()->toString('YYYY-MM-dd'),
'decorators' => array('ViewHelper')
));
}
}
let me add probably a bit shorter way which worked for me just fine:
//after adding all the form elements
//all form elements in a loop
foreach ($this->getElements() as $el) {
$el->setDecorators(
array('ViewHelper', 'Errors', array('HtmlTag', array('tag' => 'p')
);
}
//form itself
$this->setDecorators( array('FormElements', 'Form') );
it seams to me in your case you also should filter out elements by type in search for those which does not need outer html at all
You have to customize your Zend_Form elements's decorators. Check this tutorial.
In your case it will be something similar to this:
$form->setElementDecorators(array(
'ViewHelper',
'Errors',
array('Label', array('tag' => 'label', 'placement' => 'prepend'),
array(array('data' => 'HtmlTag'), array('tag' => 'p')),
));
That sets the decorators for all the form elements. You can as well configure individual elements (like your hidden-s & buttons).
It's possible also to form display groups, and decorate them individually.