Codeigniter HMVC MY_Form_validation from library - php

Whatever I do I cant seem to use the dob function in my MY_Form_validation... please note the _register_verify is inside my User library, and not a controller, so I'm using $CI and not $this...
<?php
/** application/libraries/MY_Form_validation **/
class MY_Form_validation extends CI_Form_validation
{
public $CI;
function __construct( $config = array() )
{
parent::__construct($config);
log_message('DEBUG', 'MY FORM VALIDATION Initialized!!');
}
// --------------------------------------------------------------------
public function dob($dob)
{
$CI =& get_instance();
$CI->form_validation->set_message('dob[]_check', 'Please enter a valid DOB');
show_error('I AM AN ERROR');
}
This is the function in my User Library...
public function _register_verify($testmode = FALSE)
{
if ($testmode) return TRUE;
$CI =& get_instance();
$CI->load->library('form_validation');
$CI->form_validation->CI =& $CI;
$CI->form_validation->set_rules('dob[]', 'DOB', 'trim|dob');
if ($CI->form_validation->run() == FALSE)
{
// What to do if user details are NOT correct?
$CI->session->set_flashdata('dob_error', form_error('dob[]'));
return FALSE;
} else {
return TRUE;
}
}
I'v tried extending the MY_Form_validation and nothing else and it still doesnt work. And most of the turotials i've found call the form_validation from a controller.
I have checked the log and the log message is not there and no error shows.
EDIT: Managed to get the class initialized, however the dob never gets called

Functions inside of MY_Form_Validation.php should return boolean values that give the outcome of the test.
public function dob($dob){
//not perfect, but, returns true if date matches 12/10/1999 for example.
return preg_match("/^[0-9]{2}\/[0-9]{2}\/[0-9]{4}$/", $dob);
}
Make sure you've set dob as a rule either in you controller, or in your config file, depending on how you've set things up:
$this->load->library('form_validation');
$this->form_validation->set_rules('dob', 'date of birth', 'required|dob');
Errors are handled in application/language/english/form_validation_lang.php. Add:
$lang['dob'] = "Oops, wrong DOB format.";
Lastly, please run your form validations inside your controller, not a library, or model. There is no need to call get_instance() and assign to $CI in this use-case.

Related

Problems extending CI library Form_validation

I have tried to extend the Form_validation library from Codeigniter with no success.
I have two functions that I'd like in this extended class but when the validation is run i get these messages in the log:
DEBUG - 06-07-2016 11:20:33 --> Unable to find validation rule: checkAccountnameForUpdate
DEBUG - 06-07-2016 11:20:33 --> Unable to find validation rule: checkEmailForUpdate
Here is my extended class which is placed in
application/libraries
<?php defined('BASEPATH') OR exit('No direct script access allowed');
class MY_Form_validation extends CI_Form_validation
{
public function __construct($rules = array())
{
// Pass the $rules to the parent constructor.
parent::__construct($rules);
// $this->CI is assigned in the parent constructor, no need to do it here.
}
public function checkAccountnameForUpdate($accountname, $id)
{
return 1;
}
public function checkEmailForUpdate($email, $id)
{
return 1;
}
}
And here's my rules:
$this->form_validation->set_rules('editAccountname', 'Brugernavn', 'required|checkAccountnameForUpdate[hiddenField]');
$this->form_validation->set_rules('editEmail', 'Email', 'required|checkEmailForUpdate[hiddenField]');
$this->form_validation->set_message('checkAccountnameForUpdate', 'Test2');
$this->form_validation->set_message('checkEmailForUpdate', 'Test');
// hiddenField is the name of a hiddenField containing the users ID.
I've googled around and tired some different stuff. I have no idea why it doesn't work.
EDIT 1:
I've tried to replace
$this->form_validation->set_rules('editAccountname', 'Brugernavn', 'required|checkAccountnameForUpdate[hiddenField]');
$this->form_validation->set_rules('editEmail', 'Email', 'required|checkEmailForUpdate[hiddenField]');
to
$this->form_validation->set_rules('editAccountname', 'Brugernavn', 'required|checkAccountnameForUpdate');
$this->form_validation->set_rules('editEmail', 'Email', 'required|checkEmailForUpdate');
No changes.
Here is my extension to the validation library. I have left a few functions out as they are site specific but do not affect the demo here.
APPPATH/libraries/MY_Form_validation.php
class MY_Form_validation extends CI_Form_validation
{
public function __construct($rules = array())
{
parent :: __construct($rules);
}
/*
* reformats the input to ###-###-#### and returns formatted string,
* if it cannot accomplish the format (of a non-empty input) it returns FALSE.
*/
public function phone_format($phone)
{
if(empty($phone))
{
//assume an empty field is OK.
//There needs to be a required rule to check a required field and that rule should
//be before this one in the list of rules
return TRUE;
}
$phone = preg_replace('/[^0-9]/', '', $phone);
$newPhone = preg_replace("/([0-9]{3})([0-9]{3})([0-9]{4})/", "$1-$2-$3", $phone);
if(preg_match('/((\d){3})?(\-){1}(\d){3}(\-){1}(\d){4}/', $newPhone))
{
//preg_replace was able to reformat it to the correct pattern - must be good
return $newPhone;
}
return FALSE;
}
/**
* field validation for zipcode
*/
public function check_zipcode($zipcode)
{
$result = (bool) preg_match("/^([0-9]{5})(-[0-9]{4})?$/i", $zipcode);
return $result;
}
}
We can test this class with the simple controller and view shown below. The test uses the phone_format validator function.
A couple things to note about how I'm using form_validation->set_rules().
First, I pass an array of rules instead of the usually demonstrated pipe separated string. eg. "trim|required". Why? Because set_rules() turns the string into an array anyway so why make it do the extra work?
Second. Notice I am passing a fourth argument. The fourth argument is not well documented. Its use is shown in the Setting Error Messages section but it is not described in the Class Reference section of the documentation. The argument accepts an array of error messages in the form ['rule_name' => 'This is the error message'].
I'm also in the habit of using the short syntax to create arrays eg. $this->data = []; instead of $this->data = array(); mostly because it's less typing.
Here's the test controller Testcase.php
class Testcase extends CI_Controller
{
protected $data;
function __construct()
{
parent::__construct();
$this->data = [];
$this->load->library('form_validation');
}
public function test_validation()
{
$this->form_validation->set_rules('phone', 'Phone'
, ['trim', 'required', 'phone_format']
, [
'phone_format' => 'Not a valid phone number.',
'required' => '<em>{field}</em> required.'
]
);
if($this->form_validation->run() == FALSE)
{
$this->load->view('test_form_v', $this->data);
}
else
{
echo "Passed Validation<br>";
echo $_POST['phone'];
}
}
}
And here is the view file test_form_v.php
<?php
echo form_open('testcase/test_validation');
echo form_input('phone', set_value('phone'));
echo form_error('phone');
echo form_submit('Submit', 'Submit');
echo form_close();
Run it by entering this url in a browser your_doman.whatever/testcase/test_validation
Submit without entering any input and you get the required error. Submit "123456789" and you get the invalid phone number error message. Submit "1234567890" and you get
Passed Validation
123-456-7890
This demonstrates that the extend class and its new validator works. I hope this helps you figure out your problem.

Form Validation Won't Work if Load Two Models - CodeIgniter

I have one controller and try to load two models (Usermodel and Contentmodel) and also I need to load Form Validation Library. I use Usermodel to do everything with user such as login and register, and I need Contentmodel to do everything with my web content. At first I was able to login and register and I had no problem with Form Validation Library, but then when I add a line $this->load->model('contentmodel'); to load Contentmodel, I suddenly get this error:
If I remove the line $this->load->model('contentmodel'); everything goes back to normal again.
Controller (Controll.php):
defined('BASEPATH') OR exit('No direct script access allowed');
class Controll extends CI_Controller {
/**
* Index Page for this controller.
*
* Maps to the following URL
* http://example.com/index.php/welcome
* - or -
* http://example.com/index.php/welcome/index
* - or -
* Since this controller is set as the default controller in
* config/routes.php, it's displayed at http://example.com/
*
* So any other public methods not prefixed with an underscore will
* map to /index.php/welcome/<method_name>
* #see http://codeigniter.com/user_guide/general/urls.html
*/
public $lang;
public $logo;
public function __construct () {
parent::__construct();
$this->load->helper('url');
$this->load->helper('form');
$this->load->model('contentmodel');
$this->load->model('usermodel');
$this->load->library('session');
$this->load->library('form_validation');
/*get all user sessions data*/
$this->sesi = $this->session->all_userdata();
$config = $this->contentmodel->load_config();
$this->lang = $config['lang'];
$this->logo = $config['image_logo_path'];
$data['lang'] = $this->lang;
$this->load->view('/header/header');
}
public function panel(){
$this->form_validation->set_rules('email', 'Email', 'required');
$this->form_validation->set_rules('cred', 'Password', 'required');
if($this->form_validation->run() === false){
echo '<center style="position: relative;z-index:10000;font-family: \'Roboto\', sans-serif;color:white;top: 62%;">'.validation_errors().'</center>';
$this->load->view('login');
}else{
$user = $this->usermodel->login();
if($user == 0){
echo '<center class="logerror" style="position: relative;z-index:10000;font-family: \'Roboto\', sans-serif;color:white;top: 62%;">Username or Password incorect. Please try again</center>';
$this->load->view('login');
}else{
$data['data'] = 2;
$data['user'] = $user;
$this->load->view('/header/navbar',$data);
$this->load->view('panel');
$this->load->view('/footer/footer');
}
}
}
And also, if I remove/comment these lines:
$this->form_validation->set_rules('email', 'Email', 'required');
$this->form_validation->set_rules('cred', 'Password', 'required');
/* ... */
if($this->form_validation->run() === false){
/* ... */
}else{
/* ... */
}
Everything goes back to normal again as well.
Please help me. Thanks in advance.
The problem is your $lang variable. As you can see, the Form_validation Library is also using it ($this->CI->lang->load('form_validation');) . Change it to something else, and set it to private. As a rule, any variable inside your controller should be set to private, or else you will have such issues.
You produced a strange problem.Your question title Form Validation Won't Work if Load Two Models - CodeIgniter is wrong.
Form validation library does not stop working how many model you load. You need to find what mistake you do.
Your mistake
#CodeGodie already mentioned why you got that error.Little more addition
If you remove this code $this->lang = $config['lang']; from your controller construct function it will work
why?
Codeigniter's controller uses $lang as an object of CI_Lang class.Form validation class uses(look inside the file and the line number that your error message gave) that variable and it should be object of CI_Lang. But you replacing it as string at your controller construct function that's why you got that error.
On your form validation run part you use === try only with ==
`if($this->form_validation->run() === false){`
replace with.
`if($this->form_validation->run() == false){`
Also You have quite a bit in the construct area.
Auto load url and form helper
Don't load a view in __construct area bad practice I think
Controller With Callback
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class Controll extends CI_Controller {
public function __construct () {
parent::__construct();
$this->load->helper('url'); // Autoload it
$this->load->helper('form'); // Autoload it
$this->load->library('session'); // Autoload it
$this->load->model('contentmodel');
$this->load->model('usermodel');
$this->load->library('form_validation');
// Removed View From Construct not good idea to have in construct area.
}
// change panel to index.
public function index() {
$this->form_validation->set_rules('email', 'Email', 'required|callback_user_login');
$this->form_validation->set_rules('cred', 'Password', 'required');
if ($this->form_validation->run() == TRUE) {
// You could redirect to another controller once login
redirect('success_page');
}
// http://www.codeigniter.com/userguide2/general/views.html
// If not data pass through these views then you will need to use
// something like $this->load->view('header', null, true);
// or with data $this->load->view('header', $data, true);
$this->load->view('header', null, true);
//$this->load->view('header', $data, true);
$this->load->view('login'); // if you need to pass data through to login page then $this->load->view('login', $data);
$this->load->view('footer', null, true);
//$this->load->view('footer', $data, true);
}
public function user_login() {
$user = $this->usermodel->login();
if ($user == TRUE) {
return TRUE;
} else {
$this->form_validation->run('user_login', 'Incorrect Username Or Password');
return FALSE;
}
}
}
On your view then echo the validation messages
<?php echo validation_errors(); ?>
CI2 http://www.codeigniter.com/userguide2/libraries/form_validation.html
CI3 http://www.codeigniter.com/user_guide/libraries/form_validation.html

PHP OOP-based login system

Lets say I am building an OOP-based user authentication system, and I would like to incorporate the following principles: Direct Injection, Inheritance, Encapsulation, Polymorphism and the Single Responsibility Principle.
My background in programming is has always relied on procedural programming, and thus, am finding it difficult to really put these practices into correct use.
Assume I have these classes:
class Config
{
public function set($key, $value);
public function get($key, $default = null);
}
class User
{
public function __construct(PDO $dbh, $id = null);
public function setProfile(Profile $profile);
}
class Auth
{
public function __construct(Config $config);
public function login($username, $password, $keepLoggedIn = true);
public function isLoggedIn();
public function getLoggedInUser();
public function logout();
public function register(array $data);
}
class Session
{
public function start($sessionName = null);
public function write($key, $value);
public function read($key, $default = null);
}
class Profile
{
public function setAddress(Address $address);
public function setName($name);
public function setDOB(DateTime $date);
public function getAge();
}
class Validator
{
public function validate($input);
}
I have intentionally left off the function bodies to keep things simple.
To the best of my knowledge, I believe I'm using the principles correctly. However, I am still unclear as to how you would connect classes like: the Validator to the User model, the User model to the Auth and the Session to the Auth class. All of which depend on each other.
You are on the right track. The way these classes connect to each other is called extending. I tend to go towards an MVC setup, meaning Model, View, Controller.
Your logic goes into the controller, all your DB queries and concrete back end methods go in the model. The controller receives requests and returns responses. It's the middleman. It talks to the back end after a request has been made to it, and feeds the front in via response.
So you have a core controller (keep it bare minimal), then each class you make extends the core controller. So your controller is where you tie all this together.
<?php
//your main core controller, where you load all these things you need avilable, so long as this class is extended
class CoreController {
public $auth
public $session;
public $view;
function construct__ ()
{
$this->auth = instantiateAuthClassHere();
$this->session = instantiateSessionClassHere();
$this->view = instantiateViewClassHere();
}
public function anotherHelperForSomething(){
//helper stuff for this method
}
}
//index, page, or content controller, depending on how many you need, i.e. if you want a controller for each page, thats fine, e.g indexController, etc..
//this is the middle man, has logic, receives requst, returns response to view.
class Controller extends CoreController {
public function index (){
$userModel = new userModel();
//do something with this
$session = $this->session;
$content = 'some html';
$userInfo = $userModel->getUsers();
$view = $this->view->render( array(
'content' => $content,
'userInfo' => $userInfo,
));
return $view;
}
}
//Core LIbraries
class Validator {
//your validator stuff
}
//Core LIbraries
class Session {
//your validator stuff
}
//Core LIbraries
class Auth {
//your validator stuff
}
class CoreModel{
public $validator;
function __construct(){
$this->validator = instantiateValidatorClassHere();
}
}
//a user model class (back end). you want a model class for each db table pretty much.
class UserModel extends CoreModel {
// if you need the validator anywhere inside this class, its globally available here inside any class that extends the CoreModel, e.g. $this->validator->methodName()
public function getUsers (){
$sql = 'SELECT * from users';
$result = $db->get($sql);
return $result;
}
}
Notice, on the Controller, this is a generic name for something like indexController, or anything custom. Also, I have the word extends there. It inherits all the objects from the parent that it extends. Inside it, now they will be available via $this->. See my example where I get $this->session.
Try to avoid constructs - you probably don't need them anywhere except for the core, and under special circumstances, which you might then need to check for yourself before you do even that. I dont use constructs much anymore. It can be a bit clunky and unmanageable.

CodeIgniter: How to put custom validation function in model instead of controller?

In CI's documentation, it says that you could create your own custom validation for use in form submission check. It shows how this can be done in a controller:
http://ellislab.com/codeigniter%20/user-guide/libraries/form_validation.html
But what if I want to have my custom validation function in a model?
I've found that the following did not work...
BOTH FUNCTIONS BELOW ARE IN A MODEL:
public function validate_form(){
$this->form_validation->set_rules('username', 'Username', 'callback_illegal_username_check');
$this->form_validation->run();
}
And here's my custom validation function:
public function illegal_username_check($string){
if($string == 'fcuk'){
$this->form_validation->set_message('illegal_username_check', 'Looks like you are trying to use some swear words in the %s field');
return FALSE;
}
else{
return TRUE;
}
}
I found that because my custom validation function is in the model, it did not get called when I run my "validate_form()" function. How do I resolve this?
Many thanks in advance!
You should put custom validation rules in a MY_Form_validation.php in the application/libraries folder.
Then, when you assign your rules you can do something like this..
$this->form_validation->set_rules('field1', 'Field one name', 'trim|required|xss_clean|your_custom_validator');
Note the custom validator doesn't require the callback_ keyword in front.
Here's an example My_Form_valdation.php file.
class MY_Form_validation extends CI_Form_validation {
function __construct($rules = array()) {
parent::__construct($rules);
$this->ci = & get_instance();
$this->ci->load->database();
}
function your_custom_validator($val) {
$this->set_message('your_custom_validator', 'this isn\'t right!');
return (!$val) ? FALSE : TRUE;
}
Note in the construct I've got the Ci instance and loaded the database class.
To use it i'd do something like this..
$this->ci->db->where('id', 1)->get('user')->row();

Creating a custom codeigniter validation rule

I have a function in my login form that checks if the email and password match the values in the database and if so it logs the user into the system.
I would like to display a validation error if this function returns false.
My problem is that I am unsure how to go about creating this. The message relates to both the password and email fields so I would not want a rule for each input field just display a single message.
I have tried using flashdata to achieve this but it only works when the page has been refreshed.
How can I created a new validation rule solely for the function $this->members_model->validate_member() ??
$this->form_validation->set_error_delimiters('<div class="error">', '</div>');
$this->form_validation->set_rules('email_address', '"Email address"', 'trim|required|valid_email');
$this->form_validation->set_rules('password', '"Password"', 'trim|required');
if ($this->form_validation->run() == FALSE)
{
$viewdata['main_content'] = 'members/login';
$this->load->view('includes/template', $viewdata);
}
else
{
if($this->members_model->validate_member())
{
You use the callback_ in your rules, see callbacks, for ex.
$this->form_validation->set_rules('email_address', '"Email address"', 'trim|required|valid_email|callback_validate_member');
and add the method in the controller. This method needs to return either TRUE or FALSE
function validate_member($str)
{
$field_value = $str; //this is redundant, but it's to show you how
//the content of the fields gets automatically passed to the method
if($this->members_model->validate_member($field_value))
{
return TRUE;
}
else
{
return FALSE;
}
}
You then need to create a corresponding error in case the validation fails
$this->form_validation->set_message('validate_member','Member is not valid!');
One best way to achieve this is extending CodeIgniter’s Form Validation library. Let say we want to create a custom validator named access_code_unique for the field access_code of the database table users.
All you have to do is creating a Class file named MY_Form_validation.php in application/libraries directory. The method should always return TRUE OR FALSE
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class MY_Form_validation extends CI_Form_validation {
protected $CI;
public function __construct() {
parent::__construct();
// reference to the CodeIgniter super object
$this->CI =& get_instance();
}
public function access_code_unique($access_code, $table_name) {
$this->CI->form_validation->set_message('access_code_unique', $this->CI->lang->line('access_code_invalid'));
$where = array (
'access_code' => $access_code
);
$query = $this->CI->db->limit(1)->get_where($table_name, $where);
return $query->num_rows() === 0;
}
}
Now you can easily add your new created rule
$this->form_validation->set_rules('access_code', $this->lang->line('access_code'), 'trim|xss_clean|access_code_unique[users]');

Categories