yii2 Unique Validation(non-ajax) not working - validation

I see some links says that Yii2 unique validation is for Ajax validation only(But I dont find any best practice to follow.).So I'm asking this for non ajax validation in Yii2
my model rules are
['name', 'unique', 'targetAttribute' => 'function_id','message' => 'name must be unique.'],
My controller functions are normal actionCreate()
Anybody have solution for this? Thanks in Advance
Edit: For Ajax
ok.I Did,My controller code is now
$model = new JobFunctionRole();
$model->scenario = 'insert';
$jobFunction=JobFunction::find()->all();
if(Yii::$app->request->post()){
if (Yii::$app->request->isAjax && $model->load(Yii::$app->request->post())) {
Yii::$app->response->format = Response::FORMAT_JSON;
return ActiveForm::validate($model);
}
if ($model->save()) {
return $this->redirect(['view', 'id' => $model->job_function_role_id]);
}
} else {
return $this->render('create', [
'model' => $model,'jobFunction'=>$jobFunction
]);
}`
But page redirects and shows blank page.

Could be you must check for both togheter
['a1', 'unique', 'targetAttribute' => ['a1', 'a2']]
[
'name', 'unique',
'targetAttribute' => ['name','function_id'],
'message' => 'name must be unique.'
],

Related

Laravel Many to one in Resource

I use laravel 8 & have 3 table:
Products, ProductPrice & ProductsPublisher:
this is my Products model for this relationship:
public function lastPrice(){
return $this->hasMany(ProductPrice::class)->where('status','active')->orderBy('created_at','DESC')->distinct('publisher_id');
}
and this is my productsPrice model for publisher relationship:
public function getPublisher(){
return $this->belongsTo(ProductsPublisher::class,'publisher_id');
}
now, i want to use laravel resource for my api, i wrote products resource:
public function toArray($request)
{
return [
'id' => $this->id,
'price' => lastPrice::make($this->lastPrice),
'status' => $this->status,
'slug' => $this->slug,
'title' => $this->title,
'description' => $this->description,
'txt' => $this->txt,
'lang' => $this->lang,
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
];
but in lastPrice resource, when i wrote like this:
return [
'id' => $this->id,
'main_price' => $this->main_price
];
it give me this error:
Property [id] does not exist on this collection instance.
when i use this code:
return parent::toArray($request);
get response but because i need to use another relationship in my lastPirce for publishers, i cant use that code and should return separately my data.
What i should to do?
thanks
Edit 1:
this is my Controller Code:
$products = Product::where('id',$id)->where('slug',$slug)->where('status','confirm')->first();
if(!$products){
return $this->sendError('Post does not exist.');
}else{
return $this->sendResponse(new \App\Http\Resources\Products\Products($products), 'Posts fetched.');
}
and this is sendResponse & sendError:
public function sendResponse($result, $message)
{
$response = [
'success' => true,
'data' => $result,
'message' => $message,
];
return response()->json($response, 200);
}
public function sendError($error, $errorMessages = [], $code = 404)
{
$response = [
'success' => false,
'message' => $error,
];
if(!empty($errorMessages)){
$response['data'] = $errorMessages;
}
return response()->json($response, $code);
}
thanks.
Edit 2:
i change my lastPrice Resource toArray function to this and my problem solved, but i think this isn't a clean way, any better idea?
$old_data = parent::toArray($request);
$co = 0;
$new_data = [];
foreach ($old_data as $index){
$publisher_data = Cache::remember('publisher'.$index['publisher_id'], env('CACHE_TIME_LONG') , function () use ($index) {
return ProductsPublisher::where('id' , $index['publisher_id'])->first();
});
$new_data[$co]['main_prices'] = $index['main_price'];
$new_data[$co]['off_prices'] = $index['off_price'];
$new_data[$co]['publisher'] = SinglePublisher::make($publisher_data);
$new_data[$co]['created_at'] = $index['created_at'];
$co++;
}
return $new_data;

Validate json object key in laravel request file

I have below type of json in my laravel request, I want to validate json object key in my laravel request file. I want to validate title value is required of data json. I found solution but it's for controller, I want to validate it in my request file
{"ID":null,"name":"Doe","first-name":"John","age":25,"data":[{"title":"title1","titleval":"title1_val"},{"title":"title2","titleval":"title2_val"}]}
Why not use Validator
$data = Validator::make($request->all(), [
'ID' => ['present', 'numeric'],
'name' => ['present', 'string', 'min:0'],
'first-name' => ['present', 'string', 'min:0',],
'age' => ['present', 'numeric', 'min:0', 'max:150'],
'data' => ['json'],
]);
if ($data->fails()) {
$error_msg = "Validation failed, please reload the page";
return Response::json($data->errors());
}
$json_validation = Validator::make(json_decode($request->input('data')), [
'title' => ['present', 'string', 'min:0']
]);
if ($json_validation->fails()) {
$error_msg = "Json validation failed, please reload the page";
return Response::json($json_validation->errors());
}
public function GetForm(Request $request)
{
return $this->validate(
$request,
[
'title' => ['required'],
],
[
'title.required' => 'title is required, please enter a title',
]
);
}
public function store(Request $request)
{
$FormObj = $this->GetForm($request);
$FormObj['title'] = 'stackoveflow'; // custom title
$result = Project::create($FormObj); // Project is a model name
return response()->json([
'success' => true,
'message' => 'saved successfully',
'saved_objects' => $result,
], 200);
}

How to use unique validation in Yii 2

I want to make usernames and email addresses unique.
I am using yii base to develop my App. It doesnt not work for me.
My Model:
public function rules()
{
return [
[['username', 'email', 'password'], 'required'],
[['username', 'email'], 'unique']
];
}
My Controller:
public function actionCreate()
{
$model = new Userapp();
$post = Yii::$app->request->post('UserApp');
if (Yii::$app->request->isPost && $model->validate()) {
$model->email = $post['email'];
$model->username = $post['username'];
$model->password = $model->setPassword($post['password']);
if($model->save()){
return $this->redirect(['view', 'id' => $model->id]);
}
}
return $this->render('create', [
'model' => $model,
]);
}
Yii2 has a bunch of built in validators see.
One of which is unique
From Yii2 docs.
// a1 needs to be unique in the column represented by the "a1" attribute
['a1', 'unique'],
// a1 needs to be unique, but column a2 will be used to check the uniqueness
of the a1 value
['a1', 'unique', 'targetAttribute' => 'a2'],
Update:
In your rules array, add the unique validator to email and username like so:
public function rules()
{
return [
[['username', 'email', 'password'], 'required'],
[['username', 'email'], 'unique'],
];
}
Then before saving the model:
if(!$model->validate()){
return false;
}
Update 2:
You are trying to validate the model before any attributes have been assigned. Update your controller code to the following:
public function actionCreate()
{
$model = new Userapp();
$post = Yii::$app->request->post('UserApp');
if (Yii::$app->request->isPost) {
$model->email = $post['email'];
$model->username = $post['username'];
$model->password = $model->setPassword($post['password']);
if($model->validate() && $model->save()){
return $this->redirect(['view', 'id' => $model->id]);
}
else {
return false;
}
}
return $this->render('create', [
'model' => $model,
]);
}
the idea was to do a re-direction only when $model->save() is true otherwise render back the original model to be created/updated

Test the exist validator in Yii2 without database with mockeryBuilder()

I want to test my AR model without connect to database in Yii 2 so I use mockBuilder() but I dont know how can I pass the mock object to the model exist validator, for example:
class Comment extends ActiveRecord
{
public function rules()
{
return [
[['id', 'user_id', 'post_id'], 'comment'],
['comment', 'string',
'max' => 200
],
['user_id', 'exist',
'targetClass' => User::className(),
'targetAttribute' => 'id'
],
['post_id', 'exist',
'targetClass' => Post::className(),
'targetAttribute' => 'id'
]
];
}
}
class CommentTest extends TestCase
{
public function testValidateCorrectData()
{
$user = $this->getMockBuilder(User::className())
->setMethods(['find'])
->getMock();
$user->method('find')->willReturn(new User([
'id' => 1
]));
$post = $this->getMockBuilder(Post::className())
->setMethods(['find'])
->getMock();
$post->method('find')->willReturn(new Post([
'id' => 1
]));
// How can I pass to $user and $post to exist validator in Comment model?
$comment = new Comment([
'user_id' => 1,
'post_id' => 1,
'comment' => 'test...'
]);
expect_that($comment->validate());
}
}
ok, It's not a best code just I'd like to introduce what I want to do.
Yii2 ExistValidator uses ActiveQuery::exists() for check existence and you should replace generated validator to mockobject where the method createQuery returns mockobject of ActiveQuery where ::exists() return something you want (true/false) e.g.
$activeQueryMock = $this->getMockBuilder(ActiveQuery::className())
->disableOriginalConstructor()
->setMethods(['exists'])
->getMock();
$activeQueryMock->expects($this->any())
->method('exists')
->willReturn($value); //Your value here true/false
$model = $this->getMockBuilder(Comment::className())
->setMethods(['getActiveValidators'])
->getMock();
$model->expects($this->any())
->method('getActiveValidators')
->willReturnCallback(function () use ($activeQueryMock) {
$validators = (new Comment())->activeValidators;
foreach ($validators as $key => $validator) {
if (($validator instanceof ExistValidator) && ($validator->attributes = ['user_id'])) {
$mock = $this->getMockBuilder(ExistValidator::className())
->setConstructorArgs(['config' => get_object_vars($validator)])
->setMethods(['createQuery'])
->getMock();
$mock->expects($this->any())
->method('createQuery')
->willReturn($activeQueryMock);
$validators[$key] = $mock;
break;
}
}
return $validators;
});
$model->validate();

How to Use unique rules in active record yii2

I want to set the values of my table column set as unique value, how i can use to set error if in insert form, I insert the same value as data in my database?
Is it true?
public function rules()
{
return [
[['nama_barang', 'harga', 'stok', 'id_satuan'], 'required'],
[['harga', 'stok', 'id_satuan'], 'integer'],
['nama_barang', 'unique', 'targetAttribute' => ['nama_barang' => 'nama_barang']],
[['foto'], 'safe']
];
}
Remember: model, view, controller.
Model
add unique validator in your model rules like
...
[['nama_barang'], 'unique'],
...
View
Enable ajax validation in your form view
...
<?php $form = ActiveForm::begin(['enableAjaxValidation' => true]); ?>
...
Controller
Add ajax validation in your controller
Create Action
...
public function actionCreate()
{
$model = new Product();
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())) {
...
and Update Action
...
public function actionUpdate($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())) {
...
PS: if not present, add required classes in your controller.
use yii\web\Response;
use yii\widgets\ActiveForm;
Try this way
public function rules()
{
return [
[['nama_barang', 'harga', 'stok', 'id_satuan'], 'required'],
[['harga', 'stok', 'id_satuan'], 'integer'],
['nama_barang', 'unique', 'targetAttribute' => ['nama_barang'], 'message' => 'Username must be unique.'],
[['foto'], 'safe']
];
}
Just set unique in the rules [['name'], 'unique'],
Below is the complete function.
public function rules()
{
return [
[['name', 'description', 'comp_id'], 'required'],
[['description'], 'string'],
[['comp_id'], 'integer'],
[['name'], 'string', 'max' => 100,],
[['name'], 'unique'],
[['comp_id'], 'exist', 'skipOnError' => true, 'targetClass' => Company::className(), 'targetAttribute' => ['comp_id' => 'comp_id']],
];
}
I had a similar problem whereby when I insert a record with an existing unique field the framework remained silent returning my view back without any error.
So, the trick around this was to do a success-redirect only when $model->save() has a boolean value of true, else render back the _form.php through your view.php

Resources