Cannot show callback validation message in a model - php

I'm using codeigniter 3 to build a simple login form but my callback validation message didn't work. Here is my code:
LoginForm_model.php
class LoginForm_model extends CI_Model
{
private $username;
private $password;
protected $validationRules = [
'username' => 'required|callback_username_exist',
'password' => 'required',
];
public function username_exist($str)
{
$this->load->model('Reseller_model', 'reseller');
$reseller = $this->reseller->findOne(['username' => $this->input->post('LoginForm')['username']]);
if (!empty($reseller)) {
return true;
}
$this->form_validation->set_message('username_exist', 'Username tidak ditemukan');
return false;
}
public function validate() {
$modelName = explode("_", get_class($this));
foreach($this->validationRules as $field => $validationRule) {
$this->form_validation->set_rules($modelName[0].'['.$field.']', $this->getLabels($field), $validationRule);
}
return $this->form_validation->run();
}
}
I use that model in my controller for validating login form input
Welcome.php
class Welcome extends CI_Controller {
public function index()
{
$this->load->model("Loginform_model", "loginform");
if (NULL !== $this->input->post('LoginForm')) {
if ($this->loginform->validate()) {
echo "All Set!";
}
}
$this->load->view('login');
}
}
The callback validation seems to work, but the message is like this:
Unable to access an error message corresponding to your field name Username.(username_exist)
The callback validation works if I put username_exist function in my controller. Can't we do it in a model? I want to make the controller as clean as possible. Please help.

Related

Problem when trying to validate email that already exists in database

I am building custom mvc framework in php in order to learn and when I am trying to submit my form with an mail that already exists in the database, my validation should prevent me to do so, instead I get this error:
Fatal error: Uncaught Error: Call to a member function findUserByEmail() on null in C:\xampp\htdocs\gacho\App\Controllers\UsersController.php:
UsersController.php
<?php
namespace App\Controllers;
use App\Models\User;
use Core\Controller;
class UsersController extends Controller
{
public function __construct($controller, $action)
{
parent::__construct($controller, $action);
$this->userModel = $this->load_model('User');
}
public function registerAction()
{
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$data = [
'email' => trim($_POST['email']),
];
}
if (empty($data['email'])) {
$data['email_err'] = "Please enter your email!!!";
} else {
if ($this->userModel->findUserByEmail($data['email'])) {
$data['email_err'] = "Email is already taken!";
}
}
}
User.php
<?php
namespace App\Models;
use Core\Database;
class User
{
private $db;
public function __construct()
{
$this->db = new Database();
}
public function findUserByEmail($email)
{
$this->db->query('SELECT * FROM users WHERE email = :email');
$this->db->bind(':email', $email);
$row = $this->db->single();
if ($this->db->rowCount() > 0) {
return true;
} else {
return false;
}
}
}
Controller.php:
<?php
namespace Core;
class Controller
{
protected $_controller;
protected $_action;
public $view;
public function __construct($controller, $action)
{
$this->_controller = $controller;
$this->_action = $action;
$this->view = new View();
}
protected function load_model($model)
{
$modelPath = 'App\Models\\' . $model;
if (class_exists($modelPath)) {
$this->{$model.'Model'} = new $modelPath();
}
}
}
I think the mistake is about $this->userModel , but I'm stuck and any help is appreciated.
The problem is that in __construct of UsersController you have:
$this->userModel = $this->load_model('User');
So you assign to userModel property the return value of load_model method.
load_model method doesn't return anything so $this->userModel is always set to NULL, doesn't matter if load_model succeeded or not.
You should just return new $modelPath(); in load_model if you want to assign it to a property by return value.
Also add throw new Exception($modelPath. 'not found'); at the end of load_model method to be sure it did load the model, and not just failed silently to find it.
Note that $this->userModel is not the same as $this->UserModel (case sensitive) and $modelPath = 'App\Models\\' . $model; - why \ after App, and two \ after Models?
I think you need to access your model in $this->UserModel, since User was passed into the load_model method.

Laravel 4 - redirect from a repository when not returning the called method

I am using a repository pattern in my Laravel 4 project but come across something which I think I am doing incorrectly.
I am doing user validation, before saving a new user.
I have one method in my controller for this:
public function addNewUser() {
$validation = $this->userCreator->validateUser($input);
if ( $validation['success'] === false )
{
return Redirect::back()
->withErrors($validation['errors'])
->withInput($input);
}
return $this->userCreator->saveUser($input);
}
Then the validateUser method is:
public function validate($input) {
$rules = array(
'first_name' => 'required',
'last_name' => 'required',
'email_address' => 'unique:users'
);
$messages = [
];
$validation = Validator::make($input, $rules, $messages);
if ($validation->fails())
{
$failed = $validation->messages();
$response = ['success' => false, 'errors' => $failed];
return $response;
}
$response = ['success' => true];
return $response;
}
This may be okay, but I dont like doing the if statement in my controller? I would rather be able to handle that in my validation class.
But to be able to redirect from the validation class, I need to return the method in the controller.
What if I then want to have 5 methods called, I cant return them all?
I would like to be able to simply call the methods in order, then in their respective class handle what I need to and if there is any errors redirect or deal with them. But if everything is okay, simply ignore it and move to the next function.
So example:
public function addNewUser()
{
$this->userCreator->validateUser($input);
$this->userCreator->formatInput($input);
$this->userCreator->sendEmails($input);
return $this->userCreator->saveUser($input);
}
If doing the if statement in the controller isn't as bad as I think then I can continue, but this seems incorrect?
For repository pattern, you can use this :-
setup your basemodel like this
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class BaseModel extends Model{
protected static $rules=null;
protected $errors=null;
public function validateForCreation($data)
{
$validation=\Validator::make($data,static::$rules);
if($validation->fails())
{
$this->errors=$validation->messages();
return false;
}
return true;
}
/**
* #return errors
*/
public function getErrors() { return $this->errors; }
}
now in your repository, add these methods
protected $model;
protected $errors=null;
public function model(){ return $this->model; }
public function getErrors(){ return $this->errors; }
public function create($inputs)
{
if(!$this->model->validateForCreation($inputs))
{
$this->errors=$this->model->getErrors();
return false;
}
$new=$this->model->create($inputs);
return $new;
}
and the controller will look like this..
public function postCreate(Request $request)
{
$inputs=$request->all();
if($new=$this->repo->create($inputs))
{
return redirect()->back()
->with('flash_message','Created Successfully');
}
return redirect()->back()->withInput()->withErrors($this->repo->getErrors())
->with('flash_message','Whoops! there is some problem with your input.');
}

Laravel Authentication

$this->beforeFilter(function()
{
Config::set('auth.model', 'User');
if ((Auth::guest())) {
//dd(Auth::guest());
$msg3 = "Please Login First";
// dd("ok");
return Redirect::to(Request::root().'/auth')->with("error_message", $msg3);
}
});
I am using a Auth::guest() function for stopping unauthorized access but when I hit URL unauthorized access works fine but login fails... without this portion of code login using Auth::attempt() works fine... what can be the problem??
Edit
//AuthController for login
<?php
// uncomment this to use namespaced controller
//namespace Modules\admin\Controllers;
class AuthController extends \BaseController
{
public function __construct()
{
$this->beforeFilter(function()
{
Config::set('auth.model', 'User');
});
}
public function getIndex()
{
return \View::make("login");
}
public function postLogin()
{
$msg7 = "Invalid email address or password";
// $results['userData'] = user::get();
// dd($results);
//$password=Input::get('password');
//$password=Hash::make('secret');
$userData = array(
'email' => Input::get('email'),
'password'=> Input::get('password')
);
$email=Input::get('email');
// $password=Input::get('password');
// dd($password);
//dd($userData);
$rules = array(
'email' => 'required|email',
'password' => 'required|min:5'
);
$remember=Input::get('remember');
$remember_me=false;
if (!empty($remember)) {
$remember_me=true;
}
$validator = Validator::make(Input::get(), $rules);
if($validator->fails()){
// redirect to the login page with validation errors
return Redirect::to(Request::root().'/auth')->withErrors($validator)->withInput();
}
else{
//dd(Auth::attempt($userData));
// check authentication
if(Auth::attempt($userData,$remember_me)){
// dd(Auth::attempt($userData)); // redirect to the dashboard page
//dd($userData);
return Redirect::to(Request::root().'/home');
}else{
//dd($userData);
//DB::table('user')->insert($userData);
//dd("test");
// redirect to the login page with error message
return Redirect::to(Request::root().'/auth')->with("error_message", $msg7);
}
}
}
// logout function
public function getLogout()
{
// delete all data from sesstion
Auth::logout();
Session::flush();
// redirect to login page
return Redirect::to(Request::root().'/auth');
}
}
// DashboardController where unauthorized access is blocked
<?php
class DashboardController extends BaseController{
public function __construct()
{
$this->beforeFilter(function()
{
Config::set('auth.model', 'User');
if ((Auth::guest())) {
//dd(Auth::guest());
$msg3 = "Please Login First";
// dd("ok");
return Redirect::to(Request::root().'/auth')->with("error_message", $msg3);
}
});
}
public function getIndex()
{
//dd(Auth::check());
return View::make('home');
}
}
The problem is that you should exclude your action when you send your login form data. If in your controller you have method postLogin to handle POST data from login form, you should use:
$this->beforeFilter(function() {
// here goes code of your filter
}, array('except' => 'postLogin'));
Reference

Automate redirection after form validation in Laravel 4

I have the following piece of code:
if(Request::ajax())
{
$response_values = array(
'validation_failed' => 1,
'errors' => $validator->errors->toArray()
);
return Response::json($response_values);
}
else
{
return Redirect::route("resource.create")
->withInput()
->withErrors($validator->errors);
}
I have this a lot in my code, and would like to find a way to automate this.
I tried creating a method in BaseController but it doesn't redirect properly, I also tried an after filter, but I was unable to pass parameters to this after filter, as I would need to pass errors and route.
How could I achieve this?
This is not working for you?
class BaseController extends \Controller {
public function processAndRedirectError($validator)
{
if(Request::ajax())
{
$response_values = array(
'validation_failed' => 1,
'errors' => $validator->errors->toArray()
);
return Response::json($response_values);
}
else
{
return Redirect::route("resource.create")
->withInput()
->withErrors($validator->errors);
}
}
}
class MyController extends BaseController {
public function store()
{
$validator = Validator::make(...);
return $this->processAndRedirectError($validator);
}
}

Laravel 4: Pass validation messages obtained from repository to controller

Learning about Ioc and Repositories and stuck at last hurdle!
Assuming I am validating input, how do I pass back messages from the Validator within the repository to the controller?
UserRepository
interface UserRepository {
public function all();
public function create($input);
public function findById($id);
}
Sentry2UserRepository
class Sentry2UserRepository implements UserRepository {
...
public function create($input) {
$validation = Validator::make($input, User::$rules);
if ($validation->passes()) {
Sentry::createUser( array_except( $input, ['password_confirmation']));
// Put something here to tell controller that user has been successfully been created
return true;
}
else {
// pass back to controller that validation has failed
// with messages
return $validation->messages(); ?????
}
...
My UserController
UserController extends BaseController {
...
public function postRegister() {
$input['first_name'] = Input::get('first_name');
$input['last_name'] = Input::get('last_name');
$input['email'] = Input::get('email');
$input['password'] = Input::get('password');
$input['password_confirmation'] = Input::get('password_confirmation');
// Something like
if ($this->user->create($input)) {
Session::flash('success', 'Successfully registered');
return Redirect::to('/');
}
else {
Session::flash('error', 'There were errors in your submission');
return Redirect::to('user/login')->withErrors()->withInput();
}
}
...
}
Only 1.5 weeks into Laravel so please go easy on me.
Assuming your repository is working fine for you already:
class Sentry2UserRepository implements UserRepository {
public $validation;
public function create($input) {
$this->validation = Validator::make($input, User::$rules);
if ($this->validation->passes()) {
Sentry::createUser( array_except( $input, ['password_confirmation']));
// Put something here to tell controller that user has been successfully been created
return true;
}
else {
// pass back to controller that validation has failed
// with messages
return false;
}
}
}
Then you just have to access it within your controller using
$this->user->validation->messages()

Categories