ZF2 Elements "select" and "multicheckbox" not render correctly - select

Why elements "select" and "multicheckbox" not render correctly (in html)?
Element "text" and "checkbox" render correctly!
Example:
1) Code in form:
class Profile extends Form {
public function __construct($name = null) {
parent::__construct('page');
$this->setAttribute('action', 'info');
$this->setAttribute('method', 'post');
$this->setInputFilter($this->getFilters());`
$this->add(array(
'type' => 'Zend\Form\Element\Select',
'name' => 'usernames',
'attributes' => array(
'id' => 'usernames'
),
'options' => array(
'label' => 'User Name',
'options' => array(
'test' => 'Hi, Im a test!',
'Foo' => 'Bar',
),
),
));
$this->add(array(
'type' => 'select',
'name' => 'language',
'options' => array(
'label' => 'Which is your mother tongue?',
'value' => array(
'0' => 'French',
'1' => 'English',
'2' => 'Japanese',
'3' => 'Chinese',
),
)
));
}
2) Code in view:
<h1><?php echo $this->translate('Profile') ?></h1>
<?php $form = $this->form; $form->prepare();?>
<?php echo $this->form()->openTag($form) ?>
<dl class="zend_form">
<?php foreach ($form as $element): ?>
<?php if ($element->getLabel() != null): ?>
<dt><?php echo $this->translate($this->formLabel($element)); ?></dt>
<?php endif ?>
<?php if ($element instanceof Zend\Form\Element\Button): ?>
<dd><?php echo $this->formButton($element) ?></dd>
<?php elseif ($element instanceof Zend\Form\Element\Captcha): ?>
<dd><?php echo $this->formCaptcha($element) . $this->translate($this->formElementErrors($element)); ?></dd>
<?php else: ?>
<dd><?php echo $this->formInput($element) . $this->translate($this->formElementErrors($element)); ?></dd>
<?php endif ?>
<?php endforeach ?>
</dl>
<?php if ($this->redirect): ?>
<input type="hidden" name="redirect" value="<?php echo $this->redirect ?>" />
<?php endif ?>
<input type="submit" value="<?php echo $this->translate('Submit'); ?>" />
<?php echo $this->form()->closeTag() ?>
3) Code in html, after render:
...
<dt><label for="usernames">User Name</label></dt>
<dd><input type="select" name="usernames" id="usernames" value=""></dd>
<dt><label for="language">Which is your mother tongue?</label></dt>
<dd><input type="select" name="language" value=""></dd>
...
it is not correctly!?
...
<select>
<option>value 1</option>
<option>value 2</option>
</select>
... - that's correct)

The formInput() helper is specifically for outputting <input> elements, so ZF is doing exactly what you've told it to. You probably want something more like this:
<?php foreach ($form as $element): ?>
<?php if ($element->getLabel() != null): ?>
<dt><?php echo $this->translate($this->formLabel($element)); ?></dt>
<?php endif ?>
<dd><?php echo $this->formElement($element) . $this->translate($this->formElementErrors($element)) ?></dd>
<?php endforeach ?>
The formElement() helper will call whatever helper is appropriate.

Related

CodeIgniter Omnipay Przelewy24: Message: The email parameter is required

I try enable payment gateway Przelewy24 with Omnipay library for Codeigniter 3.
For this I install via composer both libraries.
Library:
https://github.com/mysiar-org/omnipay-przelewy24v1
and
https://github.com/thephpleague/omnipay
Then I create controller
Cart_contoller.php I add function
use Omnipay\Omnipay;
/**
* Payment with Przelewy24
*/
public function przelewy24_payment_post()
{
$przelewy24 = get_payment_gateway('przelewy24');
if (empty($przelewy24)) {
$this->session->set_flashdata('error', "Payment method not found!");
echo json_encode([
'result' => 0
]);
exit();
}
/** #var \Omnipay\Przelewy24\Gateway $gateway */
$gateway = Omnipay::create('Przelewy24');
$gateway->initialize([
'merchantId' => 'xxxx',
'posId' => 'xxxx',
'crc' => 'xxxxxxxxxxxx',
'testMode' => true,
]);
$params = array(
'sessionId' => 2327398739,
'amount' => 12.34,
'currency' => 'PLN',
'description' => 'Payment test',
'returnUrl' => 'www.xxxxxx',
'notifyUrl' => 'www.xxxxxxxxxxx',
'card' => array(
'email' => 'info#example.com',
'name' => 'My name',
'country' => 'PL',
),
);
$response = $gateway->purchase($params)->send();
if ($response->isSuccessful()) {
$response->redirect();
} else {
echo 'Failed';
}
}
in view page I add:
<?php echo form_open('cart_controller/przelewy24_payment_post'); ?>
<div class="payment-icons-container">
<label class="payment-icons">
<?php $logos = #explode(',', $payment_gateway->logos);
if (!empty($logos) && item_count($logos) > 0):
foreach ($logos as $logo): ?>
<img src="<?php echo base_url(); ?>assets/img/payment/<?= html_escape(trim($logo)); ?>.svg" alt="<?= html_escape(trim($logo)); ?>">
<?php endforeach;
endif; ?>
</label>
</div>
<button id="submit" class="btn btn-primary" id="card-button">
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
<?= trans("pay"); ?> <?= price_formatted($total_amount, $currency); ?>
</button>
<?php echo form_close(); ?><!-- form end -->
On button submit I get:
Type: Omnipay\Common\Exception\InvalidRequestException
Message: The email parameter is required
What I do wrong? Can anyone help me with this code how to correct integrate this gateway?

Create using modal in yii2 something wrong

I've created form using modal. The problem is button "Create" in views/index.php. Proccess testing paging & searching successfully, but after that when I to click button "created" in views/index.php. Form create with modal not display, I don't know why.
Code in controller
public function actionCreate()
{
$model = new Donatur();
if ($model->load(Yii::$app->request->post()) && $model->save()) {
Yii::$app->session->setFlash('success', 'Data berhasil disimpan!');
return $this->redirect(['index']);
return $this->refresh();
} else {
if (Yii::$app->request->isAjax) {
return $this->renderAjax('create', ['model' => $model]);
}
else{
return $this->render('create', ['model' => $model]);
}
}
}
Code in views/index.php
<?php \yii\widgets\Pjax::begin(['timeout' => false, 'id' => 'pjax-gridview']); ?>
<?php
use yii\helpers\Html;
use yii\grid\GridView;
use yii\widgets\Pjax;
use yii\bootstrap\Modal;
use yii\helpers\Url;
/* #var $this yii\web\View */
/* #var $searchModel app\models\SearchDonatur */
/* #var $dataProvider yii\data\ActiveDataProvider */
$this->title = 'Data Donatur';
?>
<?php if (Yii::$app->session->hasFlash('success')): ?>
<div class="alert alert-success alert-dismissable">
<button aria-hidden="true" data-dismiss="alert" class="close" type="button">×</button>
<h4><i class="icon fa fa-check"></i>Informasi!</h4>
<?= Yii::$app->session->getFlash('success') ?>
</div>
<?php endif; ?>
<?php if (Yii::$app->session->hasFlash('delete')): ?>
<div class="alert alert-success alert-dismissable">
<button aria-hidden="true" data-dismiss="alert" class="close" type="button">×</button>
<h4><i class="icon fa fa-check"></i>Informasi!</h4>
<?= Yii::$app->session->getFlash('delete') ?>
</div>
<?php endif; ?>
<div class="donatur-index">
<?php Pjax::begin(['timeout'=>false,'id'=>'pjax-gridview']); ?>
<h1><?= Html::encode($this->title) ?></h1>
<?php // echo $this->render('_search', ['model' => $searchModel]); ?>
<p>
<?= Html::button('Tambah Donatur', ['value'=>Url::to('create'),'class' => 'btn btn-success','id'=>'modalButton']) ?>
</p>
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'emptyCell'=>'-',
'summary'=>'',
'columns' => [
//['class' => 'yii\grid\SerialColumn'],
[
'attribute'=>'kode_donatur',
'value'=>'kode_donatur',
'contentOptions'=>['style'=>'width: 200px;']
],
[
'attribute'=>'nama_donatur',
'value'=>'nama_donatur',
'contentOptions'=>['style'=>'width: 250px;']
],
[
'attribute'=>'alamat',
'value'=>'alamat',
'contentOptions'=>['style'=>'width: 350px;']
],
[
'attribute'=>'telepon',
'value'=>'telepon',
'contentOptions'=>['style'=>'width: 290px;']
],
[
'class' => \yii\grid\ActionColumn::className(),
'header' => 'Aksi',
'template' => '{update} {delete}',
'buttons' => [
'update' => function($url, $model) {
$icon = '<span class="glyphicon glyphicon-pencil"></span>';
return Html::a($icon, $url,[
'data-toggle' => "modal",
'data-target' => "#donaturModal",
]);
},
'delete' => function($url, $model) {
$icon = '<span class="glyphicon glyphicon-trash"></span>';
return Html::a($icon, $url,
[
'data-confirm' => "Apakah yakin dihapus ?",
'data-method' => 'post',
]);
},
]
],
],
]); ?>
<?php \yii\widgets\Pjax::end() ?>
<?php Pjax::end(); ?>
</div>
<?php
// for modal update
Modal::begin([
'id' => 'donaturModal',
'header' => '<h1 align="center">Ubah Data Donatur</h1>',
]);
Pjax::begin(['id'=>'pjax-modal', 'timeout'=>false,
'enablePushState'=>false,
'enableReplaceState'=>false,]);
Pjax::end();
Modal::end();
?>
<?php
// for modal update
$this->registerJs('
$("#donaturModal").on("shown.bs.modal", function (event) {
var button = $(event.relatedTarget)
var href = button.attr("href")
$.pjax.reload("#pjax-modal", {
"timeout":false,
"url":href,
"replace":false,
});
})
');
?>
<?php
// for modal create
Modal::begin([
'header' => '<h1 align="center">Tambah Donatur</h1>',
'id' => 'modal',
]);
echo "<div id='modalContent'><div>";
Modal::end()
?>
<?php
// for modal create
Modal::begin([
'id' => 'modal',
'header' => '<h1 align="center">Ubah Data Donatur</h1>',
]);
Pjax::begin(['id'=>'pjax-modal', 'timeout'=>false,
'enablePushState'=>false,
'enableReplaceState'=>false,]);
Pjax::end();
Modal::end();
?>
<?php
// for modal create
$this->registerJs('
$("#modal").on("shown.bs.modal", function (event) {
var button = $(event.relatedTarget)
var href = button.attr("href")
$.pjax.reload("#pjax-modal", {
"timeout":false,
"url":href,
"replace":false,
});
})
');
?>
Code in views/create.php
<?php
use yii\helpers\Html;
use yii\bootstrap\ActiveForm;
use yii\widgets\Pjax;
use yii\bootstrap\Modal;
use yii\helpers\Url;
use yii\db\ActiveRecord;
/* #var $this yii\web\View */
/* #var $model app\models\Donatur */
?>
<h2 align="center">Form Donatur</h2>
<?php
echo "&nbsp";
echo "&nbsp";
?>
<?php $form = ActiveForm::begin([
'layout' => 'horizontal',
'enableAjaxValidation' => false,
'id' => 'create-form',
]); ?>
<?= $form->field($model, 'kode_donatur')->textInput(['readonly' => true, 'style'=>'width:100px']) ?>
<?= $form->field($model, 'nama_donatur')->textInput(['style'=>'width:350px']) ?>
<?= $form->field($model, 'alamat')->textArea(['rows' => 3, 'style'=>'width:350px']) ?>
<?= $form->field($model, 'telepon')->textInput(['style'=>'width:350px']) ?>
<div class="form-group">
<div class="col-sm-offset-4">
<?= Html::submitButton('Simpan', ['class'=> 'btn btn-primary']) ?>
<?php
echo "&nbsp";
echo "&nbsp";
echo Html::a('Keluar', ['index'],[
'class'=>'btn btn-success',
'onclick' =>'$("#modal").modal("hide");
return false;'
]);
?>
</div>
</div>
<?php ActiveForm::end();?>
The before I created form created with modal follow this link : click
I think problem with button handler.
Probably you forgot to add handler:
$(function(){
$('#modalButton').click(function(){ ... });
})

Codeigniter validate form is not working

I have the same implementation for my login for and is working, but on my contact form it is not, and I have no error message just re routed to the home page.
the weird thing is if in my controller i implement the index function like this:
public function index() {
$this->myprocess();
}
and my view using
<?php
$attributes = array('class' => 'form-contact', 'id' => 'myform2');
echo form_open('contact',$attributes);
?>
instead of calling my function myprocess all the validations work but no use for a form with out my header footers etc.
bellow that is how i want my code to work i hope yall can help me.
my controller:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class contact extends CI_Controller {
function __construct()
{
parent::__construct();
$this->load->model('contact_m');
}
public function index()
{
$data = array('title' => 'Contact', 'main_content' => 'contact_v');
$this->load->view('template', $data);
}
public function myprocess(){
$this->form_validation->set_rules('dfname', 'Name', 'required|trim|xss_clean|max_length[40]');
$this->form_validation->set_rules('dfemail', 'Email', 'required|trim|xss_clean|valid_email|max_length[50]|callback__verifyemail');
$this->form_validation->set_rules('dfmsg', 'dfmsg', 'trim|xss_clean');
$this->form_validation->set_error_delimiters('<br /><span class="error">', '</span>');
if ($this->form_validation->run() == FALSE) // validation hasn't been passed
{
$this->load->view('contact_v');
}
else
{
$form_data = array(
'dfname' => set_value('dfname'),
'dfemail' => set_value('dfemail'),
'dfmsg' => set_value('dfmsg')
);
if ($this->contact_m->SaveForm($form_data) == TRUE)
{
redirect('contact/success');
}
else
{
echo 'An error occurred saving your information. Please try again later';
}
}
}
function success()
{
echo 'this form has been successfully submitted with all validation being passed. All messages or logic here. Please note
sessions have not been used and would need to be added in to suit your app';
}
public function verifyemail(){
$name = $this->input->post('dfName');
$pass = $this->input->post('dfemail');
if($this->contact_m->email_exist($name,$pass)){
if ($this->session->userdata('site_lang') == 'portuguese')
{
$this->form_validation->set_message('_verifyuser','Usuario Inexistente!');
}else{
$this->form_validation->set_message('_verifyuser','User Not Found!');
}
$this->index();
return false;
}else{
return true;
}
}
}
?>
my view:
<div class="container">
<div class="row">
<div class=" col-md-4 col-md-offset-4">
<?php echo br(2)?>
<div class="account-wall drop-shadow">
<?php
$title = $this->my_library->my_title($this->session->userdata('site_lang'),FORM_CONTACT);
echo '<h1 class="text-center login-title">'. $title. '</h1>';
echo br(1)
?>
<?php
$attributes = array('class' => 'form-contact', 'id' => 'myform2');
echo form_open('contact/myprocess',$attributes);
?>
<p>
<label for="dfname">Name</span></label>
<?php echo form_error('dfname'); ?>
<input id="dfname" type="text" class="form-control" placeholder="Name" name="dfname" maxlength="40" value="<?php echo set_value('dfname'); ?>" autofocus />
<?php echo br(1)?>
</p>
<p>
<label for="dfemail">Email</span></label>
<?php echo form_error('dfemail'); ?>
<input id="dfemail" type="text" class="form-control" placeholder="Email" name="dfemail" maxlength="50" value="<?php echo set_value('dfemail'); ?>" />
<?php echo br(1)?>
</p>
<p>
<label for="dfmsg">Message</label>
<?php echo form_error('dfmsg'); ?>
<?php echo form_textarea( array( 'name' => 'dfmsg', 'rows' => '4', 'cols' => '43', 'value' => set_value('dfmsg') ) )?>
<?php echo br(1)?>
</p>
<p>
<?php echo form_submit( 'submit', 'Submit'); ?>
</p>
<?php form_close();?>
</div>
</div>
</div>
</div>
<?php echo br(5)?>
your callback function for validation need an underscore for prefix name :
public function _verifyemail()
and you need to call the process function :
public function index()
{
$data = array('title' => 'Contact', 'main_content' => 'contact_v');
if($this->input->post())
$this->myprocess();
$this->load->view('template', $data);
}
So after all this days and examining all my code and re-writing all of it i found the problem.
for some reason this line wasnt working : echo form_close(); so my first form was aways open messing up asll my validation after writing on all of then it starting working.

CakePHP 2.0 Determine which submit button has been clicked

In CakePHP 1.3 you can create a form with multiple submit buttons:
echo $this->Form->submit('Submit 1', array('name'=>'submit');
echo $this->Form->submit('Submit 2', array('name'=>'submit');
and detect which submit button was pressed in the controller with:
if (isset($this->params['form']['submit']) && $this->params['form']['submit'] == "Submit 1") {
// first button clicked
}
In CakePHP, $this->params['form'] isn't set and the clicked button value doesn't appear anywhere in $this->request, $this->request->data, $this->params, $this->data or $_POST.
How do I determine which button has been clicked in CakePHP 2.0?
Thanks in advance.
Edit:
As requested, here's the code for the form:
<?php echo $this->Form->create('History', array('action'=>'add')); ?>
<div class='submit'>
<?php
echo $this->Form->submit('Yes', array('div'=>false, 'name'=>'submit'));
echo $this->Form->submit('No', array('div'=>false, 'name'=>'submit'));
?>
</div>
<?php echo $this->Form->end()?>
And the output of the form:
<form action="/projects/kings_recruit/trunk/www/histories/add" id="HistoryAddForm" method="post" accept-charset="utf-8">
<div style="display:none;">
<input name="_method" value="POST" type="hidden">
</div>
<div class="submit">
<input name="submit" value="Yes" type="submit">
<input name="submit" value="No" type="submit">
</div>
</form>
Generally it is a bad practise to use the same name for both submit buttons.
There should be a "submit" key in the $_POST and $this->request->data
I tested this in CakePHP 2.1.1 as shown below:
The view code:
<?php echo $this->Form->create('Message', array('action'=>'test'));
// Extra test input field
echo $this->Form->input('test');
?>
<div class='submit'>
<?php
echo $this->Form->submit('Yes', array('div'=>false, 'name'=>'submit'));
echo $this->Form->submit('No', array('div'=>false, 'name'=>'submit'));
?>
</div>
<?php echo $this->Form->end()?>
The in the controller in $this->request->data:
array(
'submit' => 'Yes',
'Message' => array(
'test' => 'TestFieldTest'
)
)
And in $_POST:
array(
'_method' => 'POST',
'data' => array(
'Message' => array(
'test' => 'TestFieldTest'
)
),
'submit' => 'Yes'
)
You can also give the two submits different names:
echo $this->Form->submit('Yes', array('div'=>false, 'name'=>'submitY'));
echo $this->Form->submit('No', array('div'=>false, 'name'=>'submitN'));
This way you can differ them in the $_POST or $this->request->data, because the keys will be the submits' names:
array(
'submitY' => 'Yes',
'Message' => array(
'test' => 'foo'
)
)
array(
'_method' => 'POST',
'data' => array(
'Message' => array(
'test' => 'Bar'
)
),
'submitY' => 'Yes'
)
Then to determine which button is pressed you can use a simple isset($_POST['']) or over $this->request->data ?
Don't use the same name for both submit buttons. Consider this example:
<?php echo $this->Form->create(false); ?>
<?php echo $this->Form->text('input'); ?>
<?php echo $this->Form->submit('Yes', array('name' => 'submit1')); ?>
<?php echo $this->Form->submit('No', array('name' => 'submit2')); ?>
<?php echo $this->Form->end(); ?>
debug($this->request->data) will produce the following when the "Yes" button is clicked:
array(
'submit1' => 'Yes',
'input' => 'test'
)
And here it is when the "No" button is clicked:
array(
'submit2' => 'No',
'input' => 'test'
)
To check which button was clicked:
if (isset($this->request->data['submit1'])) {
// yes button was clicked
} else if (isset($this->request->data['submit2'])) {
// no button was clicked
}
in 2.0 there is no $this->params['form'] anymore
all form helper posted fields end up in $this->data (which makes more sense anyway)
so
if (!empty($this->data['submit']) && $this->data['submit'] == "Submit 1") {}
note that !empty() is better here as well.
PS: you can use my enhanced upgrade shell to replace it in your code: https://github.com/dereuromark/upgrade
its the command
cake Upgrade.Upgrade request
(https://github.com/dereuromark/upgrade/blob/master/Console/Command/UpgradeShell.php#L833)
if (!empty($this->request->data['submit']) && $this->request->data['submit'] == "Yes") {
// do your stuff
}

How do I use ViewScripts on Zend_Form File Elements?

I am using this ViewScript for my standard form elements:
<div class="field" id="field_<?php echo $this->element->getId(); ?>">
<?php if (0 < strlen($this->element->getLabel())) : ?>
<?php echo $this->formLabel($this->element->getName(), $this->element->getLabel());?>
<?php endif; ?>
<span class="value"><?php echo $this->{$this->element->helper}(
$this->element->getName(),
$this->element->getValue(),
$this->element->getAttribs()
) ?></span>
<?php if (0 < $this->element->getMessages()->length) : ?>
<?php echo $this->formErrors($this->element->getMessages()); ?>
<?php endif; ?>
<?php if (0 < strlen($this->element->getDescription())) : ?>
<span class="hint"><?php echo $this->element->getDescription(); ?></span>
<?php endif; ?>
</div>
Trying to use that ViewScript alone results in an error:
Exception caught by form: No file
decorator found... unable to render
file element
Looking at this FAQ revealed part of my problem, and I updated my form element decorators like this:
'decorators' => array(
array('File'),
array('ViewScript', array('viewScript' => 'form/field.phtml'))
)
Now it's rendering the file element twice, once within my view script, and extra elements with the file element outside my view script:
<input type="hidden" name="MAX_FILE_SIZE" value="8388608" id="MAX_FILE_SIZE" />
<input type="hidden" name="UPLOAD_IDENTIFIER" value="4b5f7335a55ee" id="progress_key" />
<input type="file" name="upload_file" id="upload_file" />
<div class="field" id="field_upload_file">
<label for="upload_file">Upload File</label>
<span class="value"><input type="file" name="upload_file" id="upload_file" /></span>
</div>
Any ideas on how to handle this properly with a ViewScript?
UPDATE: Based on Shaun's solution, here's my final code:
Form Element:
$this->addElement('file', 'upload_file', array(
'disableLoadDefaultDecorators' => true,
'decorators' => array('File', array('ViewScript', array(
'viewScript' => '_form/file.phtml',
'placement' => false,
))),
'label' => 'Upload',
'required' => false,
'filters' => array(),
'validators' => array(array('Count', false, 1),),
));
View Script:
<?php
$class .= 'field ' . strtolower(end(explode('_',$this->element->getType())));
if ($this->element->isRequired()) {
$class .= ' required';
}
if ($this->element->hasErrors()) {
$class .= ' errors';
}
?>
<div class="<?php echo $class; ?>" id="field_<?php echo $this->element->getId(); ?>">
<?php if (0 < strlen($this->element->getLabel())): ?>
<?php echo $this->formLabel($this->element->getFullyQualifiedName(), $this->element->getLabel());?>
<?php endif; ?>
<span class="value"><?php echo $this->content; ?></span>
<?php if ($this->element->hasErrors()): ?>
<?php echo $this->formErrors($this->element->getMessages()); ?>
<?php endif; ?>
<?php if (0 < strlen($this->element->getDescription())): ?>
<p class="hint"><?php echo $this->element->getDescription(); ?></p>
<?php endif; ?>
</div>
The answer is relatively simple as it happens. All you need do is specify the File decorator first, create a specific view script for the file input and specify false for the placement in the viewScript decorator arguments, this will effectively inject the output from the File decorator into the viewScript decorator e.g.
$element->setDecorators(array('File', array('ViewScript', array('viewScript' => 'decorators/file.phtml', 'placement' => false))));
Then in the new file element view script you simply echo $this->content in the script where you'd like the file input markup to be placed. Here's an example from a recent project, so ignore the markup if it looks a little odd, hopefully it will illustrate the point.
<label for="<?php echo $this->element->getName(); ?>" class="element <?php if ($this->element->hasErrors()): ?> error<?php endif; ?>" id="label_<?php echo $this->element->getName(); ?>">
<span><?php echo $this->element->getLabel(); ?></span>
<?php echo $this->content; ?>
<?php if ($this->element->hasErrors()): ?>
<span class="error">
<?php echo $this->formErrors($this->element->getMessages()); ?>
</span>
<?php endif; ?>
</label>
When rendered you will see this html for the element
<label for="photo" class="element" id="label_photo">
<span>Photo</span>
<input type="hidden" name="MAX_FILE_SIZE" value="6291456" id="MAX_FILE_SIZE">
<input type="file" name="photo" id="photo">
</label>
This is not a simple or ideal solution because it requires an extension of the File decorator... but it's rather frustrating that they didn't make the effort to separate the hidden element generation logic from the file input generation logic. I'm not sure if the file view helper handles the issue of an element being an array (that seems to be the reason they did it this way.)
Extension of File Decorator:
(the commented out part is what causes the extra input to be generated.)
<?php
class Sys_Form_Decorator_File extends Zend_Form_Decorator_File {
public function render($content) {
$element = $this->getElement();
if (!$element instanceof Zend_Form_Element) {return $content;}
$view = $element->getView();
if (!$view instanceof Zend_View_Interface) {return $content;}
$name = $element->getName();
$attribs = $this->getAttribs();
if (!array_key_exists('id', $attribs)) {$attribs['id'] = $name;}
$separator = $this->getSeparator();
$placement = $this->getPlacement();
$markup = array();
$size = $element->getMaxFileSize();
if ($size > 0) {
$element->setMaxFileSize(0);
$markup[] = $view->formHidden('MAX_FILE_SIZE', $size);
}
if (Zend_File_Transfer_Adapter_Http::isApcAvailable()) {
$apcAttribs = array('id' => 'progress_key');
$markup[] = $view->formHidden('APC_UPLOAD_PROGRESS', uniqid(), $apcAttribs);
}
else if (Zend_File_Transfer_Adapter_Http::isUploadProgressAvailable()) {
$uploadIdAttribs = array('id' => 'progress_key');
$markup[] = $view->formHidden('UPLOAD_IDENTIFIER', uniqid(), $uploadIdAttribs);
}
/*
if ($element->isArray()) {
$name .= "[]";
$count = $element->getMultiFile();
for ($i = 0; $i < $count; ++$i) {
$htmlAttribs = $attribs;
$htmlAttribs['id'] .= '-' . $i;
$markup[] = $view->formFile($name, $htmlAttribs);
}
}
else {$markup[] = $view->formFile($name, $attribs);}
*/
$markup = implode($separator, $markup);
switch ($placement) {
case self::PREPEND: return $markup . $separator . $content;
case self::APPEND:
default: return $content . $separator . $markup;
}
}
}
?>
Form setup in controller action:
$form = new Zend_Form();
$form->addElement(new Zend_Form_Element_File('file'));
$form->file->setLabel('File');
$form->file->setDescription('Description goes here.');
$decorators = array();
$decorators[] = array('File' => new Sys_Form_Decorator_File());
$decorators[] = array('ViewScript', array('viewScript' => '_formElementFile.phtml'));
$form->file->setDecorators($decorators);
$this->view->form = $form;
In action view:
<?php echo $this->form; ?>
In element script:
<div class="field" id="field_<?php echo $this->element->getId(); ?>">
<?php if (0 < strlen($this->element->getLabel())) : ?>
<?php echo $this->formLabel($this->element->getName(), $this->element->getLabel());?>
<?php endif; ?>
<span class="value">
<?php
echo $this->{$this->element->helper}(
$this->element->getName(),
$this->element->getValue(),
$this->element->getAttribs()
);
?>
</span>
<?php if (0 < $this->element->getMessages()->length) : ?>
<?php echo $this->formErrors($this->element->getMessages()); ?>
<?php endif; ?>
<?php if (0 < strlen($this->element->getDescription())) : ?>
<span class="hint"><?php echo $this->element->getDescription(); ?></span>
<?php endif; ?>
</div>
Output should be:
<form enctype="multipart/form-data" action="" method="post">
<dl class="zend_form">
<input type="hidden" name="MAX_FILE_SIZE" value="134217728" id="MAX_FILE_SIZE" />
<div class="field" id="field_file">
<label for="file">File</label>
<span class="value"><input type="file" name="file" id="file" /></span>
<span class="hint">Description goes here.</span>
</div>
</dl>
</form>
A problem with this solution is that the hidden elements don't render within the viewscript; this might be a problem if you're using the div as a selector in a client-side script...
What I've realized is, a custom decorator class will handle most fields except File fields.
Make sure your class implements the interface like so:
class CC_Form_Decorator_Pattern
extends Zend_Form_Decorator_Abstract
implements Zend_Form_Decorator_Marker_File_Interface
This worked for me.
This helped me fix my problem. I adjusted the code to wrap the file element inside a table. To make it work, simply remove the label from the viewdecorator and add the file element as follows:
$form->addElement('file', 'upload_file', array(
'disableLoadDefaultDecorators' => true,
'decorators' => array(
'Label',
array(array('labelTd' => 'HtmlTag'), array('tag' => 'td', 'class' => 'labelElement')),
array(array('elemTdOpen' => 'HtmlTag'), array('tag' => 'td', 'class' => 'dataElement','openOnly' => true, 'placement' => 'append')),
'File',
array('ViewScript', array(
'viewScript' => 'decorators/file.phtml',
'placement' => false,
)),
array(array('elemTdClose' => 'HtmlTag'), array('tag' => 'td', 'closeOnly' => true, 'placement' => 'append')),
array(array('row' => 'HtmlTag'), array('tag' => 'tr'))
),
'label' => 'Upload',
'required' => false,
'filters' => array(),
'validators' => array(array('Count', false, 1), ),
));
I've found a work-around that avoids the ViewScript altogether.
First, the element definition:
$this->addElement('file', 'upload_file', array(
'disableLoadDefaultDecorators' => true,
'decorators' => array(
'File',
array(array('Value'=>'HtmlTag'), array('tag'=>'span','class'=>'value')),
'Errors',
'Description',
'Label',
array(array('Field'=>'HtmlTag'), array('tag'=>'div','class'=>'field file')),
),
'label' => 'Upload File',
'required' => false,
'filters' => array('StringTrim'),
'validators' => array(),
));
Second, after the form class has been instantiated, I mimic the behavior of my ViewScript:
$field = $form->getElement('upload_file');
$decorator = $field->getDecorator('Field');
$options = $decorator->getOptions();
$options['id'] = 'field_' . $field->getId();
if ($field->hasErrors()) {
$options['class'] .= ' errors';
}
$decorator->setOptions($options);
I guess that I should look into class-based decorators. Maybe there's more flexibility there?
The easiest thing to do is to add no markup at all to the output in your custom File Decorator:
class Custom_Form_Decorator_File extends Zend_Form_Decorator_File {
public function render($content) {
return $content;
}
}
now you can do whatever you want in your viewscript for this file element (output the file input field and all hidden fields you need on your own).
Just in case you have followed #Shaun's answer and you are still getting the error: make sure that you've disabled default decorators for the element in question (take look at line 2):
$this->addElement('file', 'upload_file', array(
'disableLoadDefaultDecorators' => true,
'decorators' => array('File', array('ViewScript', array(
'viewScript' => '_form/file.phtml',
'placement' => false,
))),
'label' => 'Upload',
'required' => false,
'filters' => array(),
'validators' => array(array('Count', false, 1),),
));