I'm just wondering if there is way to run a validation function from your rules method where you don't need to pass in any parameters to it?
So normally you would pass in the attribute name for the property, but say you know what properties you want to use such as $this->foo and $this->bar.
So a normal custom inline validator would be done like this:
['country', 'validateCountry']
public function validateCountry($attribute, $params)
{
if (!in_array($this->$attribute, ['USA', 'Web'])) {
$this->addError($attribute, 'The country must be either "USA" or "Web".');
}
}
Like I'm currently doing this:
['username', 'regAvailable', 'params' => ['email' => 'email']],
public function regAvailable($attribute, $params) {
$username = $this->{$attribute};
$email = $this->{$params['email']};
}
Sure, it does the job. But seems a bit overkill when I can just do:
public function regAvailable($attribute, $params) {
$username = $this->username;
$email = $this->email;
}
Sure, I can still do it this way, but then I kinda feel like the code wouldn't be very "clean" by having those unused parameters there; I would prefer to have it like this:
public function regAvailable() {
$username = $this->username;
$email = $this->email;
}
Is there anyway do do something like that? If so, how?
Of course you can do that. You can avoid passing any argument to custom validation method. For example:
public function regAvailable() {
if(!$this->hasErrors()){
if(strlen($this->email) < 10 && $this->email!='info#site.com' && $this->username!='admin'){
$this->addError('email','Invalid email!');
$this->addError('username','username must not be admin');
}
}
}
But, please note that, using those argument would be useful if you need to perform some validation for multiple fields. Assume that we have 9 fields that we need to validate theme like above function. So, it is better to use $attribute argument as it refers to the field which is under validation progress.
Related
I have situation where codeigniter shows database Error Number 1048. It seems Values NULL but when I try to check it usign var_dump($_POST) Values are not NULL.
Controller : Jurusan.php
public function simpan()
{
$this->form_validation->set_rules('code','Kode','required|integer');
$this->form_validation->set_rules('jurusan','Jurusan','required');
$this->form_validation->set_rules('singkatan','Singkatan','required');
$this->form_validation->set_rules('ketua','Ketua','required');
$this->form_validation->set_rules('nik','NIK','required|integer');
$this->form_validation->set_rules('akreditasi','Akreditasi','required');
if($this->form_validation->run() == FALSE)
{
$isi['content'] = 'jurusan/form_tambahjurusan';
$isi['judul'] = 'Master';
$isi['sub_judul'] = 'Tambah Jurusan';
$this->load->view('tampilan_home',$isi);
} else {
$this->model_security->getSecurity();
$key = $this->input->post('code');
$data['kd_prodi'] = $this->input->post['code'];
$data['prodi'] = $this->input->post['jurusan'];
$data['singkat'] = $this->input->post['singkatan'];
$data['ketua_prodi'] = $this->input->post['ketua'];
$data['nik'] = $this->input->post['nik'];
$data['akreditasi'] = $this->input->post['akreditasi'];
$this->load->model('model_jurusan');
$query = $this->model_jurusan->getdata($key);
if($query->num_rows()>0)
{
$this->model_jurusan->getupdate($key,$data);
} else {
$this->model_jurusan->getinsert($data);
}
redirect('jurusan');
}
}
Model : model_jurusan.php
class Model_jurusan extends CI_model {
public function getdata($key)
{
$this->db->where('kd_prodi',$key);
$hasil = $this->db->get('prodi');
return $hasil;
}
public function getupdate($key,$data)
{
$this->db->where('kd_prodi',$key);
$this->db->update('prodi',$data);
}
public function getinsert($data)
{
$this->db->insert('prodi',$data);
}
}
Here is the error shown :
Here is the database structure :
You have a wrong syntax in these lines:
$key = $this->input->post('code');
$data['kd_prodi'] = $this->input->post['code']; // <-- use ('code')
$data['prodi'] = $this->input->post['jurusan']; // <-- use ('jurusan')
Change this to
$this->input->post['array_key'];
this
$this->input->post('array_key');
Read : Input Class in Codeigniter
Well the problem lies in your way of accepting input parameters.
$this->input->post
is a method which accepts the variable name, not an array. So all the input parameters need to be passed as a function parameter to post method. These lines need to be altered to.
$data['kd_prodi'] = $this->input->post('code');
$data['prodi'] = $this->input->post('jurusan');
$data['singkat'] = $this->input->post('singkatan');
$data['ketua_prodi'] = $this->input->post('ketua');
$data['nik'] = $this->input->post('nik');
$data['akreditasi'] = $this->input->post('akreditasi');
Hope this solves the problem.
EDIT:
You did a var_dump($_POST) which works as it is supposed to and it will read the values of the post parameters. So either you fetch the parameters from $_POST array, or you use the $this->input->post() method. But I would suggest using the $this->input->post() method as it provides additional sanitization such as xss attack handling etc, which could be turned on an off from the config.
i have tried your code...it works. I think there some mistakes in your <input> tags, You must use <input name=""> not <input id=""> or something else. Hope it can help you out
You are try to get value from post is wrong. You should use at this way
$_POST['array value'];
I've read through the tutorials/reference of the Form-Component in Zend-Framework 2 and maybe I missed it somehow, so I'm asking here.
I've got an object called Node and bound it to a form. I'm using the Zend\Stdlib\Hydrator\ArraySerializable-Standard-Hydrator. So my Node-object has got the two methods of exchangeArray() and getArrayCopy() like this:
class Node
{
public function exchangeArray($data)
{
// Standard-Felder
$this->node_id = (isset($data['node_id'])) ? $data['node_id'] : null;
$this->node_name = (isset($data['node_name'])) ? $data['node_name'] : null;
$this->node_body = (isset($data['node_body'])) ? $data['node_body'] : null;
$this->node_date = (isset($data['node_date'])) ? $data['node_date'] : null;
$this->node_image = (isset($data['node_image'])) ? $data['node_image'] : null;
$this->node_public = (isset($data['node_public'])) ? $data['node_public'] : null;
$this->node_type = (isset($data['node_type'])) ? $data['node_type']:null;
$this->node_route = (isset($data['node_route'])) ? $data['node_route']:null;
}
public function getArrayCopy()
{
return get_object_vars($this);
}
}
In my Controller I've got an editAction(). There I want to modify the values of this Node-object. So I am using the bind-method of my form. My form has only fields to modify the node_name and the node_body-property. After validating the form and dumping the Node-object after submission of the form the node_name and node_body-properties now contain the values from the submitted form. However all other fields are empty now, even if they contained initial values before.
class AdminController extends AbstractActionController
{
public function editAction()
{
// ... more stuff here (getting Node, etc)
// Get Form
$form = $this->_getForm(); // return a \Zend\Form instance
$form->bind($node); // This is the Node-Object; It contains values for every property
if(true === $this->request->isPost())
{
$data = $this->request->getPost();
$form->setData($data);
// Check if form is valid
if(true === $form->isValid())
{
// Dumping here....
// Here the Node-object only contains values for node_name and node_body all other properties are empty
echo'<pre>';print_r($node);echo'</pre>';exit;
}
}
// View
return array(
'form' => $form,
'node' => $node,
'nodetype' => $nodetype
);
}
}
I want to only overwrite the values which are coming from the form (node_name and node_body) not the other ones. They should remain untouched.
I think a possible solution would be to give the other properties as hidden fields into the form, however I don't wanna do this.
Is there any possibility to not overwrite values which are not present within the form?
I rechecked the code of \Zend\Form and I gotta be honest I just guessed how I can fix my issue.
The only thing I changed is the Hydrator. It seems that the Zend\Stdlib\Hydrator\ArraySerializable is not intended for my case. Since my Node-Object is an object and not an Array I checked the other available hydrators. I've found the Zend\Stdlib\Hydrator\ObjectProperty-hydrator. It works perfectly. Only fields which are available within the form are populated within the bound object. This is exactly what I need. It seems like the ArraySerializable-hydrator resets the object-properties, because it calls the exchangeArray-method of the bound object (Node). And in this method I'm setting the non-given fields to null (see code in my question). Another way would propably be to change the exchangeArray-method, so that it only sets values if they are not available yet.
So the solution in the code is simple:
$form = $this->_getForm();
$form->setHydrator(new \Zend\Stdlib\Hydrator\ObjectProperty()); // Change default hydrator
There is a bug in the class form.php, the filters are not initialized in the bindvalues method just add the line $filter->setData($this->data);
it should look like this after including the line
public function bindValues(array $values = array())
{
if (!is_object($this->object)) {
return;
}
if (!$this->hasValidated() && !empty($values)) {
$this->setData($values);
if (!$this->isValid()) {
return;
}
} elseif (!$this->isValid) {
return;
}
$filter = $this->getInputFilter();
$filter->setData($this->data); //added to fix binding empty data
switch ($this->bindAs) {
case FormInterface::VALUES_RAW:
$data = $filter->getRawValues();
break;
case FormInterface::VALUES_NORMALIZED:
default:
$data = $filter->getValues();
break;
}
$data = $this->prepareBindData($data, $this->data);
// If there is a base fieldset, only hydrate beginning from the base fieldset
if ($this->baseFieldset !== null) {
$data = $data[$this->baseFieldset->getName()];
$this->object = $this->baseFieldset->bindValues($data);
} else {
$this->object = parent::bindValues($data);
}
}
to be precious it is line no 282 in my zf2.0.6 library
this would fix your problem, this happen only for binded object situation
I ran into the same problem, but the solution of Raj is not the right way. This is not a bug as for today the code remains still similar without the 'fix' of Raj, adding the line:
$filter->setData($this->data);
The main problem here is when you bind an object to the form, the inputfilter is not stored inside the Form object. But called every time from the binded object.
public function getInputFilter()
...
$this->object->getInputFilter();
...
}
My problem was that I created every time a new InputFilter object when the function getInputFilter was called. So I corrected this to be something like below:
protected $filter;
...
public function getInputFilter {
if (!isset($this->filter)) {
$this->filter = new InputFilter();
...
}
return $this->filter;
}
I ran into the same issue today but the fix Raj suggested did not work. I am using the latest version of ZF2 (as of this writing) so I am not totally surprised that it didn't work.
Changing to another Hydrator was not possible as my properties are held in an array. Both the ObjectProperty and ClassMethods hydrators rely on your properties actually being declared (ObjectProperty uses object_get_vars and ClassMethods uses property_exists). I didn't want to create my own Hydrator (lazy!).
Instead I stuck with the ArraySerializable hydrator and altered my exchangeArray() method slightly.
Originally I had:
public function exchangeArray(array $data)
{
$newData = [];
foreach($data as $property=>$value)
{
if($this->has($property))
{
$newData[$property] = $value;
}
}
$this->data = $newData;
}
This works fine most of the time, but as you can see it blows away any existing data in $this->data.
I tweaked it as follows:
public function exchangeArray(array $data)
{
$newData = [];
foreach($data as $property=>$value)
{
if($this->has($property))
{
$newData[$property] = $value;
}
}
//$this->data = $newData; I changed this line...
//to...
$this->data = array_merge($this->data, $newData);
}
This preserves any existing keys in $this->data if they are missing from the new data coming in. The only downside to this approach is I can no longer use exchangeArray() to overwrite everything held in $this->data. In my project this approach is a one-off so it is not a big problem. Besides, a new replaceAllData() or overwrite() method is probably preferred in any case, if for no other reason than being obvious what it does.
Lets see the action (form is based on model)
$this->form->bind ($request->getParameter('task'));
if ($this->form->isValid())
{
// cakk
}
This all works good, its not valid when its really not valid etc.
But I want to edit some fields, for example a date must be always set to now. Or a password must be encoded. How can I do this?
You can override the doSave() method in the form .. something like this :
public function doSave($con = null)
{
$this->values['form field'] = 'newvalue';
parent::doSave($con);
}
$this->values is an array containing the values on the form.
Update
You could use a post validator .. like this (again in the form class) :
$this->validatorSchema->setPostValidator(
new sfValidatorCallback(array('callback' => array($this, 'methodName')))
);
public function methodName($validator, $values)
{
// check / change what you need to
$values['fieldname'] = 'new value';
// return values
return $values;
}
Im carrying out some form validation with codeigniter using a custom validation callback.
$this->form_validation->set_rules('testPost', 'test', 'callback_myTest');
The callback runs in a model and works as expected if the return value is TRUE or FALSE. However the docs also say you can return a string of your choice.
For example if I have a date which is validated, but then in the same function the format of the date is changed how would I return and retrieve this new formatted value back in my controller?
Thanks for reading and appreiate the help.
I'm not entirely sure I got what you were asking, but here's an attempt.
You could define a function within the constructor that serves as the callback, and from within that function use your model. Something like this:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Controllername extends CI_Controller {
private $processedValue;
public function index()
{
$this->form_validation->set_rules('testpost','test','callback');
if ($this->form_validation->run()) {
//validation successful
echo $this->processedValue; //outputs the value returned by the model
} else {
//validation failed
}
}
private function callback($input)
{
$this->load->model('yourmodel');
$return = $this->yourmodel->doStuff($input);
//now you have the user's input in $input
// and the returned value in $return
//do some checks and return true/false
$this->processedValue = $return;
}
}
public function myTest($data){ // as the callback made by "callback_myTest"
// Do your stuff here
if(condition failed)
{
$this->form_validation->set_message('myTest', "Your string message");
return false;
}
else
{
return true;
}
}
Please try this one.
I looked at function _execute in file Form_validation of codeigniter. It sets var $_field_data to the result of callback gets(If the result is not boolean). There is another function "set_value". Use it with the parameter which is name of your field e.g. set_value('testPost') and see if you can get the result.
The way Tank_Auth does this in a controller is like so
$this->form_validation->set_rules('login', 'Login', 'trim|required|xss_clean');
if ($this->form_validation->run()) {
// validation ok
$this->form_validation->set_value('login')
}
Using the set_value method of form_validation is undocumented however I believe this is how they get the processed value of login after it has been trimmed and cleaned.
I don't really like the idea of having to setup a new variable to store this value directly from the custom validation function.
edit: sorry, misunderstood the question. Use a custom callback, perhaps. Or use the php $_POST collection (skipping codeigniter)...apologies haven't tested, but I hope someone can build on this...
eg:
function _is_startdate_first($str)
{
$str= do something to $str;
or
$_POST['myinput'} = do something to $str;
}
================
This is how I rename my custom callbacks:
$this->form_validation->set_message('_is_startdate_first', 'The start date must be first');
.....
Separately, here's the callback function:
function _is_startdate_first($str)
{
$startdate = new DateTime($this->input->post('startdate'), new DateTimeZone($this->tank_auth->timezone()));
$enddate = new DateTime($this->input->post('enddate'), new DateTimeZone($this->tank_auth->timezone()));
if ($startdate>$enddate) {
return false;
} else {
return true;
}
}
i am newbie in CodeIgniter...and i am trying to do form validation for array input...
the array name is pages[].
and i wrote:
$this->form_validation->set_rules('pages[]','','required');
if i use that:
$this->form_validation->set_message('required', 'you not selected pages.');
it will not change the other "required" validation input params?
So how can i set error message only for one validation?
This is my custom Form_Validation class. you can use it if you want to. put this file under your libraries directory. then you can use the set message like this:
$this->form_validation->setError(YOUR_INPUT_NAME, THE_MESSAGE);
ex: $this->form_validation->setError('email', 'Invalid email');
--
class MY_Form_validation extends CI_Form_validation {
public function set_error($field, $pesan_error){
$this->_field_data[$field]['error'] = $pesan_error;
}
public function get_error($field){
return $this->_field_data[$field]["error"];
}
public function get_all_error(){
// return $this->_field_data[$field]["error"];
$fields = $this->_field_data;
$pesan = "";
foreach($fields as $field ) {
if($field["error"]) {
$pesan .= "<p>$field[error]</p>";
}
}
return $pesan;
}
}
It doesn't work like you stated, you should read this section of the user guide more carefully.
I'm not sure I can explain better, but the first field of the set_message method doesn't refer to the type of validation but to the callback function's name, that's the function which is doing the custom validation work.
What you need to do is define your callback function (the guide has a good example), in which you iterate through your array's elements and count what's checked. If at the end of the iteration the counter is 0 you set your error message.
Hope this helps.