I have form, created by ActiveForm widget. User enters polish postal code there. In appropriate controller I put entered data in DB, for example:
$company_profile_data->postal_code = $_POST['CompanyProfiles']['postal_code'];
$company_profile_data->update();
I decided to use standalone validator for postal code validation. Rules for this attribute in model:
public function rules() {
return [
//...some other rules...
['postal_code', 'string', 'length' => [6,6]],
['postal_code', PostalValidator::className()], //standalone validator
];
}
app/components/validators/PostalValidator class code:
namespace app\components\validators;
use yii\validators\Validator;
use app\models\CompanyProfiles;
use app\models\Users;
class PostalValidator extends Validator {
public function init() {
parent::init();
}
public function validateAttribute($model, $attribute) {
if (!preg_match('/^[0-9]{2}-[0-9]{3}$/', $model->$attribute))
$model->addError($attribute, 'Wrong postal code format.');
}
public function clientValidateAttribute($model, $attribute, $view) { //want js-validation too
$message = 'Invalid status input.';
return <<<JS
if (!/^[0-9]{2}-[0-9]{3}$/.test("{$model->$attribute}")) {
messages.push("$message");
}
JS;
}
}
So, an example of correct code is 00-202.
When I (in user role) enter incorrect value, page reloads and I see Wrong postal code format. message, although I redefined clientValidateAttribute method and wrote JS-validation, which, as I suggested, will not allow page to reload. Then I press submit button again: this time page doesn't reload and I see Invalid status input. message (so, the second press time JS triggers). But I when enter correct code after that, I still see Invalid status input. message and nothing happens.
So, what's wrong with my clientValidateAttribute() method? validateAttribute() works great.
UPDATE
Snippet from controller
public function actionProfile(){ //can't use massive assignment here, cause info from 2 (not 1) user models is needed
if (\Yii::$app->user->isGuest) {
return $this->redirect('/site/index/');
}
$is_user_admin = Users::findOne(['is_admin' => 1]);
if ($is_user_admin->id == \Yii::$app->user->id)
return $this->redirect('/admin/login/');
$is_user_blocked = Users::find()->where(['is_blocked' => 1, 'id' => \Yii::$app->user->id])->one();
if($is_user_blocked)
return $this->actionLogout();
//3 model instances to retrieve data from users && company_profiles && logo
$user_data = Users::find()->where(['id'=>\Yii::$app->user->id])->one();
$user_data->scenario = 'update';
$company_profile_data = CompanyProfiles::find()->where(['user_id'=>Yii::$app->user->id])->one();
$logo = LogoData::findOne(['user_id' => \Yii::$app->user->id]);
$logo_name = $logo->logo_name; //will be NULL, if user have never uploaded logo. In this case placeholder will be used
$upload_logo = new UploadLogo();
if (Yii::$app->request->isPost) {
$upload_logo->imageFile = UploadedFile::getInstance($upload_logo, 'imageFile');
if ($upload_logo->imageFile) { //1st part ($logo_data->imageFile) - whether user have uploaded logo
$logo_file_name = md5($user_data->id);
$is_uploaded = $upload_logo->upload($logo_file_name);
if ($is_uploaded) { //this cond is needed, cause validation for image fails (?)
//create record in 'logo_data' tbl, deleting previous
if ($logo_name) {
$logo->delete();
} else { //if upload logo first time, set val to $logo_name. Otherwise NULL val will pass to 'profile' view, and user wont see his new logo at once
$logo_name = $logo_file_name.'.'.$upload_logo->imageFile->extension;
}
$logo_data = new LogoData;
$logo_data->user_id = \Yii::$app->user->id;
$logo_data->logo_name = $logo_name;
$logo_data->save();
}
}
}
if (isset($_POST['CompanyProfiles'])){
$company_profile_data->firm_data = $_POST['CompanyProfiles']['firm_data'];
$company_profile_data->company_name = $_POST['CompanyProfiles']['company_name'];
$company_profile_data->regon = $_POST['CompanyProfiles']['regon'];
$company_profile_data->pesel = $_POST['CompanyProfiles']['pesel'];
$company_profile_data->postal_code = $_POST['CompanyProfiles']['postal_code'];
$company_profile_data->nip = $_POST['CompanyProfiles']['nip'];
$company_profile_data->country = $_POST['CompanyProfiles']['country'];
$company_profile_data->city = $_POST['CompanyProfiles']['city'];
$company_profile_data->address = $_POST['CompanyProfiles']['address'];
$company_profile_data->telephone_num = $_POST['CompanyProfiles']['telephone_num'];
$company_profile_data->email = $_POST['CompanyProfiles']['email'];
$company_profile_data->update();
}
if (isset($_POST['personal-data-button'])) {
$user_data->username = $_POST['Users']['username'];
$user_data->password_repeat = $user_data->password = md5($_POST['Users']['password']);
$user_data->update();
}
return $this->render('profile', ['user_data' => $user_data, 'company_profile_data' => $company_profile_data, 'upload_logo' => $upload_logo, 'logo_name' => $logo_name]);
}
My inaccuracy was in clientValidateAttribute() method. Instead of $model->$attribute in code snippet:
if (!/^[0-9]{2}-[0-9]{3}$/.test("{$model->$attribute}")) {
...I had to use predefined JS-var value, cause this var changes with entered value change. So, my new code is:
public function clientValidateAttribute($model, $attribute, $view) {
return <<<JS
if (!/^[0-9]{2}-[0-9]{3}$/.test(value)) {
messages.push("Wrong postal code format.");
}
JS;
}
Model does not load rules and behaviors until not called any function from model. When you call $company_profile_data->update(); model call update and validate functions.
Try add after $company_profile_data = CompanyProfiles::find() this code:
$company_profile_data->validate();
Or just use load function. I think it will help.
I've created a form which adds a category of product in a Categories table (for example Sugar Products or Beer), and each user has their own category names.
The Categories table has the columns id, category_name, userId, created_At, updated_At.
I've made the validation and every thing is okay. But now I want every user to have a unique category_name. I've created this in phpMyAdmin and made a unique index on (category_name and userId).
So my question is this: when completing the form and let us say that you forgot and enter a category twice... this category exist in the database, and eloquent throws me an error. I want just like in the validation when there is error to redirect me to in my case /dash/warehouse and says dude you are trying to enter one category twice ... please consider it again ... or whatever. I am new in laravel and php, sorry for my language but is important to me to know why is this happens and how i solve this. Look at my controller if you need something more i will give it to you.
class ErpController extends Controller{
public function __construct()
{
$this->middleware('auth');
}
public function index()
{
return view('pages.erp.dash');
}
public function getWarehouse()
{
$welcome = Auth::user()->fName . ' ' . Auth::user()->lName;
$groups = Group::where('userId',Auth::user()->id)->get();
return view('pages.erp.warehouse', compact('welcome','groups'));
}
public function postWarehouse(Request $request)
{
$input = \Input::all();
$rules = array(
'masterCategory' => 'required|min:3|max:80'
);
$v = \Validator::make($input, $rules);
if ($v->passes()) {
$group = new Group;
$group->group = $input['masterCategory'];
$group->userId = Auth::user()->id;
$group->save();
return redirect('dash/warehouse');
} else {
return redirect('dash/warehouse')->withInput()->withErrors($v);
}
}
}
You can make a rule like this:
$rules = array(
'category_name' => 'unique:categories,category_name'
);
I'd like to ask, is it possible to change the original posted attributes in actionCreate()?
For example I have 3 attributes: name, phNumber, address
In the _form.php, it automatically posts these 3 attributes. BUT what if I want to change the posted name attribute to all Uppercases? Do I need to create my own method of creating a record just to change how the name will be recorded OR is there something that I can do in actionCreate() so that it only changes the name attribute?
For example, user types in
adam michael
for the name textbox, and I want to change only this attribute to
ADAM MICHAEL
to be recorded in the database instead of having to create another method.
Code below:
public function actionCreate() {
$model = new Masseuse;
if (isset($_POST['Masseuse'])) {
$model->setAttributes($_POST['Masseuse']);
if ($model->save()) {
if (Yii::app()->getRequest()->getIsAjaxRequest())
Yii::app()->end();
else
$this->redirect(array('servicemasseuse/create', 'mid' => $model->id));
}
}
$this->render('create', array( 'model' => $model));
}
Just simply do a $model->name=strtoupper($model->name);
Refer here
You must alter the user input prior to saving the data. You do this by creating an overwritten function in your model.
class Masseuse extends CActiveRecord {
// ...
public function beforeSave()
{
$this->name = strtoupper($this->name)
}
}
I am using a Yii hiddenField in a CActiveForm widget. I have saved this hidden field value in database. There is no issue with storing in DB with Controller action at all. after saving this the hidden field should display the value. And how can I populate the form with the database stored value. Or how to refer some other field in the form to contain value from DB after save is processed.
<?php echo $form->hiddenField($model,'ad_form_id',array('value'=>$base)); ?>
My controller action
public function actionBCFormFields()
{
$model=new BCFormField();
if(isset($_POST['BCFormField']))
{
$model->ad_form_id = $_POST['BCFormField']['ad_form_id'];
$model->attributes=$_POST['BCFormField'];
if ($model->save()){
echo'saved';
}
$this->redirect(array('create',
'crm_base_form_field_id'=>$model->crm_base_form_field_id));
}
Based on the very litle code you have given us i would suggest something like this in your controller, but if you edit your question and elaborate , i will edit my question:
public $ad_form_id
public function actionCreate()
{
$model = new User;
$this->ad_form_id = $this->base;
if (isset($_POST['User'])) {
$model->attributes = $_POST['User'];
$this->base = $this->ad_form_id;
if ($model->validate() && $model->save()) {
$this->redirect(array('view'));
}
}
$this->render('create',array('model' => $model,));
}
I'm trying to figure out how I can use the is_unique rule from the Codeigniter form validation library in the following situation.
I'm trying to submit a edit user form and have the rule:
$this->form_validation->set_rules('user_name', 'User Name', 'required|trim|xss_clean|is_unique[users.user_name]');
What if other values in the form are being changed but this value stays the same. The form is going to see that this value already exists so how would I protect it from editing if this value isn't changed.
Using your code as an example, the is_unique validation rule works by looking for a field called user_name in your users database table. If the field with the same value exists it validates as false.
To make sure it runs only when the user submits a new value, you could check the posted value $this->input->post('user_name') against the value you pulled from the database to populate your form with. If they are the same, don't validate is_unique;
if($this->input->post('user_name') != $original_value) {
$is_unique = '|is_unique[users.user_name]'
} else {
$is_unique = ''
}
$this->form_validation->set_rules('user_name', 'User Name', 'required|trim|xss_clean'.$is_unique);
There's a better way to go around it, I think, still using CodeIgniters' validation library...
Use edit_unique where you pass an extra parameter which is the id of the row you're editing.. See below.. I use it and works pretty fine for me.. hope it helps
$this->form_validation->set_rules('user_name', 'User Name', 'required|trim|xss_clean|edit_unique[users.user_name.'.$id.']');
$something = $this->input->post('something');
$this->form->validation->set_rules('something','Something','xss_clean|is_unique['tbl'.users]');
if($this->form_validation->run()== FALSE){
}
Simple Way
Just Change isset to is_object in system/libraries/form_validation.php
public function is_unique($str, $field)
{
sscanf($field, '%[^.].%[^.]', $table, $field);
return is_object($this->CI->db) //default isset
? ($this->CI->db->limit(1)->get_where($table, array($field => $str))->num_rows() === 0)
: FALSE;
}
Here's an easy method that worked for me and uses well documented code (thanks to https://github.com/ivantcholakov for sharing it!). I found it referenced at https://github.com/bcit-ci/CodeIgniter/issues/3109#issuecomment-46346280
Download https://github.com/ivantcholakov/starter-public-edition-3/blob/master/platform/application/libraries/MY_Form_validation.php (MIT licensed) and save it to your application at application\libraries\MY_Form_validation.php
Delete these two lines from __construct():
$this->CI->load->helper('checkbox');
$this->CI->load->helper('email');
Delete all the functions except __construct() and unique().
At the end of the __construct() method of your controller add this line:
$this->load->library('form_validation');
As per the documentation of the unique() method update your validation rule to add a "unique" rule like this (e.g. if you already have required and trim rules):
…|required|unique[tablename.fieldname,tablename.(primaryKey-used-for-updates)]|trim...
Extend Form_validation.php library create class inside of application/libraries file name MY_Form_validation.php
<?php
class MY_Form_validation extends CI_Form_validation{
protected $ci;
public function __construct($config = array()){
parent::__construct($config);
$this->ci =& get_instance();
}
public function is_unique_update($str, $field){
$explode=explode('#', $field);
$field_name=$explode['0'];
$field_id_key=$explode['1'];
$field_id_value=$explode['2'];
sscanf($field_name, '%[^.].%[^.]', $table, $field_name);
if(isset($this->ci->db)){
if($this->ci->db->limit(1)->get_where($table, array($field_name => $str,$field_id_key=>$field_id_value))->num_rows() === 0){
$this->ci->form_validation->set_message('is_unique_update', 'The {field} field must contain a unique value.');
return false;
}
return true;
}
}
}
Now in your controller
$this->form_validation->set_rules('user_name', 'User Name', 'required|trim|xss_clean|is_unique_update[users.user_name#id#'.$id.']');
"#" I used for explode the string
where id is primary key of users table
and $id is the value of id.
Now you can use this is_unique_update validation in any controller.
This question is very old but maybe some new people experience this problem and this is the solution for it.
I bet your are using Modular Extensions (HMVC) and you have created a new library, MY_Form_validation. You did id for callbacks, so you have this line of code on your class in order to use callbacks:
$this->form_validation->CI =& $this;
Well, the solution to this is whenever you want to use "is_unique" you must delete this line of code "$this->form_validation->CI =& $this;" from the class. I have experienced this problem and i fix it this way, it works fine now.
If you realy want to use callbacks "$this->form_validation->CI =& $this;", then do it only on required "methods" / "functions" where you don't want to use is_unique.
This code helpful for unique validation to create and update function...
In controller
Add this form validation code in both create and update function
$this->form_validation->set_rules('order_no', 'Order no', 'required|callback_check_order_no');
Add this call back function in controller
function check_order_no($order_no) {
if($this->input->post('id'))
$id = $this->input->post('id');
else
$id = '';
$result = $this->Data_model->check_unique_order_no($id, $order_no);
if($result == 0)
$response = true;
else {
$this->form_validation->set_message('check_order_no', 'Order no already exist');
$response = false;
}
return $response;
}
In model
function check_unique_order_no($id = '', $order_no) {
$this->db->where('order_no', $order_no);
$this->db->where('status', "A");
if($id) {
$this->db->where_not_in('id', $id);
}
return $this->db->get('delivery_order')->num_rows();
}
I'm using codeigniter3 and it shows me error when I check username on updating the value, is_unique is not designed to work with update scenario
so using #Anthony Mutisya's answer, here is the complete solution
in your controller, add this line while validation username of the current user with the database
$this->form_validation->set_rules('user_name', 'User Name', 'required|trim|xss_clean|edit_unique[users.user_name.'.$id.']');
You can get that $id from your submited form.
Now, add the following function to /system/libraries/Form_Validation.php this file. System folder is present in your root of CodeIgniter3 folder.
/**
* edit_unique // for check on update value
*
* Check if the input value doesn't already exist
* in the specified database field.
*
* #param string $str
* #param string $field
* #return bool
*/
function edit_unique($value, $params) {
$CI =& get_instance();
$CI->load->database();
$CI->form_validation->set_message('edit_unique', "Sorry, that %s is already being used.");
list($table, $field, $current_id) = explode(".", $params);
$query = $CI->db->select()->from($table)->where($field, $value)->limit(1)->get();
if ($query->row() && $query->row()->id != $current_id)
{
return FALSE;
} else {
return TRUE;
}
}
It works perfectly fine in my case
CodeIgniter 4 has already solution for that,
$validation->setRules([
'email' => 'required|valid_email|is_unique[users.email,id,{id}]',
]);
$_POST = [
'id' => 4,
'email' => 'foo#example.com',
];
then the {id} placeholder would be replaced with the number 4, giving this revised rule:
$validation->setRules([
'email' => 'required|valid_email|is_unique[users.email,id,4]',
]);
Official Documentation
we must have to add table name for is_unique
for Exp.
is_unique[users.email]