I am trying to do the custom validation.All is working fine except $this->addError .
It is not adding the error as it should. this is my controller action
public function actionVerifyAnswer()
{
if(isset(Yii::app()->session['_emailId']))
{
$model=new LoginForm;
$model->scenario='verifyAns';
if(isset($_POST['LoginForm']))
{
$model->attributes=$_POST['LoginForm'];
if($model->validate())
{
$theQuestion=$model->secretQuestion;
$theAnswer= strtolower($model->verifyAnswer);
$usersModel=new Users;
$emailUser= Yii::app()->session['_emailId'];
$userRecord=$usersModel->find('loginEmail=:email AND secretQuestion=:que',array(':email'=>$emailUser,':que'=>$theQuestion));
if(empty($userRecord))
{
throw new CHttpException('You have selected the wrong question');
}
else
{
$usersAnswer= strtolower($userRecord->secretAnswer);
if($theAnswer === $usersAnswer)
{
$this->redirect('changePassword');
}
else
{
throw new CHttpException('you have given the wrong answer');
}
}
}
else
{
throw new CHttpException('model->validate()');
}
}
else
{
$secretQuestion= Yii::app()->params['secretQuestion'];
$this->render('verifyAnswer', array('model'=>$model,
'secretQuestion'=>$secretQuestion,
));
}
}
else
{
Yii::app()->user->loginRequired();
}
}
and this is my custom validation in the model
public function checkQuestion()
{
if(!$this->hasErrors())
{
$model=new LoginForm;
$theQuestion=$this->secretQuestion;
$usersModel=new Users;
$emailUser= Yii::app()->session['_emailId'];
$userRecord=$usersModel->find('loginEmail=:email AND secretQuestion=:que',array(':email'=>$emailUser,':que'=>$theQuestion));
if(empty($userRecord))
{
//this line is not working
$this->addError('secretQuestion', 'Incorrect Combination');
//if i throw exception here. Then exception is working
}
}
}
How can i make $this->addError working?
Custom validation should be triggered from within the model validate ;
public function rules()
{
// NOTE: you should only define rules for those attributes that
// will receive user inputs.
return array(
array('the_answer', 'checkQuestion'),
....
);
}
public function checkQuestion($attribute,$params)
{
....
if(empty($userRecord))
{
//this line is not working
$this->addError('secretQuestion', 'Incorrect Combination');
//if i throw exception here. Then exception is working
}
}
I have solved the issue and i am posting the answer because it might help somebody else also.
I needed to remove the
else{
//not the code inside
}
of this condition
if(isset($_POST['LoginForm']))
{
Note:- I just removed the else and its braces {} and left the code inside the else
as it was i.e :-
$secretQuestion= Yii::app()->params['secretQuestion'];
$this->render('verifyAnswer', array('model'=>$model,
'secretQuestion'=>$secretQuestion,
));
Related
So I'm making this login-app, and I've got troubles displaying the correct error-messages upon register. I want all the exceptions to be thrown and not just one exception in a "try...catch"-method.
So this is the setup:
// EXTENDED EXCEPTION CLASSES
class AException extends Exception {
public function __construct($message = null, $code = 0) {
echo $message;
}
}
class BException extends Exception {
public function __construct($message = null, $code = 0) {
echo $message;
}
}
// INDEX.PHP
try {
$register = new RegisterController();
} catch (AException | BException $e) {
$e->getMsg();
}
I have several factors that may trigger the exception, and I would like all the exceptions to be triggered and captured e.g. if the register form was posted empty, there should be one exception for username being empty, another exception for password being empty etc..
class RegisterController {
public function __construct() {
if (!empty($_POST)) {
$this->checkUserInput();
$this->checkPassInput();
}
}
//... executing code
private function checkUserInput() {
if (strlen($_POST['username']) < 3) { // check character length bigger than 3
throw new \AException("Username has too few characters.");
}
}
private function checkPassInput() {
if (strlen($_POST['password']) < 3) { // check character length bigger than 3
throw new \BException("Password has too few characters.");
}
}
}
So, how do I make my "try...catch"-method echo both the thrown exceptions? Is it possible?
Right now only the first thrown exception-message is displayed, so I guess I need to find some way for the script to continue after an exception has been thrown...
P.S. To clarify further: if a register form is posted with empty input-fields e.g. both username and password input is empty, I want the code to echo two exception-messages, both "Username has too few characters." and "Password has too few characters.".
That's not how the try/catch mechanism is supposed to work. It is not meant to report notices to end users, but to programmatically take action if an undesired situation occurs.
What you want is a simple form validation:
class RegisterController {
public $errors = [];
public function __construct() {
if (!empty($_POST)) {
$this->checkUserInput();
$this->checkPassInput();
}
private function checkUserInput() {
if (strlen($_POST['username']) < 3) { // check character length bigger than 3
$this->errors[] = "Username has too few characters.";
}
}
private function checkPassInput() {
if (strlen($_POST['password']) < 3) { // check character length bigger than 3
$this->errors[] = "Password has too few characters.";
}
}
}
Then you can use something like:
$register = new RegisterController();
if (!empty($register->errors)) {
foreach ($register->errors as $error) {
echo '<div class="error">' . $error . '</div>';
}
}
Sorry for my English, but what I'm trying to say is explained below.
I have a controller say ControllerCard which has an action like this.
function actionScanCard()
{
...
$this->redirect('/transaction/redeem');
...
}
In other controllers, ControllerTransaction, I am trying to get that it comes/redirected from /card/scan-card
function actionRedeem()
{
$redirectFrom = ????;
if ($redirectFrom === '/card/scan-card')
{
// some actions
}
else
throw new ForbiddenHttpException('Must scan card!');
}
How do I get this $redirectFrom value with Yii2?
You could use the remember() & previous() methods in yii\helpers\BaseUrl.
function actionScanCard()
{
...
\yii\helpers\Url::remember();
$this->redirect('/transaction/redeem');
...
}
in TransactionController (or other)
function actionRedeem()
{
$url = \yii\helpers\Url::previous();
if($url === Url::to('card/scan-card')) {
// some actions
} else{}
}
I'm working on an api, it handles the requests which comes from clients, then gets the response from server(developed using codeigniter 3) and forwards that back to client.
But, in case of any database errors, like duplicate id, or null values, the model class cannot handle that error to display a proper error message. I've tried the try catch block but not succeeded yet.
Here's the model:
public function add() {
try {
$this->db->trans_start(FALSE);
$this->db->insert('users', $preparedData);
$this->db->trans_complete();
if ($this->db->trans_status() === FALSE) {
throw new Exception("Database error:");
return false;
}
return TRUE;
} catch (Exception $e) {
log_message('error: ',$e->getMessage());
return;
}
}
One thing to mention, I've set db_debug to FALSE.
Any help would be appreciated.
As for CI 3, below code gets database error code and error message. db_debug is set to FALSE.
public function add() {
try {
$this->db->trans_start(FALSE);
$this->db->insert('users', $preparedData);
$this->db->trans_complete();
// documentation at
// https://www.codeigniter.com/userguide3/database/queries.html#handling-errors
// says; "the error() method will return an array containing its code and message"
$db_error = $this->db->error();
if (!empty($db_error)) {
throw new Exception('Database error! Error Code [' . $db_error['code'] . '] Error: ' . $db_error['message']);
return false; // unreachable retrun statement !!!
}
return TRUE;
} catch (Exception $e) {
// this will not catch DB related errors. But it will include them, because this is more general.
log_message('error: ',$e->getMessage());
return;
}
}
Refer to documentation at https://www.codeigniter.com/userguide3/database/queries.html#handling-errors
saying
If you need to get the last error that has occurred, the error() method will return an array containing its code and message.
It is a bit incomplete in my opinion because it does not show error code and error message in the example code.
I just lost an hour trying to figure out why I can't get the error in my code. You have to check for an error after each statement! Working solution:
function insertUpdate($data) {
$order = $data->order;
$order_products = $data->order_products;
$this->db->trans_start();
$order->user_id = $this->session->user_id;
$error = "OK";
if (!$this->db->insert('_order', $order)) {
$error = $this->db->error()["message"];
}
$id = $this->db->insert_id();
foreach ($order_products as $row) {
$row->order_id = $id;
if (!$this->db->insert('_order_product', $row)) {
$error = $this->db->error()["message"];
break;
}
}
$order_code = substr(md5($id), 0, 6);
if (!$this->db->where('order_id', $id)) {
$error = $this->db->error()["message"];
}
if (!$this->db->update('_order', ["order_code" => $order_code])) {
$error = $this->db->error()["message"];
}
$this->db->trans_complete();
return [
'result' => $error, 'order_code' => $order_code
];
}
Suggestion in above code
Remove line $this->db->trans_complete();
If we see $this->db->error() after completing transaction it will be always empty
Remove semicolon - log_message('error :',$e->getMessage());
return;
public function add()
{
try {
$this->db->trans_start(FALSE);
$this->db->insert('users', $preparedData);
// documentation at
// https://www.codeigniter.com/userguide3/database/queries.html#handling-errors
// says; "the error() method will return an array containing its code and message"
$db_error = $this->db->error();
if (!empty($db_error)) {
throw new Exception('Database error! Error Code [' . $db_error['code'] . '] Error: ' . $db_error['message']);
return false; // unreachable return statement !!!`enter code here`
}
return TRUE;
} catch (Exception $e) {
// this will not catch DB related `enter code here`errors. But it will include them, because this is more general.
log_message('error ',$e->getMessage());
return;
}
}
I have my own MVC and in my BaseController i create simple method flashMessage.
public function flashMessage($name, $value)
{
if(!isset($_SESSION['message'][$name])) {
$_SESSION['message'][$name] = $value;
}
}
This work good but i dont know when to destroy this session. Is good idea to put in __destructor session_unset($_SESSION['message']); ?
This work good but my message has no lifetime
public function authenticate()
{
if(isset($_POST['submit']))
{
$username = $this->inputFilter($_POST['username']);
$password = $this->inputFilter($_POST['password']);
// check if user exist
if(!$this->auth->autheticate($username, $password)) {
$this->flashMessage('error', 'Error: Invalid username or password!');
return $this->redirect('login');
}else {
$this->flashMessage('success', 'Success: Uspešno ste se prijavili na sistem!');
return $this->redirect('home');
}
}
}
You remove it on read.
A simple example, by making the flash message a class.
class FlashMessage
{
static function create($name, $value)
{
if(!isset($_SESSION['message'][$name])) {
$_SESSION['message'][$name] = $value;
}
}
static function read($name)
{
if(isset($_SESSION['message'][$name])) {
$message = $_SESSION['message'][$name];
unset($_SESSION['message'][$name]);
return $message;
}
//return null, false or throw exception
}
}
I suggest looking in already implemented flash messages algorithm.
E.g. in Yii you can set to remove flash message when it was shown:
$this->setFlash('type', 'message');
$this->showFlash('type');
function showFlash($type) {
$msg = isset($_SESSION['message'][$type]) ? $_SESSION['message'][$type] : null;
if (!is_null($msg)) {
unset($_SESSION['message'][$type]);
}
return $msg;
}
I have a form which represnts single answer object (this is standard propel generated form I have not changed much there only some validation rules) and another form that represents a collection of answers code as below:
class BbQuestionAnswersForm extends sfForm {
public function __construct($defaults = array(), $options = array(), $CSRFSecret = null) {
parent::__construct($defaults, $options, $CSRFSecret);
}
public function configure() {
if (!$questions = $this->getOption('questions')) {
throw new InvalidArgumentException('The form need array of BbExamQuestion objects.');
}
if (!$taker = $this->getOption('taker')) {
throw new InvalidArgumentException('The form need BbExamtaker object.');
}
if (!$user = $this->getOption('questions')) {
throw new InvalidArgumentException('The form need sfGuardUser object.');
}
foreach($questions as $question) {
$answer = new BbExamAnswer();
$answer->setBbExamQuestion($question);
$answer->setBbExamTaker($taker);
$answer->setCreatedBy($user);
$answer->setUpdatedBy($user);
$form = new BbExamAnswerForm($answer, array('question' => $question));
$this->embedForm($question->getId(), $form);
}
$this->widgetSchema->setNameFormat('solve[%s]');
}
}
Everything(validation, display) goes fine with this form until I try to save it. Part of action which trying to save the form:
...
$this->form = new BbQuestionAnswersForm(null, array('questions' => $this->questions, 'taker' => $this->taker, 'user' => $this->getUser()->getGuardUser()));
if($request->isMethod('post')) {
$this->form->bind($request->getParameter($this->form->getName()));
if($this->form->isValid()) {
if($this->form->save()) {
$this->getUser()->setFlash('success', 'Save goes fine.');
$this->redirect($this->generateUrl('#bb'));
} else {
$this->getUser()->setFlash('error', 'Upps an error occurred.');
}
}
}
When I send valid form I receive "Call to undefined method BbQuestionAnswersForm::save()" error.
I tried to write this method like this:
public function save() {
$conn = Propel::getConnection(ZlecPeer::DATABASE_NAME);
$conn->beginTransaction();
try{
foreach($this->getEmbeddedForms() as $form) {
$form->save();
}
$conn->commit();
} catch(Exception $e) {
$conn->rollback();
echo 'upps something goes wrong';
die($e->getMessage());
return false;
}
return true;
}
but it doesnt work, I receive exception without any message.
What am I doing wrong, how to make save method work?
I believe your BbQuestionAnswersForm is extending the wrong object. It should extend BaseFormDoctrine or possibly BaseBbQuestionAnswersForm if you are using the framework correctly.
Edit: Just noticed you are using propel but it should be the same thing. Try:
class BbQuestionAnswersForm extends BaseBbQuestionAnswersForm
and less likely:
class BbQuestionAnswersForm extends BaseFormPropel
Save method should looks like this:
public function save($con = null) {
if (null === $con) {
$con = Propel::getConnection(BbExamAnswerPeer::DATABASE_NAME);
}
$con->beginTransaction();
try{
foreach($this->embeddedForms as $name => $form) {
if(!isset($this->values[$name]) || !is_array($this->values[$name])) {
continue;
}
if($form instanceof sfFormObject) {
$form->updateObject($this->values[$name]);
$form->getObject()->save($con);
$form->saveEmbeddedForms($con);
} else {
throw new Exception('Embedded form should be an instance of sfFormObject');
}
}
$con->commit();
} catch(Exception $e) {
$con->rollBack();
throw $e;
return false;
}
return true;
}