CodeIgniter autoloading form validation rules set not working with parameters - forms

Following CI user_guide, I have created a configuration file named "form_validation.php" with in it the following sets:
$config = array(
'user/create' => array(
array(
'field' => 'id',
'label' => '',
'rules' => ''
),
array(
'field' => 'first_name',
'label' => 'lang:First name',
'rules' => 'required|max_length[30]'
),...
),
'user/update' => array(
array(
'field' => 'id',
'label' => '',
'rules' => ''
),
array(
'field' => 'first_name',
'label' => 'lang:First name',
'rules' => 'required|max_length[30]'
),...
)
);
In my 'user' controller, when I call the 'create' method, hence with the URL http://localhost/my_ci_application/user/create, the statement $this->form_validation->run() automatically runs the first set of rules defined in my configuration file. This is the expected behaviour from what I read in the user guide.
But when I run the following URL http://localhost/my_ci_application/user/update/1 to update the user whose ID is 1, it does not automatically load the 'user/update' rules set. It seems like because of the parameter, CI expects to find a 'user/update/1' rules set, which of course I cannot create because the ID of my users will vary all the time when calling this method.
Am I understanding this right? If yes, then that's a pity as I thought standard CI URL were formed like: controller/method/parameters... so I would expect the form validation class to only consider the first two URI segments?!
FYI, if I write in my user.update method the following, my validation rules work fine:
$this->form_validation->run('user/update')
So my question is really if I understood the autoloading of rules properly or not, and if there is anything we can do to autoload those rules even with methods having some parameters.
thank you very much in advance.

In your form_validation.php file:
$CI =& get_instance();
$config = array(
'user/update/' . $CI->uri->segment(3) => array(
....
)
);

if i understant this question u will need call validation, for example:
$this->lang->load('form_validation', 'portuguese'); //if u have order language
if($this->form_validation->run('user/update') == FALSE)
{
//msg error
}
else{
//save
}
To get the value for the url dowel u need:
$this->uri->segment(3);
i hope this has helped

You can extend the library to achieve this
application/libraries/MY_Form_validation.php
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class MY_Form_validation extends CI_Form_validation {
function run($group = '')
{
if($group == '')
{
$group = '/' . implode('/', array_slice($this->CI->uri->rsegment_array(), 0, 2));
}
return parent::run($group);
}
}

Related

Prestashop helper form 'file' type

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

Module Forms - Store Value of addField to a Variable

I have something like in my custom module:
$fieldset->addField('orderinfo', 'link', array(
'label' => Mage::helper('web')->__('Order Info'),
'style' => "",
'href' => Mage::helper('adminhtml')->getUrl('adminhtml/sales_order/view', array('order_id' => $order_id)),
'value' => 'Magento Blog',
'after_element_html' => '',
));
And as you can see from the code, I am trying to link that field to the Order Tab in the back-end. I'm having trouble getting the ID though. I'm planning to just save the Order ID in the database, and then using the addField I could have the correct url.
But how can I save an addField value to a variable?
I want to store the value in "$order_id".
Is it possible?
I am not sure in which context you are using this fieldset but if it is used for example for creating or editing object you can try something like that:
In controller:
public function editAction()
{
$id = $this->getRequest()->getParam('id');
$model = Mage::getModel('module/model')->load($id);
Mage::register('model_name', $model);
}
and then in the block:
protected function _prepareForm()
{
$model = Mage::registry('model_name');
// add fieldset to form
$fieldset->addField('orderinfo', 'link', array(
'label' => Mage::helper('web')->__('Order Info'),
'style' => "",
'href' => Mage::helper('adminhtml')->getUrl('adminhtml/sales_order/view', array('order_id' => $model->getOrderId())),
'value' => 'Magento Blog',
'after_element_html' => '',
));
//rest of the elements
}
Answering my own post again. (src: https://magento.stackexchange.com/questions/682/module-forms-store-value-of-addfield-to-a-variable)

Zend Controller Router : Define variables to point to a different action in one controller

I'm just new with Zend and I have a little trouble with Zend Routers. I've searched about it, but nothing found...
I want to be able to define a router for each defined variable at uri level to point to a different action in one controller.
I'm working with lang and modules so I defined at bootstrap application the next initRoutes function:
protected function _initRoutes()
{
$front = Zend_Controller_Front::getInstance();
$router = $front->getRouter();
$defaultRoute = new Zend_Controller_Router_Route(
':lang/:module/:controller/:action',
array(
'lang' => 'es',
'module' => 'default',
'controller' => 'index',
'action' => 'index'
),
array(
'lang' => '^(en|es)$',
'module' => '^(default|admin)$'
)
);
$router->addRoute('defaultRoute', $defaultRoute);
return $router;
}
I want to be able to access forum sections and forum topics by their defined action.
Something like :
mydomain/forum -> forum/index
mydomain/forum/section -> forum/sectionAction
mydomain/forum/section/topic -> forum/topicAction
and also with the lang and module defined at uri level like :
mydomain/lang/module/forum
mydomain/lang/module/forum/section
mydomain/lang/module/forum/section/topic
So I have this :
class ForumController extends Zend_Controller_Action
{
public function indexAction()
{
}
public function sectionAction()
{
}
public function topicAction()
{
}
Then I created the next routes inside the Default_Bootstrap :
$forumRoutes = new Zend_Controller_Router_Route(
':lang/:module/forum',
array(
'lang' => 'es',
'module' => 'default',
'controller' => 'forum',
'action' => 'index'
)
);
$sectionRoutes = new Zend_Controller_Router_Route(
':lang/:module/forum/:section',
array(
'lang' => 'es',
'module' => 'default',
'controller' => 'forum',
'action' => 'section',
'section' => ''
)
);
$topic = new Zend_Controller_Router_Route(
':lang/:module/forum/:section/:topic',
array(
'lang' => 'es',
'module' => 'default',
'controller' => 'forum',
'action' => 'topic',
'section' => '',
'topic' => ''
)
);
$router->addRoute('forumTopics', $topic);
$router->addRoute('forumSections', $section);
$router->addRoute('forum', $forumRoutes);
Now, this only works if I define the lang and module at uri level, but doesn't work if I defined like => mydomain/forum/section | section/topic. This also brings me another problem with my navigation->menu. If I define "forum" as a static variable at router definition, when I hover over at any label defined at navigatoin.xml, the uri level have the same value for every one of them.
I've tried to make a chain like this:
$forumRoutes = new Zend_Controller_Router_Route(
':lang/:module/forum',
array(
'lang' => 'es',
'module' => 'default',
'controller' => 'forum',
'action' => 'index'
)
);
$section = new Zend_Controller_Router_Route(
':section',
array(
'action' => 'section',
'section' => ''
)
)
$topic = new Zend_Controller_Router_Route(
':topic',
array(
'action' => 'topic',
'topic' => ''
)
)
$chainedRoute = new Zend_Controller_Router_Route_Chain();
$chainedRoute->chain($topic)
->chain($section)
->chain($forumRoutes);
$router->addRoute($chainedRoute);
But this doesn't work as I expected.
Any help would be appreciated, thanks.
You are new to Zend. You said it. So here are some explanations:
Ideally the URL on Zend application is:
example.com/controller/action/param-name/:param-value
So in which case, if there is an action called Edit under UsersController, it will be:
example.com/users/edit
if action is add, it will be :
example.com/users/add
when you specify first parameter as a variable, it will collide with controller requests. Example: if you say controller is User but first parameter accepts a value and puts it in emplyees then a request as example.com/employees and example.com/user will both point towards employees controller even if the usercontroller exists! which again is a theory!
What you might want to do is, leave the routes to only accept dynamic values rather routing! You do not want users to route your application but, route user to different sections of the application.
About language then you need to use Zend_Locale which will check for HTML language that is
<html lang="nl"> or <html lang = "en">
Hope things are clear! :)
Here's a quick example which should help you work with routes like that in ZF.
If you are using a default project structure like the one you get when starting a new project using Zend Tool go into the Application folder.
In your Bootstrap.php set up something like this:
protected function _initRouteBind() {
// get the front controller and get the router
$front = Zend_Controller_Front::getInstance();
$router = $front->getRouter();
// add each custom route like this giving them a descriptive name
$router->addRoute(
'addTheDescriptiveRouteNameHere',
new Zend_Controller_Router_Route(
'/:controller/:id/:action/:somevar',
array(
'module' => 'default',
'controller' => ':controller',
'action' => ':action',
'id' => ':id',
'somevar' => ':somevar'
)
)
);
}
My example above is just to illustrate how you would use a route where the controller, the action and a couple of parameters are set in the url.
The controller and action should be resolved without any additional work however to get the 'id' or 'somevar' value you can do this in your controller:
public function yourAction()
{
// How you get the parameters to pass in to a function
$id = $this->getRequest()->getParam('id');
$somevar = $this->getRequest()->getParam('somevar');
// Using the parameters
$dataYouWant = $this->yourAmazingMethod($id);
$somethingElse = $this->yourOtherAmazingMethod($somevar);
// Assign results to the view
$this->view->data = $dataYouWant;
$this->view->something = $somethingElse;
}
So while you will want to make sure your methods handle the parameters being passed in with care (after all it is user supplied info) this is the principle behind making use of the route parameter binding. You can of course do things like '/site' as the route and have it direct to a CMS module or controller, then another for '/site/:id' where 'id' is a page identifier.
Also just to say a nice alternative to:
$id = $this->getRequest()->getParam('id');
$somevar = $this->getRequest()->getParam('somevar');
which wasn't that nice itself anyway since it was assuming a parameter was going to be passed, using shorthand conditional statement in conjunction with action helpers is:
$id = ($this->_hasParam('id')) ? $this->_getParam('id') : null;
$somevar = ($this->_hasParam('somevar')) ? $this->_getParam('somevar') : null;
If you are not familiar with this, the
($this->_hasParam('id'))
is the conditional test which if true assigns the value of whatever is on the left of the ':' and which if false assigns the value of whatever is on the right of the ':'.
So if true the value assigned would be
$this->_getParam('id')
and null if false.
Does that help? :-D

Zend: Form validation: value was not found in the haystack error

I have a form with 2 selects. Based on the value of the first select, it updates the values of the second select using AJAX. Doing this makes the form not being valid. So, I made the next change:
$form=$this->getAddTaskForm(); //the form
if(!$form->isValid($_POST)) {
$values=$form->getValues();
//get the options and put them in $options
$assignMilestone=$form->getElement('assignedMilestone');
$assignMilestone->addMultiOptions($options);
}
if($form->isValid($_POST)) {
//save in the database
}else {
//redisplay the form
}
Basically, I check if it is valid and it isn't if the user changed the value of the first select. I get the options that populated the second select and populate the form with them. Then I try to validate it again. However this doesn't work. Anybody can explain why? The same "value was not found in the haystack" is present.
You could try to deactivate the validator:
in your Form.php
$field = $this->createElement('select', 'fieldname');
$field->setLabel('Second SELECT');
$field->setRegisterInArrayValidator(false);
$this->addElement($field);
The third line will deactivate the validator and it should work.
You can also disable the InArray validator using 'disable_inarray_validator' => true:
For example:
$this->add( array(
'name' => 'progressStatus',
'type' => 'DoctrineModule\Form\Element\ObjectSelect',
'options' => array(
'disable_inarray_validator' => true,
),
));
Additionaly you should add you own InArray Validator in order to protect your db etc.
In Zend Framework 1 it looks like this:
$this->addElement('select', $name, array(
'required' => true,
'label' => 'Choose sth:',
'filters' => array('StringTrim', 'StripTags'),
'multiOptions' => $nestedArrayOptions,
'validators' => array(
array(
'InArray', true, array(
'haystack' => $flatArrayOptionsKeys,
'messages' => array(
Zend_Validate_InArray::NOT_IN_ARRAY => "Value not found"
)
)
)
)
));
Where $nestedArrayOptions is you multiOptions and $flatArrayOptionsKeys contains you all keys.
You may also add options to select element before checking for the form validation. This way you are insured the select value is in range.

How to verify password field in zend form?

In my form, I'm trying to verify that the user fills in the same value both times (to make sure they didn't make a mistake). I think that's what Zend_Validate_Identical is for, but I'm not quite sure how to use it. Here's what I've got so far:
$this->addElement('password', 'password', array(
'label' => 'Password:',
'required' => true,
'validators' => array(
'Identical' => array(What do I put here?)
)
));
$this->addElement('password', 'verifypassword', array(
'label' => 'Verify Password:',
'required' => true,
'validators' => array(
'Identical' => array(What do I put here?)
)
));
Do I need it on both elements? What do I put in the array?
For what its worth, support for comparing two identical form fields within a model was added to the 1.10.5 release. I wrote up a short tutorial on the matter, which you can access via the below link, but the bottom line is that the Zend_Validate_Identical validator has been refactored to accept a form field name as input. For instance, to compare the values of form fields pswd and confirm_pswd, you'll attach the validator to confirm_pswd like so:
$confirmPswd->addValidator('Identical', false, array('token' => 'pswd'));
Works like a charm.
See Validating Identical Passwords with the Zend Framework for a more complete example.
I can't test it at the moment, but I think this might work:
$this->addElement('password', 'password', array(
'label' => 'Password:',
'required' => true
));
$this->addElement('password', 'verifypassword', array(
'label' => 'Verify Password:',
'required' => true,
'validators' => array(
array('identical', true, array('password'))
)
));
After two days I found the right answer follow me step by step:
step 1:
create PasswordConfirmation.php file in root directory of your project with this path:
yourproject/My/Validate/PasswordConfirmation.php with this content below:
<?php
require_once 'Zend/Validate/Abstract.php';
class My_Validate_PasswordConfirmation extends Zend_Validate_Abstract
{
const NOT_MATCH = 'notMatch';
protected $_messageTemplates = array(
self::NOT_MATCH => 'Password confirmation does not match'
);
public function isValid($value, $context = null)
{
$value = (string) $value;
$this->_setValue($value);
if (is_array($context)) {
if (isset($context['user_password'])
&& ($value == $context['user_password']))
{
return true;
}
}
elseif (is_string($context) && ($value == $context)) {
return true;
}
$this->_error(self::NOT_MATCH);
return false;
}
}
?>
step 2:
Add two field in your form like this:
//create the form elements user_password
$userPassword = $this->createElement('password', 'user_password');
$userPassword->setLabel('Password: ');
$userPassword->setRequired('true');
$this->addElement($userPassword);
//create the form elements user_password repeat
$userPasswordRepeat = $this->createElement('password', 'user_password_confirm');
$userPasswordRepeat->setLabel('Password repeat: ');
$userPasswordRepeat->setRequired('true');
$userPasswordRepeat->addPrefixPath('My_Validate', 'My/Validate', 'validate');
$userPasswordRepeat->addValidator('PasswordConfirmation', true, array('user_password'));
$this->addElement($userPasswordRepeat);
now enjoy your code
class My_Validate_PasswordConfirmation extends Zend_Validate_Abstract
{
const NOT_MATCH = 'notMatch';
protected $_messageTemplates = array(
self::NOT_MATCH => 'Password confirmation does not match'
);
public function isValid($value, $context = null)
{
$value = (string) $value;
$this->_setValue($value);
if (is_array($context)) {
if (isset($context['password_confirm'])
&& ($value == $context['password_confirm']))
{
return true;
}
} elseif (is_string($context) && ($value == $context)) {
return true;
}
$this->_error(self::NOT_MATCH);
return false;
}
}
http://framework.zend.com/manual/en/zend.form.elements.html
$token = Zend_Controller_Front::getInstance()->getRequest()->getPost('password');
$confirmPassword->addValidator(new Zend_Validate_Identical(trim($token)))
->addFilter(new Zend_Filter_StringTrim())
->isRequired();
Use the above code inside the class which extends zend_form.
I was able to get it to work with the following code:
In my form I add the Identical validator on the second element only:
$this->addElement('text', 'email', array(
'label' => 'Email address:',
'required' => true,
'filters' => array('StringTrim'),
'validators' => array('EmailAddress')
));
$this->addElement('text', 'verify_email', array(
'label' => 'Verify Email:',
'required' => true,
'filters' => array('StringTrim'),
'validators' => array('EmailAddress', 'Identical')
));
And in the controller, just before calling isValid():
$validator = $form->getElement('verify_email')->getValidator('identical');
$validator->setToken($this->_request->getPost('email'));
I don't know if there is a more elegant way of doing this without having to add this code to the controller. Let me know if there is a better way to do this.
With Zend Framework 1.10 the code needed to validate the equality of two fields using Zend Form and Zend Validate is:
$form->addElement('PasswordTextBox',
'password',
array('label' => 'Password')
);
$form->addElement('PasswordTextBox',
'password_confirm',
array('label' => 'Confirm password',
'validators' => array(array('Identical', false, 'password')),
)
);
You can notice, in the validators array of the password_confirm element, that the Identical validator is passed as array, the semantics of that array is: i) Validator name, ii) break chain on failure, iii) validator options
As you can see, it's possible to pass the field name instead of retrieving the value.