I use the newest Zend Framework available, and now i want to use ReCaptcha on my form. Together with some other elements, the ReCaptcha element is defined by:
$pubKey = 'replaced by the actual pubkey';
$privKey = 'replaced by the actual privkey';
$recaptcha = new \Zend\Captcha\ReCaptcha(['pubKey' => $pubKey, 'privKey' => $privKey]);
$this->add(array(
'attributes' => array (
'data-role' => 'none',
),
'name' => 'captcha',
'type' => 'captcha',
'options' => array(
'captcha' => $recaptcha,
),
));
This code validates the form in the controller:
public function contactAction () {
$contactForm = new ContactForm();
if($this->getRequest()->isPost()) {
$contactForm->setData($this->getRequest()->getPost());
if($contactForm->isValid()){
// send actual mail
return $this->redirect()->toRoute('page', ['lang' => $this->translator->getLocale(), 'page' => 'contact']);
}
}
$viewModel = new ViewModel ([
'contactForm' => $contactForm
]);
$viewModel->setTemplate('application/index/contact');
return $viewModel;
}
And finally, this is the view:
<?= $this->form($contactForm); ?>
To me, this code is pretty straightforward and should work. However, on sending the contact form, it displays the error 'Captcha value is wrong'. Any ideas?
You have to name the element according to the rules of Google. With this code, it works like a breeze
$pubKey = 'replaced by the actual pubkey';
$privKey = 'replaced by the actual privkey';
$recaptcha = new \Zend\Captcha\ReCaptcha(['pubKey' => $pubKey, 'privKey' => $privKey]);
$this->add(array(
'name' => 'g-recaptcha-response',
'type' => 'captcha',
'options' => [
'captcha' => $recaptcha,
]
));
Anyways, as always the ZF Docs are very short and lack examples.
Related
Whenever I submit the form I get this message:
The input was not found in the haystack.
This is for the shipping-method element (radio button). Can't figure out what it means, the POST data for that element is not null.
public function getInputFilter()
{
if (!$this->inputFilter) {
$inputFilter = new InputFilter();
// Some other basic filters
$inputFilter->add(array(
'name' => 'shipping-method',
'required' => true,
'filters' => array(
array('name' => 'StripTags'),
array('name' => 'StringTrim')
),
'validators' => array(
array(
'name' => 'StringLength',
'options' => array(
'encoding' => 'UTF-8',
'max' => 20,
),
),
array(
'name' => 'Db\RecordExists',
'options' => array(
'table' => 'shipping',
'field' => 'shipping_method',
'adapter' => $this->dbAdapter
)
),
),
));
$inputFilter->get('shipping-address-2')->setRequired(false);
$inputFilter->get('shipping-address-3')->setRequired(false);
$this->inputFilter = $inputFilter;
}
return $this->inputFilter;
}
I only keep finding solutions for <select>.
Here's the sample POST data:
object(Zend\Stdlib\Parameters)#143 (1) {
["storage":"ArrayObject":private] => array(9) {
["shipping-name"] => string(4) "TEST"
["shipping-address-1"] => string(4) "test"
["shipping-address-2"] => string(0) ""
["shipping-address-3"] => string(0) ""
["shipping-city"] => string(4) "TEST"
["shipping-state"] => string(4) "TEST"
["shipping-country"] => string(4) "TEST"
["shipping-method"] => string(6) "Ground"
["submit-cart-shipping"] => string(0) ""
}
}
UPDATE:
form.phtml
<div class="form-group">
<?= $this->formRow($form->get('shipping-method')); ?>
<?= $this->formRadio($form->get('shipping-method')
->setValueOptions(array(
'Ground' => 'Ground',
'Expedited' => 'Expedited'))
->setDisableInArrayValidator(true)); ?>
</div>
ShippingForm.php
$this->add(array(
'name' => 'shipping-method',
'type' => 'Zend\Form\Element\Radio',
'options' => array(
'label' => 'Shipping Method',
'label_attributes' => array(
'class' => 'lbl-shipping-method'
),
)
));
The problem lies with when you use the setValueOptions() and the setDisableInArrayValidator(). You should do this earlier within your code as it is never set before validating your form and so the inputfilter still contain the defaults as the InArray validator. As after validation, which checks the inputfilter, you set different options for the shipping_methods.
You should move the setValueOptions() and the setDisableInArrayValidator() before the $form->isValid(). Either by setting the right options within the form itsself or doing this in the controller. Best way is to keep all of the options in one place and doing it inside the form class.
$this->add([
'name' => 'shipping-method',
'type' => 'Zend\Form\Element\Radio',
'options' => [
'value_options' => [
'Ground' => 'Ground',
'Expedited' => 'Expedited'
],
'disable_inarray_validator' => true,
'label' => 'Shipping Method',
'label_attributes' => [
'class' => 'lbl-shipping-method',
],
],
]);
Another small detail you might want to change is setting the value options. They are now hardcoded but your inputfilter is checking against database records whether they exist or not. Populate the value options with the database records. If the code still contains old methods but the database has a few new ones, they are not in sync.
class ShippingForm extends Form
{
private $dbAdapter;
public function __construct(AdapterInterface $dbAdapter, $name = 'shipping-form', $options = [])
{
parent::__construct($name, $options)
// inject the databaseAdapter into your form
$this->dbAdapter = $dbAdapter;
}
public function init()
{
// adding form elements to the form
// we use the init method to add form elements as from this point
// we also have access to custom form elements which the constructor doesn't
$this->add([
'name' => 'shipping-method',
'type' => 'Zend\Form\Element\Radio',
'options' => [
'value_options' => $this->getDbValueOptions(),
'disable_inarray_validator' => true,
'label' => 'Shipping Method',
'label_attributes' => [
'class' => 'lbl-shipping-method',
],
],
]);
}
private function getDbValueOptions()
{
$statement = $this->dbAdapter->query('SELECT shipping_method FROM shipping');
$rows = $statement->execute();
$valueOptions = [];
foreach ($rows as $row) {
$valueOptions[$row['shipping_method']] = $row['shipping_method'];
}
return $valueOptions;
}
}
Just had this happen yesterday.
The select and multi select ZF2+ elements have a built in in_array validator.
Remember filters occur before validators.
You may be doing too much here -- it is very rare to need to filter or add validators ot select and multi select form elements in ZF2 forms. The built in element validator is robust, ZF does a lot of work for us.
Try removing both filter and validator for the element, such as:
$inputFilter->add(array(
'name' => 'shipping-method',
'required' => true,
));
There is another edge case that I have seen: changing the select element's valueOptions somewhere in the controller (or view) resulting in different valueOptions used in view vs form validation (in our case it was replacing the element with a new one before validation).
I think your problem lies in the fact you are adding your value options after the InArray validator has been set, hence the validator has no haystack.
Try this
$this->add(array(
'name' => 'shipping-method',
'type' => 'Zend\Form\Element\Radio',
'options' => array(
'label' => 'Shipping Method',
'label_attributes' => array(
'class' => 'lbl-shipping-method'
),
'value_options' => array(
'Ground' => 'Ground',
'Expedited' => 'Expedited'
),
'disable_inarray_validator' => TRUE,
)
));
and remove setValueOptions and setDisableInArrayValidator from your view.
Hope this works.
I am migrating an application from Zend 1 to Zend 2 and starting to desperate with one issue. The application works with different locales and therefore, I need to store the data in a normalized way in the database. In Zend 1 I used this code:
public function normalizeNumber( $value )
{
// get the locale to change the date format
$this->_locale = Zend_Registry::get('Zend_Locale' );
return Zend_Locale_Format::getNumber($value, array('precision' => 2, 'locale' => $this->_locale));
}
Unfortunately Zend 2 does not has this Zend_Locale_Format::getNumber any more and I was not able to figure out what function did replace it. I have tried with NumberFormat, but I get only localized data not normalized. I need this function to normalize data I receive from a form via POST. Can someone give some advice?
thanks
Just to complete my question. The Form element definition I am using is the following:
namespace Profile\Form;
use Zend\Form\Form;
use Zend\InputFilter\InputFilterProviderInterface;
class Profile Extends Form implements InputFilterProviderInterface
{
protected $model;
public function __construct( $model, $name = 'assignmentprofile')
{
parent::__construct( $name );
$this->setAttribute( 'method', 'post');
$this->model = $model;
...
$this->add( array(
'name' =>'CommutingRate',
'type' =>'Zend\Form\Element\Text',
'options' => array( // list of options to add to the element
'label' => 'Commuting rate to be charged:',
'pattern' => '/[0-9.,]/',
),
'attributes' => array( // Attributes to be passed to the HTML lement
'type' =>'text',
'required' => 'required',
'placeholder' => '',
),
));
}
public function getInputFilterSpecification()
{
return array(
...
'CommutingRate' => array(
'required' => true,
'filters' => array(
array( 'name' => 'StripTags', ),
array( 'name' => 'StringTrim'),
array( 'name' => 'NumberFormat', 'options' => array('locale' => 'en_US', 'style' => 'NumberFormatter::DECIMAL', 'type' => 'NumberFormatter::TYPE_DOUBLE',
))
),
'validators' => array(
array( 'name' => 'Float',
'options' => array( 'messages' => array('notFloat' => 'A valid numeric entry is required')),
),
),),
...
);
}
}
As mentioned before, I am able to localized the data and validate it in the localized manner, but i am failing to convert it back to a normalized manner...
I m working on prestasshop and I created a helper form inside a controller (for back office). My question is how to upload a document by using the type:'file' from the helper form. Here is the code:
public function __construct()
{
$this->context = Context::getContext();
$this->table = 'games';
$this->className = 'Games';
$this->lang = true;
$this->addRowAction('edit');
$this->addRowAction('delete');
$this->bulk_actions = array('delete' => array('text' => $this->l('Delete selected'),
'confirm' => $this->l('Delete selected items?')));
$this->multishop_context = Shop::CONTEXT_ALL;
$this->fieldImageSettings = array(
'name' => 'image',
'dir' => 'games'
);
$this->fields_list = array(
'id_game' => array(
'title' => $this->l('ID'),
'width' => 25
)
);
$this->identifier = 'id_game';
parent::__construct();
}
public function renderForm()
{
if (!($obj = $this->loadObject(true)))
return;
$games_list = Activity::getGamesList();
$this->fields_form = array(
'tinymce' => true,
'legend' => array(
'title' => $this->l('Game'),
'image' => '../img/admin/tab-payment.gif'
),
'input' => array(
array(
'type' => 'select',
'label' => $this->l('Game:'),
'desc' => $this->l('Choose a Game'),
'name' => 'id_games',
'required' => true,
'options' => array(
'query' => $games_list,
'id' => 'id_game',
'name' => 'name'
)
),
array(
'type' => 'text',
'label' => $this->l('Game Title:'),
'name' => 'name',
'size' => 64,
'required' => true,
'lang' => true,
'hint' => $this->l('Invalid characters:').' <>;=#{}'
),
array(
'type' => 'file',
'label' => $this->l('Photo:'),
'name' => 'uploadedfile',
'id' => 'uploadedfile',
'display_image' => false,
'required' => false,
'desc' => $this->l('Upload your document')
)
)
);
$this->fields_form['submit'] = array(
'title' => $this->l(' Save '),
'class' => 'button'
);
return AdminController::renderForm();
}
Now how can I upload the document?
Do I have to create a column in the table of the db (games table) for storing the file or something related?
Thanks in advance
I assume this AdminController for your model. Now a model obviously can't hold a file in table column. What you can do is hold path to the uploaded file. That's what you can save.
You should look in AdminController class (which you extended). When you submit a form, one of two method are executed:
processAdd()
processUpdate()
Now investigate the flow logic in these methods. Other methods are called from within this methods, such as:
$this->beforeAdd($this->object); -> calls $this->_childValidation();
$this->validateRules();
$this->afterUpdate($object);
As you can see, there these are the methods where you can do you custom stuff. If you look up these functions in AdminController class, the're empty. They are purposely added so people can override them and put their custom logic there.
So, using these functions, you can validate your uploaded file fields (even though it isnt in the model itself), if it validates you can then assign path to the object; and then in beforeAdd method you can actually move the uploaded file to the desired location (because both child validation and default validation has passed).
The way I've done it:
protected function _childValidation()
{
// Check upload errors, file type, writing permissions
// Use $this->errors['file'] if there is an error;
protected function beforeAdd($object)
{
// create filename and filepath
// assign these fields to object;
protected function afterAdd($object)
{
// move the file
If you allow the file field to be updated, you'll need to to these steps for Update methods as well.
you can get uploaded file using $_FILES['uploadedfile'] in both the functions processAdd() and processUpdate(), you can check all the conditions there and before calling $this->object->save(); to save the form data you can write the code to upload the file in the desired location like
move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target_path)
since you can't save the file in database you need to save only the name of the file or location on the database
Hope that helps
I have a form in Zend Framework 1. when I click on edit button I want to display values from databases in the form. but I don't know how to do it.
This is my form code:
// Add an email element
$this->addElement('text', 'orgname', array(
'required' => true,
'filters' => array('StringTrim'),
'style' => array('width:220px'),
'decorators'=>Array(
'ViewHelper','Errors'
)
));
This is my controller:
public function editclientcompanyAction()
$form = new Application_Form_Companyform();
$form->addform();
$this->view->form = $form;
$request = $this->getRequest();
$editid=$request->getParam('id');
$edit_show = new Application_Model_Clientcompany;
$showdetails = $edit_show->editclient($editid);
$this->view->assign('datas', $showdetails);
How do I display database vlaues in my Zend Form?
There are two cases.
1) Populating form which has fields same like the database table fields : If you have the form which has same fields like the database fields, then you can populate them easily.
First you need to get the data from the database and then call the Zend_Form populate function passing the data as an associative array, where keys will be same like form fields names and values will be values for the form fields, as below in case of your form.
This will be in your controller
$data = array("orgname" => "Value for the field");
$form = new Application_Form_Companyform();
$form->populate($data);
Now send will automatically populate the form field orgname. You dont need to modify your form or set the value field in the addElement.
*2)Setting field value manually: * The second case is to set the value manually. First you will need to modify your form and add a constructor to it. Also in your form class you will need to create a property (if you have multiple fields, then you can create an array property or multiple properties for each field. This will be all up to you.). And then set the value key in the addElement. Your form should look like this
class Application_Form_Companyform extends Zend_Form
{
private $orgname;
public function __contruct($orgname)
{
$this->orgname = $orgname;
//It is required to call the parent contructor, else the form will not work
parent::__contruct();
}
public function init()
{
$this->addElement('text', 'orgname',
array(
'required' => true,
'filters' => array('StringTrim'),
'style' => array('width:220px'),
'decorators'=>Array('ViewHelper','Errors'),
'value'=>$this->orgname
)
));
} //end of init
} //end of form
Now your controller, you will need to instantiate the form object passing the value of the orgname field like below
$form = new Application_Form_Companyform("This is the value for orgname");
And thats it.
I used such methods and it works like a charm. For your requirements, you may need to adjust the above sample code, as i did not checked it, but it will run fine for sure i hope :P
Thank you
Ok in either ZF1 or ZF2 just do this.
// Add an email element
$this->addElement('text', 'orgname',
array(
'required' => true,
'filters' => array('StringTrim'),
'style' => array('width:220px'),
'decorators' => Array('ViewHelper','Errors'),
'value' => $showdetails->orgname
)
));
You might want to test first for null/empty values first though, you could use ternary operators for convenience:
// Add an email element
$this->addElement('text', 'orgname',
array(
'required' => true,
'filters' => array('StringTrim'),
'style' => array('width:220px'),
'decorators' => Array('ViewHelper','Errors'),
'value' => empty($showdetails->orgname)? null : $showdetails->orgname
)
));
Please have a look in my edit function at /var/www/html/zend1app/application/controllers/CountryController.php :
public function editAction() {
$data = $this->getRequest()->getParams();
$id = (int)$data['id'];
$options = array();
$country = $this->getCountryModel()->fetchRow("id=$id");
if(!$country)
{
throw new Exception("Invalid Request Id!");
}
$form = new Application_Form_Country();
$form->addIdElement();
if ($this->getRequest()->isPost()) {
if ($form->isValid($this->getRequest()->getPost())){
$data = new Application_Model_Country();
if($data->save($form->getValues()))
{
$message = array("sucess" => "Country has been updated!");
}
else {
$message = array("danger" => "Country could not be updated!");
}
$this->_helper->FlashMessenger->addMessage($message);
return $this->_helper->redirector('index');
}
}
$options = array (
'id' => $country->id,
'name' => $country->name,
'code' => $country->code
);
$form->populate( $options ); // data binding in the edit form
$this->view->form = $form;
}
and form class at /var/www/html/zend1app/application/forms/Country.php :
class Application_Form_Country extends Zend_Form
{
public function init()
{
// Set the method for the display form to POST
$this->setMethod('post');
// Add an email element
$this->addElement('text', 'name', array(
'label' => 'Enter Country Name:',
'required' => true,
'filters' => array('StringTrim'),
'validators' => array(
array('validator' => 'StringLength', 'options' => array(0, 20))
)
));
// Add the comment element
$this->addElement('text', 'code', array(
'label' => 'Enter Country Code:',
'required' => true,
'validators' => array(
array('validator' => 'StringLength', 'options' => array(0, 20))
)
));
// Add the submit button
$this->addElement('submit', 'submit', array(
'ignore' => true,
'label' => 'Save',
));
// And finally add some CSRF protection
$this->addElement('hash', 'csrf', array(
'ignore' => true,
));
}
public function addIdElement()
{
$this->addElement('hidden', 'id');
}
}
HTH
I'm trying to create a login form for my web application.
Form validation errros are not showing even though I'm using the $validate Array.
user.php
public $validate = array(
'email' => array(
'notEmpty' => array(
'rule' => 'notEmpty',
'message' => 'notEmpty',
'required' => true
),
'isEmail' => array(
'rule' => 'email'
),
'isUnique' => array(
'rule' => 'isUnique'
)
),
'password' => array(
'notEmpty' => array(
'rule' => 'notEmpty'
),
'minLength' => array(
'rule' => array('minLength', 8)
)
)
);
I can't see an error in my user model, so I show you my controller and my view.
users_controller.php
class UsersController extends AppController {
public $name = 'Users';
public $helpers = array(
'Form'
);
public function login() {
if(!empty($this->data)) {
if ($this->Auth->user() != null) {
$this->Session->setFlash('You are now logged in.', 'flash/success');
$this->redirect('/');
} else {
$this->Session->setFlash('You could not get logged in. Please see errors below.', 'flash/error');
}
}
}
login.ctp
echo $this->Form->create('User', array('action' => 'login'));
echo $this->Form->input('User.email', array(
'label' => __('email address:', true),
'error' => array(
'notEmpty' => __('Email address must not be blank.', true),
'isEmail' => __('Email address must be valid.', true),
)
));
echo $this->Form->input('User.password', array('label' => __('password:', true)));
echo $this->Form->end('Log in');
I hope you can help me. I can't find my mistake since hours. Is there maybe a component or an helper which I need to include?
put echo $this->Session->flash('auth'); before form->create. You don't have to validate login form, Auth will take care of that for you. Read the cookbook: http://book.cakephp.org/view/1250/Authentication
Since you are using Auth, the minLength validation for password is useless.
Validation doesn't occur automatically unless you're saving into the database. Change the first line of the login method in the controller to
if( !empty( $this->data ) && $this->User->validates() ) {
...