So i reached the Ajax validation part. First i want to say that i read the answers of similar question but it did not helped me.
On registration form validation works good(when i try to register user with existing name it shows me error message), but when i am in the users profile and try to update his name with existing one nothing happens(no error shown).
My model UpdateForm.php rules:
public function rules()
{
return [
[['email', 'password', 'username'], 'required'],
[['email', 'password', 'username'], 'string', 'max' => 50],
[['image'], 'string', 'max' => 255],
['email', 'email'],
[[ 'email', 'username'], 'unique'],
];
}
My UserController action:
public function actionUpdate()
{
$id = \Yii::$app->user->identity->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);
}
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return $this->redirect(['view', 'id' => $model->id]);
} else {
return $this->render('update', [
'model' => $model,
]);
}
}
Will appreciate every advice!
configure yii_logger db in your machine (you can find it Yii2 docs).
then run
SELECT FROM_UNIXTIME(log_time, '%Y-%m-%d') log_date, y.* FROM yii_logger y where level = 1 order by log_time desc limit 20;
you may see error backtrace if your code is breaking somewhere.
Related
I was browsing through the web and looking for solution on how can I modify this error message on Jetstream login:
Inside app/Actions/Fortify there is a file CreateNewUser.php where I can put some validation custom message on each field like this:
public function create(array $input)
{
Validator::make($input, [
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
'phone' => ['required', 'string', 'max:17'],
'password' => $this->passwordRules(),
'terms' => Jetstream::hasTermsAndPrivacyPolicyFeature() ? ['required', 'accepted'] : '',
],[
'name.required'=>'Name is required',
'email.required'=>'Email is required',
'phone.required'=>'Phone is required',
])->validate();
However, there is none for Login.php. I search the web and saw something about vendors/laravel/fortify/src/Actions/AttemptToAuthenticate.php but its consist with lots of code where I don't know where to put the customization:
public function handle($request, $next)
{
if (Fortify::$authenticateUsingCallback) {
return $this->handleUsingCustomCallback($request, $next);
}
if ($this->guard->attempt(
$request->only(Fortify::username(), 'password'),
$request->filled('remember'))
) {
return $next($request);
}
$this->throwFailedAuthenticationException($request);
}
Is there an easy way to customize the "The email field is required" to a different custom message in Laravel 8?
Been stuck for a couple of hours.
You can customize FortifyServiceProvider inside App > Providers by using the Fortify::authenticateUsing method and it should be called from the boot method.
public function boot()
{
Fortify::authenticateUsing(function (Request $request) {
$user = User::where('email', $request->email)->first();
if ($user &&
Hash::check($request->password, $user->password)) {
return $user;
} else {
$request->session()->flash('message', 'Invalid!');
return false;
}
});
}
Reference
step 1 go to vendor\laravel\fortify\src\Http\Requests\LoginRequest.php
step 2 in the loginRequest.php you will find two method
public function authorize()
{
return true;
}
public function rules()
{
return [
Fortify::username() => 'required|string',
'password' => 'required|string',
];
}
step 3 add the following method below
public function messages() {
return = [
'email.required' => 'email required',
'password.required' => 'password required'
];
}
Now, i have an update form with three inputs - username, email and password. Everything is ok except the case when i try to update only the password.
For example: Username and email of the user have to stay the same and only the password must be changed. And here what is happening:
In this case i am trying to update only the password of the user.
Controller actionUpdate:
public function actionUpdate()
{
$model = new UpdateForm();
$id = \Yii::$app->user->identity->id;
$user = $this->findModel($id);
//default values
$model->username = $user->username;
$model->email = $user->email;
if (Yii::$app->request->isAjax && $model->load(Yii::$app->request->post())) {
Yii::$app->response->format = Response::FORMAT_JSON;
return ActiveForm::validate($model);
}
if (isset($_POST['UpdateForm']))
{
$model->attributes = $_POST['UpdateForm'];
if($model->validate())
{
$user->username = $model->username;
$user->email = $model->email;
$user->password = md5($model->password);
$user->update();
$this->redirect(['view', 'id' => $user->id]);
}
}
else
{
return $this->render('update', [
'model' => $model,
]);
}
}
UpdateForm model rules:
public function rules()
{
return [
[['email', 'password', 'username'], 'required'],
[['email', 'password', 'username'], 'string', 'max' => 50],
[['image'], 'string', 'max' => 255],
[['username', 'password', 'email'], 'trim'],
['email', 'email'],
[[ 'email', 'username'], 'unique',
'targetAttribute' => ['email', 'username'],
'message' => 'The combination of username and password is already taken'],
];
}
Appreciating every advice! Thank you in advance!
Try using save() instead of update()
if (isset($_POST['UpdateForm']))
{
$model->attributes = $_POST['UpdateForm'];
if($model->validate())
{
$user->username = $model->username;
$user->email = $model->email;
$user->password = md5($model->password);
$user->save();
$this->redirect(['view', 'id' => $user->id]);
}
}
How can i sidestep current username and password of the user when updating his information? For example - when i try to update only the name it shows me that email is already taken and vice versa. That way i can not update only the or only the email, only both of them.
My actionUpdate:
public function actionUpdate()
{
$model = new UpdateForm();
$id = \Yii::$app->user->identity->id;
$user = $this->findModel($id);
//default values
$model->username = $user->username;
$model->email = $user->email;
if (Yii::$app->request->isAjax && $model->load(Yii::$app->request->post())) {
Yii::$app->response->format = Response::FORMAT_JSON;
return ActiveForm::validate($model);
}
if (isset($_POST['UpdateForm']))
{
$model->attributes = $_POST['UpdateForm'];
if($model->validate())
{
$user->username = $model->username;
$user->email = $model->email;
$user->password = md5($model->password);
$user->update();
$this->redirect(['view', 'id' => $user->id]);
}
}
else
{
return $this->render('update', [
'model' => $model,
]);
}
}
My UpdateForm rules:
public function rules()
{
return [
[['email', 'password', 'username'], 'required'],
[['email', 'password', 'username'], 'string', 'max' => 50],
[['image'], 'string', 'max' => 255],
[['username', 'password', 'email'], 'trim'],
['email', 'email'],
[[ 'email', 'username'], 'unique'],
];
}
Thank you in advance!
you should use both for unique
eg:
// a1 and a2 need to be unique together, and they both will receive error message
[['a1', 'a2'], 'unique', 'targetAttribute' => ['a1', 'a2']]
in your case
[[ 'email', 'username'], 'unique', 'targetAttribute' => ['email', 'username']],
http://www.yiiframework.com/doc-2.0/yii-validators-uniquevalidator.html
If you want to update the fields one at a time. You need to remove the required fields. He then checks that 3 must exist. Delete this line:
[['email', 'password', 'username'], 'required'],
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 got this error when an image file is required: "Preview cannot be blank". Although I filled this field.
My rules:
public function rules()
{
return [
[['name', 'preview', 'date', 'author_id'], 'required', 'on' => 'update'],
[['name', 'preview', 'date', 'author_id'], 'required', 'on' => 'create'],
[['date_create', 'date_update', 'author_id'], 'integer'],
[['preview'], 'file', 'skipOnEmpty' => 'false', 'extensions' => 'png, jpg, jpeg'],
[['date'], 'safe'],
[['name'], 'string', 'max' => 255]
];
}
Controller:
public function actionCreate()
{
$model = new Book();
$model->scenario = 'create';
if ($model->load(Yii::$app->request->post()) && $model->validate()) {
$model->preview = UploadedFile::getInstance($model, 'preview');
if ($model->save() && $model->preview->saveAs('uploads/' . $model->preview->baseName . '.' . $model->preview->extension))
{
return $this->redirect(['view', 'id' => $model->id]);
}
} else {
return $this->render('create', [
'model' => $model,
]);
}
}
If preview file is not required there is no error and the file is being loaded into the uploads folder.
Best thing to do here is to avoid using the same field for different purposes.
In your case you are overwriting preview with UploadedFile instance, you could create another field for this and then:
$model->previewFile = UploadedFile::getInstance($model, 'preview');
Then the validation invoked by save() won't hit any new issues about preview field as the file is held in previewFile and original value of preview passed through the $model->validate() check already.
I think you can't make this field required, as it only validates $_POST variables inserted. The file upload is entered in the $_FILES superglobal and not in the $_POST superglobal. Requiring this would mean you want it in your $_POST variables.
You run the validation before handling the file upload. So I would recommend handling the file upload before you handle the model validation, so you can set the value to the model and then run validate afterwards:
public function actionCreate()
{
$model = new Book();
$model->load(Yii::$app->request->post());
$model->scenario = 'create';
$model->preview = UploadedFile::getInstance($model, 'preview');
if ($model->validate()) {
if ($model->save() && $model->preview->saveAs('uploads/' . $model->preview->baseName . '.' . $model->preview->extension))
{
return $this->redirect(['view', 'id' => $model->id]);
}
} else {
return $this->render('create', [
'model' => $model,
]);
}
}
I didn't test it locally, but making the 'preview' field required without any info in it is not going to work for sure.
P.S. I think it should be 'skipOnEmpty' => false, not with '' around the false.