I have this in my action to validate an ajax post
if(Yii::$app->request->isAjax && $model->load(Yii::$app->request->post())){
Yii::$app->response->format = Response::FORMAT_JSON;
return ActiveForm::validate($model);
}
in my view
<?php
$form = ActiveForm::begin([
'id' => $model->formName().'-form',
'action' => Url::to(['/payment/stripe/payment-session']),
'scrollToError' => false,
'validateOnSubmit' => true,
'enableAjaxValidation' => true
]);
echo $form->field($model, 'number')->textInput([ 'class' => 'form-control form-control-lg text-uppercase', 'placeholder'=>'Enter Number', 'id' => 'reports-number'])->label(false);
....
....
ActiveForm::end();
?>
in my model
public function rules() {
...
[['number'], ENumberValidator::class, 'on' => ['check-number']],
...
}
when i enter 456!! in the input, i get this ajax returned. which is correct.
{
"reports-number": [
"Number is an invalid format."
]
}
but for some reason no error message shows under the input, the input has a check mark in green and form can still be submitted. Any idea what I'm missing here? Thanks
Related
I am humbly seeking a help on how to go about displaying error message in CI4. i have create a controller like this:
public function login()
{
$validation = \config\services::validation();
$errors = array('email' => 'bad email',
'pass' => 'bad pass ');
if(!$this->validate(array('email' => 'required',
'pass' => 'required')))
{
echo view('login', array('validation' => $this->validator));
}
else
{
print 'success';
}
}
while a tested each of the error reporting function below:
$validation->listErrors();
$validation->listErrors('list');
$validation->showError();
$validation->showError('sigle');
$validation->showError('email');
but non of these function work, if i entered correct data it print success as assign but upon wrong data it all show the same error message which is:
Call to a member function listErrors() on null.
Call to a memberfunction listErrors() on null.
Call to a member function showError()on null.
Call to a member function ShowError() on null.
call form helper in your controller before your validation start
helper('form');
and i re-arrange ur code like this
public function login()
{
$data = [
'validation' => \config\services::validation()
];
if ($this->request->getMethod() == "post") { // if the form request method is post
helper('form');
$rules = [
'email' => [
'rules' => 'required',
'errors' => [
'required' => 'bad email'
]
],
'pass' => [
'rules' => 'required',
'errors' => [
'required' => 'bad pass'
]
]
];
if (!$this->validate($rules)) {
echo view('login', array('validation' => $this->validator));
} else {
// whatever you want todo
}
}
echo view('login', $data);
}
in your login view, if you want to call all error list you got use this method $validation->listErrors();
if you want to call a specific error use this method $validation->listErrors('email');
if you want to check is the specific field returning an error use this method $validation->hasError('email'))
i hope this help you to solve your problem
how to redirect the users after login,
i tried to use all of these :
Yii::$app->request->getReferrer(); // printing the refferrer url to screen
$this->redirect(\Yii::$app->request->referrer)
return \Yii::$app->getResponse()->redirect(\Yii::$app->getUser()->getReturnUrl($defaultUrl));
none of these above is working
public function actionLogin()
{
if (!\Yii::$app->user->isGuest) {
$this->goHome();
// $this->goHome();
}
/** #var LoginForm $model */
$model = \Yii::createObject(LoginForm::className());
$event = $this->getFormEvent($model);
$this->performAjaxValidation($model);
$baseurl = \Yii::$app->request->getAbsoluteUrl();
$this->trigger(self::EVENT_BEFORE_LOGIN, $event);
if ($model->load(\Yii::$app->getRequest()->post()) && $model->login()) {
$this->trigger(self::EVENT_AFTER_LOGIN, $event);
// return $this->redirect(\Yii::$app->request->referrer);
// return \Yii::$app->getResponse()->redirect(\Yii::$app->getUser()->getReturnUrl($defaultUrl));
// return \Yii::$app->request->getReferrer(); // printing the refferrer url to screen :(!!
return $this->redirect($baseurl);
// return $this->redirect(\Yii::$app->request->referrer);; //this one is returning everthing to main page, because of line 147
// return $this->goBack();
}
return $this->render('login', [
'model' => $model,
'module' => $this->module,
]);
}
In the web.php config i have this :
$config =[
..//
'modules' => [
'user' => [
'class' => 'dektrium\user\Module',
'enableUnconfirmedLogin' => true,
'confirmWithin' => 21600,
'cost' => 12,
'enableFlashMessages' => true,
'admins' => ['a'],
],
//..
all of these above is just sending the user after login to the home page
what should i do please , i have searched every where read the documentations
After 4 hours of trying i tried to "Echo" the URL after requesting referrer ;
the referrer is working fine the problem is after login the page loads more than one time and here is the problem why it's not sending back to that page but sending people to the current page (login page) then if he is a user he is automatically sending home.
The problem is common and it is related to the issue that at the time when you post login, your actual referrer is login page - actionLogin(), so you are redirected back again and off course you get passed throughout the
condition that you are not the Guest. In order to handle this, you have to assign a referrer to a modal field, so it can be posted with the login information. So at the time when login is validated, you have the required referrer url in your field. Check if you have this field identified in your form:
<?php $form = ActiveForm::begin(['id' => 'login-form']); ?>
<?= $form->field($model, 'referer')->hiddenInput()->label(false) ?>
Controller
$form = new LoginForm();
//get previos viewed page url and store in the new model
$form->referer = Yii::$app->request->referrer;
if ($form->load(Yii::$app->request->post())) {
if($form->login()){
return $this->goBack((($form->referer) ? $form->referer : null));
}
}
LoginForm() model
public $referer;
/**
* {#inheritdoc}
*/
public function rules()
{
return [
//...
['referer', 'string'],
];
}
After that, when it will be post request, this field will contain a referrer, which you will pass in your controller.
Further, if you use the yii2-user module, now it is possible and necessary in the config in the controllerMap to remove all forced redirects for the event "after logging in" (I commented them out):
...
'modules' => [
'user' => [
'class' => \dektrium\user\Module::className(),
'admins' => ['adminname'],
'enableConfirmation' => false,
'modelMap' => [
'User' => 'app\models\User',
'UserSearch' => 'app\models\UserSearch',
'Profile' => 'app\models\Profile',
],
'controllerMap' => [
'profile' => 'app\controllers\user\ProfileController',
'security' => [
'class' => \dektrium\user\controllers\SecurityController::className(),
'on ' . \dektrium\user\controllers\SecurityController::EVENT_AFTER_LOGIN => function ($e) {
/*if (Yii::$app->user->can('student free')) {
Yii::$app->response->redirect(array('/course'))->send();
}
if (Yii::$app->user->can('admin')) {
Yii::$app->response->redirect('http://site.ru/user/')->send();
}*/
//Yii::$app->response->redirect(Yii::$app->request->referrer)->send();
// Yii::$app->response->redirect(array('/user/'.Yii::$app->user->id))->send();
//Yii::$app->end();
}
],
],
],
...
I did it, with the help of #serghei Leonenco,
but i had these problems :
The page reloaded after pressing the button submit so the referrer was the login page always and this is why it kept sending users to main page.
I had to get the referrer before the form begin.
I had to pass the value of the referrer to a hidden input.
I had to check if the referrer is from my website or the guest got on login page from a 3rd party site.
Passed the value after checking, used redirect and Url::to('link', true) because the value i got from referrer was a full URL and i couldn't just redirect to a full link this is why i used Url::to with the true condition which means creating a new URL.
View
Notice that i used the referrer value before the form.
<div class="panel-body arab">
**<?php $referer = \Yii::$app->request->referrer;?>**
<?php $form = ActiveForm::begin([
'id' => 'login-form',
'enableAjaxValidation' => true,
'enableClientValidation' => false,
'validateOnBlur' => false,
'validateOnType' => false,
'validateOnChange' => false,
]) ?>
**<?= $form->field($model, 'referer')->hiddenInput(['value' => $referer])->label(false) ?>**
<?php if ($module->debug): ?>
<?= $form->field($model, 'login', [
'inputOptions' => [
'autofocus' => 'autofocus',
'class' => 'form-control',
'tabindex' => '1']])->dropDownList(LoginForm::loginList());
?>
<?php else: ?>
<?= $form->field($model, 'login',
['inputOptions' => ['autofocus' => 'autofocus', 'class' => 'form-control', 'tabindex' => '1']]
);
?>
<?php endif ?>
<?php if ($module->debug): ?>
<div class="alert alert-warning">
<?= Yii::t('user', 'Password is not necessary because the module is in DEBUG mode.'); ?>
</div>
<?php else: ?>
<?= $form->field(
$model,
'password',
['inputOptions' => ['class' => 'form-control', 'tabindex' => '2']])
->passwordInput()
->label(
Yii::t('user', 'Password')
. ($module->enablePasswordRecovery ?
' (' . Html::a(
Yii::t('user', 'Forgot password?'),
['/user/recovery/request'],
['tabindex' => '5']
)
. ')' : '')
) ?>
<?php endif ?>
<?= $form->field($model, 'rememberMe')->checkbox(['tabindex' => '3']) ?>
<?= Html::submitButton(
Yii::t('user', 'Sign in'),
['class' => 'btn btn-success btn-block', 'tabindex' => '4']
) ?>
<?php ActiveForm::end(); ?>
Model
Notice I used regex to make sure that the user got to login page using my website.
public function getReferer()
{
$getLink = \Yii::$app->request->post('login-form')['referer'];
if(preg_match('/tajrobtak/', $getLink)){
return $getLink;
} else {
return "";
}
}
Controller
public function actionLogin()
{
if (!\Yii::$app->user->isGuest) {
$this->goHome();
}
/** #var LoginForm $model */
$model = \Yii::createObject(LoginForm::className());
$referery = $model->getReferer();
$event = $this->getFormEvent($model);
$this->performAjaxValidation($model);
$this->trigger(self::EVENT_BEFORE_LOGIN, $event);
if ($model->load(\Yii::$app->getRequest()->post()) && $model->login()) {
$this->trigger(self::EVENT_AFTER_LOGIN, $event);
$this->redirect(Url::to($referery,true));
}
return $this->render('login', [
'model' => $model,
'module' => $this->module,
]);
}
I have a model with a custom validation method. For testing it always returns an error message.
public function rules()
{
return [
...
['staff_ids', 'each', 'rule' => ['string']],
[['staff_ids'], 'validateStaffIds'],
...
];
}
public function validateStaffIds($attribute, $params, $validator) {
$this->addError($attribute, 'There is an error in the staff ids');
}
In the view.php is the modal element
<p>
<?= Html::button('Add Ensemble Staff',
['value' => Url::to(['ensemble/add', 'id' => $model->id]),
'title' => 'Adding New Ensemble Staff',
'class' => 'showModalButton btn btn-primary']);
?>
</p>
<?php
Modal::begin([
'closeButton' => [
'label' => 'x',
],
'headerOptions' => ['id' => 'modalHeader'],
'id' => 'modal',
'size' => 'modal-lg',
]);
echo "<div id='modalContent'></div>";
Modal::end();
?>
The js code which fires everything up...
$(function(){
$(document).on('click', '.showModalButton', function(){
if ($('#modal').data('bs.modal').isShown) {
$('#modal').find('#modalContent')
.load($(this).attr('value'));
} else {
//if modal isn't open; open it and load content
$('#modal').modal('show')
.find('#modalContent')
.load($(this).attr('value'));
}
//dynamiclly set the header for the modal
...
});
});
And the ensemble controller which handles the add action
public function actionAdd($id)
{
$model = $this->findModel($id);
// in the post ( 'ensembleStaff_ids' => [0 => '2']); where the id actually is staff_id
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return $this->redirect(['view', 'id' => $id]);
} else {
return $this->renderAjax('add', [
'model' => $model,
]);
}
}
And the form which is injected by the js into the model (Url::to(['ensemble/add', 'id' => $model->id]), )
<?php $form = ActiveForm::begin(['id' => 'add-theater-stuff-form']); ?>
<?= $form->field($model, 'staff_ids')->widget(Select2::className(), [
'model' => $model,
'data' => ArrayHelper::map(app\models\TheaterStaff::find()->where(['theater_id' => $model->theater_id])->all(), 'staff_id', 'staff.fullname'),
'options' => [
'multiple' => true,
'prompt' => 'Ensemble Staff',
],
'pluginOptions' => [
'tags' => true
]
]); ?>
<div class="form-group">
<?= Html::submitButton('Add', ['class' => 'btn btn-primary']) ?>
</div>
<?php ActiveForm::end(); ?>
Clicking on the Add Ensemble Staff Button works fine and brings up the modal window. The form itself works fine so far; also the default validation works. Even the custom validation is called, but return $this->renderAjax(...) isn't load in the modal window anymore; it is separately.
A picture showing the modal loaded, the result after submit and a modal with default validation.
I found a similar problem here. But adding an id to the form, doesn't solve the problem. So how to get the default validation showing up properly in the modal window? Does anyone have a clue?
Solution
Thanks for the response. For me the solution was:
Enable ajax in the form
<?php $form = ActiveForm::begin(['id' => 'add-ensemble-stuff-form', 'enableAjaxValidation' => true]); ?>
And to add the following logic in the controller
public function actionAdd($id)
{
$model = $this->findModel($id);
if (Yii::$app->request->isAjax && $model->load(Yii::$app->request->post())) {
Yii::$app->response->format = Response::FORMAT_JSON;
return ActiveForm::validate($model);
} else {
// in the post ( 'ensembleStaff_ids' => [0 => '2']); where the id actually is staff_id
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return $this->redirect(['view', 'id' => $id]);
} else {
return $this->renderAjax('add', [
'model' => $model,
]);
}
}
}
if (Yii::$app->request->isAjax && $model->load(Yii::$app->request->post())) {
Yii::$app->response->format = Response::FORMAT_JSON;
return ActiveForm::validate($model);
}else{/* your code */}
add this in controller use yii\web\Response
I was trying to validate my YII2 register form but it not work. In view:
$form = ActiveForm::begin([
'id' => 'register',
'options' => ['accept-charset'=>'utf-8'],
'validateOnChange' => false,
'enableAjaxValidation' => true,
'validateOnSubmit' => true,
])
In controller:
$model = new MUser();
if($model->load(Yii::$app->request->post()) && Yii::$app->request->isAjax)
{
$model->refresh();
Yii::$app->response->format = 'json';
return ActiveForm::validate($model);
}
elseif($model->load(Yii::$app->request->post()) && $model->save())
{
\\do something
}
In Model:
public function rules()
{
return [
[
'username',
'unique',
'targetClass' => 'com\modules\admin\models\MUser',
'message' => 'Username exist',
]
];
}
Can anyone let me know what wrong I am doing?
change
return ActiveForm::validate($model)
TO
echo json_encode(ActiveForm::validate($model));
\Yii::$app->end();
ActiveForm::validate($model) is an array it needs to be represented in json form which is done by json_encode and \Yii::$app->end(); is making sure that the application stop on just checking.Also make sure you have after the namespace :
use yii\web\Response;
use yii\widgets\ActiveForm;
But By doing so the submission via ajax of your form will not work the perfect way is using validationUrl.
I am learning Yii and i am trying csrf validation
I have made the following class in the application.components.HttpRequest
class HttpRequest extends CHttpRequest {
private $_csrfToken;
public function getCsrfToken() {
if($this->_csrfToken === NULL) {
$this->_csrfToken= sha1(uniqid(mt_rand(),true));
if(!isset(Yii::app()->session['_tokenforcsrf'])) {
Yii::app()->session['_tokenforcsrf']= $this->_csrfToken;
} else {
Yii::app()->session['_tokenforcsrf']= $this->_csrfToken;
}
return $this->_csrfToken;
}
}
public function validateCsrfToken($event) {
if($this->getIsPostRequest()) {
if(isset(Yii::app()->session['_tokenforcsrf']) && isset($_POST['_tokenforcsrf'])) {
$sessiontoken=Yii::app()->session['_tokenforcsrf'];
$posttoken=$_POST['_tokenforcsrf'];
if($sessiontoken === $posttoken) {
$validity=TRUE;
} else {
$validity=FALSE;
}
} else {
$validity=false;
}
if($validity==false) {
throw new CHttpException(400,Yii::t('yii','The CSRF token could not be verified.'));
}
}
parent::validateCsrfToken($event);
}
}
The csrf validation is working properly in case of everything but whenever i try to delete some thing it shows that
The CSRF token could not be verified
Its not validating in case of deletion of the records.
The link from where i am trying to delete is
$this->menu = [
[
'label' => 'List Rolearea',
'url' => ['index']
],
[
'label' => 'Create Rolearea',
'url' => ['create']
],
[
'label' => 'Update Rolearea',
'url' => [
'update',
'owner'=>$model->roleName
]
],
[
'label' => 'Delete Rolearea',
'url' => '#',
'linkOptions' => [
'submit' => [
'delete',
'id' => $model->roleNo
],
'confirm' => 'Are you sure you want to delete this item?'
]
],
[
'label' => 'Manage Rolearea',
'url' => ['admin']
],
];
So my question is how can i resolve the issue of csrf validation in this case??
Your code requires that every action that has been secured via your CSRF token has to be invoked via POST. A simple link will result into a GET request, which is why your validation fails.