I'm a beginner of Yii, that's why can't figure out, what's wrong.
I use the same model - Users - for login, registration and edition profile.
Users model:
class Users extends \yii\db\ActiveRecord {
public $password_repeat; //have no this value in DB, that's why write it as property directly. Need only for profile editing
public function rules() {
return [
[['username', 'password', 'authKey', 'accessToken'], 'safe'],
[['username', 'password'], 'required'],
[['username', 'password', 'authKey', 'accessToken'], 'string', 'max' => 255],
[['is_admin'], 'boolean'],
//don't use scenarios() here. Use 'on' instead
['password_repeat', 'required', 'on' => 'update'],
['password_repeat', 'compare', 'compareAttribute'=>'password', 'message'=>"Passwords don't match", 'on' => 'update' ],
];
}
}
view snippet:
<?php $form = ActiveForm::begin([
'id' => 'data-form',
'options' => ['class' => 'form-horizontal', 'enctype' => 'multipart/form-data'],
'fieldConfig' => [
'template' => "{label}\n<div class=\"col-lg-3\">{input}</div>\n<div class=\"col-lg-6\">{error}</div>",
'labelOptions' => ['class' => 'col-lg-1 control-label'],
],
]); ?>
<?= $form->field($user_data, 'username') ?>
<?= $form->field($logo_data, 'imageFile')->fileInput() ?>
<?= $form->field($user_data, 'password')->passwordInput(['value'=>''])?>
<?= $form->field($user_data, 'password_repeat')->passwordInput(['value'=>''])?>
<?= Html::submitButton('Zapisz', ['class' => 'btn btn-primary btn-block', 'name' => 'data-button']) ?>
<?php ActiveForm::end(); ?>
Site controller action:
public function actionProfile(){
//3 model instances to retrieve data from users && company_profiles and logo
$user_data = Users::find()->where(['id'=>Yii::$app->user->id])->one();
$company_profile_data = CompanyProfiles::find()->where(['user_id'=>Yii::$app->user->id])->one();
$logo_data = new UploadLogo();
//here I upload file through $logo_data
if (isset($_POST['Users'])){
$user_data->username = $_POST['Users']['username'];
$company_profile_data->firm_data = $_POST['CompanyProfiles']['firm_data'];
//other assignments
$user_data->scenario = 'update'; //specially for 'profile' page
if (($_POST[Users][password] !== '') && ($_POST[Users][password_repeat]) !== '' && ($_POST[Users][password] == $_POST[Users][password_repeat]))
$user_data->password_repeat = $user_data->password = md5($_POST[Users][password]); //MAYBE, problem is here?
$user_data->update();
$company_profile_data->update();
}
return $this->render('profile', ['user_data' => $user_data, 'company_profile_data' => $company_profile_data, 'logo_data' => $logo_data]);
}
I use update scenario for profile editing page. During this scenario password_repeat is required and need to be the same as password. But it doesn't work as expected.
A: When i try to submit form without entered password AND repass, I see message "can't be blank" only for password. Then I put value in ONLY pass input, and page reloads (DB table doesn't changes), and after reloading I see message "can't be blank" this time for repass field! But the most strange is that before next page reloading everything work normal. After reloading goto A; :)
If I delete scenario, everything is ok with validation. But I can't delete it, cause in this case registration fails (repass field becomes required to fill).
So, what need I to do my with pass-repass functionality to work it fine (with scenario 'update')? Where is mistake?
Got it! I just need to move this codeline:
$user_data->scenario = 'update';
from IF stmt. And now I want to make a habit to assign scenario property directly under creating model instance.
Related
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,
]);
}
For some reason I can't login to accounts I registered. More info below.
Functions from UsersController.php
public function login() {
if ($this->request->is('post')) {
$auth = $this->Auth->identify(); // Returns false
debug($this->request->getData()); // Return email & with unhashed password
debug($auth);
if ($auth) {
$this->Auth->setUser($auth);
$this->redirect($this->Auth->redirectUrl());
} else {
$this->Flash->error('E-mail or password is wrong.');
}
}
}
public function register() {
$user = $this->Users->newEntity();
$this->set('user', $user);
$this->loadModel('Groups');
$group = $this->Groups->newEntity();
$this->set('group', $user);
if ($this->request->is('post')) {
// Check if passwords matches
$pass = $this->request->getData('password');
$con_pass = $this->request->getData('password_confirm');
if ($pass !== $con_pass) {
return $this->Flash->error('Passwords don\'t match');
}
// Patch entities
$group = $this->Groups->patchEntity($group, $this->request->getData());
$user = $this->Users->patchEntity($user, $this->request->getData());
// Make group and user
if (empty($group->errors()) && empty($user->errors())) {
// Group
if (!$this->Groups->save($group)) {
return $this->Flash->error('Something went wrong');
}
// User
$user->group_id = $group->id;
if ($this->Users->save($user)) {
$this->Flash->success('Welkom ' . $user->name . '!');
// return $this->redirect(['action' => 'register']);
} else {
return $this->Flash->error('something went wrong2');
}
}
}
}
Auth component in AppController:
$this->loadComponent('Auth', [
'userModel' => 'Users',
'loginAction' => [
'controller' => 'Users',
'action' => 'login'
],
'authenticate' => [
'Form' => [
'fields' => [
'username' => 'email',
'password' => 'password'
]
]
],
//'authError' => false,
'storage' => 'Session'
]);
Login form:
<?= $this->Form->create('User'); ?>
<?= $this->Form->email('email', ['placeholder' => 'E-mail', 'maxlength' => '42', 'label' => false]) ?>
<?= $this->Form->password('password', ['type' => 'password', 'placeholder' => 'Wachtwoord', 'maxlength' => '32', 'label' => false]) ?>
<?= $this->Form->submit('Login', ['class' => 'button']) ?>
<?= $this->Form->end(); ?>
User entity:
class User extends Entity {
protected $_accessible = [
'group_id' => true,
'name' => true,
'email' => true,
'password' => true,
'profile_img_url' => true,
'pass_reset_time' => true,
'creation_date' => true,
'modified_date' => true
];
protected function _setPassword($password) {
return (new DefaultPasswordHasher)->hash($password);
}
protected $_hidden = [
'password'
];
}
The user gets saved correctly in the database with a hashed password.
When I try to login $this->Auth->identify(); always returns false.
I've tried to / Things to know:
I'm trying to login with email and password.
Table name in db is users
Renew salt (And create a new account and login with that account)
Password column length is 255.
Checked Auth docs
Checked Blog tutorial
Checked a lot of questions related to this on Stack and other websites but nothing has fixed my problem yet.
Users get stored correctly. But as soon as I try to login, it won't let me.
I tried to login without the password hasher function and with an unhashed password, Also didn't work.
Checked in different browsers & deleted cache.
Thanks!
There doesn't seem to be any obvious errors, except for a missing emptiness check in the _setPassword() method that would prevent an empty $password from being hashed. You should do something similar to what is shown in the docs:
if (strlen($password) > 0) {
return (new DefaultPasswordHasher)->hash($password);
}
See Cookbook > Controllers > Components > Authentication > Hashing Passwords
Also the FormHelper::create() method also doesn't take a string, it only doesn't error out there for backwards compatibility reasons IIRC. If you don't have a valid context to pass, then don't pass any value at all.
That being said, you'll have to do more debugging on your own. Start with manually validating the hashed password stored in the database using the DefaultPasswordHasher::validate() method to ensure that the correct value has been hashed.
Then go set some breakpoints in the authentication code flow to figure where things may go wrong, check:
FormAuthenticate::authenticate()
FormAuthenticate::_checkFields()
BaseAuthenticate::_findUser()
BaseAuthenticate::_query()
whether the correct request data is being read, whether the query conditions are built as expected, whether and what value is being returned for password verification, etc...
Alright, I wasted my whole morning and afternoon.
I thought my password column length was 255 but it was actually 32. I checked the length of the wrong column like 4 times apparently.
Thanks for the help #ndm.
I have ajax validation on unique on create it work fine but when I want to update i cant becouse this show message that this name is already used but i not owerwrite this name it is name from database on update click. Its does not matter whcich record i want to update it always show me message that name is already used. Whan can i do to disable message when i not change my input to name which is in base. Now it is so update action automatically filed my inputs but when i not change anythink i have this error on save
<?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data'], 'id'=>$model->formName(), 'enableAjaxValidation'=>true, 'validationUrl'=>Url::toRoute('category/validation')]) ?>
My controller:
public function actionValidation(){
$model= new SmCategory;
if(Yii::$app->request->isAjax && $model->load(Yii::$app->request->post()))
{
Yii::$app->response->format='json';
return ActiveForm::validate($model);
}
}
my rules:
public function rules()
{
return [
[['Name'], 'required'],
['Name', 'unique', 'targetClass' => 'common\models\Smcategory', 'message' => 'This name has already been taken.'],
[['Rel_Category', 'IsDeleted'], 'integer'],
[['File'],'file'],
[['Name', 'Label'], 'string', 'max' => 45],
[['Picture'], 'string', 'max' => 255]
];
}
The problem is here :
$model= new SmCategory;
This code is ok for create, not for update since it will not use the existing model for validation, it could be (just an example and assuming id is the primary key) :
public function actionValidation($id = null)
{
$model = $id===null ? new SmCategory : SmCategory::findOne($id);
if(Yii::$app->request->isAjax && $model->load(Yii::$app->request->post()))
{
Yii::$app->response->format='json';
return ActiveForm::validate($model);
}
}
And you could update validationUrl in your view :
$validationUrl = ['category/validation'];
if (!$model->isNewRecord)
$validationUrl['id'] = $model->id;
$form = ActiveForm::begin([
'options' => ['enctype' => 'multipart/form-data'],
'id' => $model->formName(),
'enableAjaxValidation' => true,
'validationUrl' => $validationUrl,
]);
I have an insert form for a specific model and the required fields validations are works well through rules function in that model. I want to add another field in the form from another table and give its required validation. How to do this?
Consider following example
Contact.php // model1
...
class Contact extends Model
{
public function rules()
{
return [
['contact_name', 'string', 'required'],
// other attributes
];
}
...
Users.php // model2
...
class Users extends Model
{
public function rules()
{
return [
['user_name', 'string', 'required'],
// other attributes
];
}
...
ContactController.php
...
use \app\models\Users;
...
class ContactController extends Controller
{
public function actionCreate()
{
$contact_model = new Contact;
$users_model = new Users;
if($contact_model->load(Yii::$app->request->post()) && $users_model->load(Yii::$app->request->post()))
{
// saving code
}
else
{
return $this->render('create', ['contact_model'=>$contact_model, 'users_model'=>$users_model]);
}
}
...
in views/contact/_form.php
...
<?php $form = ActiveForm::begin(); ?>
<?= $form->field($contact_model, 'contact_name')->textInput(['maxlength' => 255]) ?>
<?= $form->field($user_model, 'user_name')->textarea(['rows' => 6]) ?>
<!-- other inputs here -->
<?= Html::submitButton($contact_model->isNewRecord ? Yii::t('app', 'Create')
: Yii::t('app', 'Update'), ['class' => $contact_model->isNewRecord
? 'btn btn-success' : 'btn btn-primary']) ?>
<?= Html::a(Yii::t('app', 'Cancel'), ['article/index'], ['class' => 'btn btn-default']) ?>
<?php ActiveForm::end(); ?>
...
Here input from two different models get validated too, and make sure that both input are in same one form.
Use enableClientValidation to validate those fields
$form = ActiveForm::begin([
'id' => 'register-form',
'enableClientValidation' => true,
'options' => [
'validateOnSubmit' => true,
'class' => 'form'
],
])
I have a table "attendance" and when I perform create action on it ,it works properly like the screen-shot below,
In this form I have used jquery to disable form field 'time in' and 'time out' if the status value is "Absent" or "Leave".
my jquery code is below
<script>
$(document).ready(function() {
$("#status_id").on('change', function()
{
if($("#status_id").val()=='Absent' || $("#status_id").val()=='Leave')
{
$("#attendance-time_in").val('');
$('#attendance-time_in').attr('disabled', true);
$("#attendance-time_out").val('');
$('#attendance-time_out').attr('disabled', true);
}
else {
$("#attendance-time_in").val();
$('#attendance-time_in').attr('disabled', false);
$("#attendance-time_out").val();
$('#attendance-time_out').attr('disabled', false);
}
});
});
</script>
and _form.php code is
<?= $form->field($model, 'status', ['inputOptions' => ['class' => 'form-control','id' => 'status_id']])
->dropDownList([ 'Present' => 'Present', 'Absent' => 'Absent', 'Leave' => 'Leave',], ['prompt' => 'Select status']); ?>
<?=
$form->field($model, 'time_in')->widget(TimePicker::classname(), [
'name' => 'time_in',
'options'=>[
'id'=>'attendance-time_in',
],
]);
?>
<?=
$form->field($model, 'time_out')->widget(TimePicker::classname(), [
'name' => 'time_out',
'options'=>[
'id'=>'attendance-time_out',
],
]);
?>
its works fine for create action but when i update any data
like if i update data of arsalan khalid ,and i put absent instead of present the jquery works properly but when i click on update button it does not update the 'time in' and 'time out' attributes while all other attributes gets updated.for 'time in' and 'time out' it takes the previous value that it have i.e 9:40am and 5:52pm but i want it should have null values as i have selected "Absent" in status.
AttendanceController Update Action
public function actionUpdate($id)
{
$model = $this->findModel($id);
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return $this->redirect(['view', 'id' => $model->id]);
} else {
return $this->render('update', [
'model' => $model,
]);
}
}
Attendance models Rules
public function rules()
{
return [
[[ 'staff_id'], 'integer'],
[['daytime'], 'safe'],
[['staff_id'], 'required'],
[['status','time_in', 'time_out'], 'string', 'max' => 45]
];
}
i am new in yii2.
Many thanks in advance.
What you need to do is create another rule inside your Attendance model.
[['time_in', 'time_out'], 'filter', 'filter' => function ($value) {
if($this->status_id == AbsentStatus->status_id)
{
return null;
}
return $value;
}],
This way, if the status_id is equal to the AbsentStatus, you set the value of time_in and time_out as null.
Edit: you should substitute 'AbsentStatus->status_id' in the condition to the value of the id of your absent status.
I think one problem is the html id name fo the fields
In Yii2 the html id of an input field inside an active form is, by default, formed automatically in the format 'classname-fieldname' (all lowercase).
eg: namimg the model class = "Customer" the filed name is like
<input type="text" id="customer-name" class="form-control" name="Customer[name]" maxlength="16">
Then your field id should named 'attendance-status_id' , 'attendance-timein_id', and so on...
Try using this format for the html id
And second, just for test, modify your controller this way
if ($model->load(Yii::$app->request->post()) && $model->save(false)) {
adding false to save() in saving process are not involved the validation rules.