Laravel validation: unique rule to bring duplicated record back - mysql

I have not found anywhere a clean way of what I am exactly looking for so thought to give on here a try:
$validator = Validator::make($request->all(), [
'an_id' => 'unique:users,an_id',
'another_id' => 'unique:users,another_id',
'test_id' => 'unique:users,test_id',
]);
if ($validator->fails()) {
//
}
So, what I'd like to do is when a duplicate test_id is provided, is to not only fail but show me which user uses the same test_id.
Is this actually possible through Laravel's Validation?

If I understand correctly, is this what you want to achieve?
Update: maybe you want to get the duplicated user in the view.
Update2: a quick way to get and return the duplicated users, if any.
(Note: I haven't tested the code so maybe slight adjustments are needed)
$validator = Validator::make($request->all(), [
'an_id' => 'unique:users,an_id',
'another_id' => 'unique:users,another_id',
'test_id' => 'unique:users,test_id',
]);
if ($validator->fails()) {
//find the duplicated user
$duplicatedUserX = User::where(
'another_id', $request->input('another_id')
)->get();
$duplicatedUserY = User::where(
'test_id', $request->input('test_id')
)->get();
// add their test_id to error messagebag.
if(!empty($duplicatedUserX){
$validator->errors()
->add('duplicatedUserXId', $duplicatedUserX->id);
}
if(!empty($duplicatedUserY){
$validator->errors()
->add('duplicatedUserYId', $duplicatedUserY->id);
}
// Send duplicated users and messagebag back to View
return redirect()->back()
->with('dupUsers', [
'x' => $duplicatedUserX,
'y' => $duplicatedUserY,
])->withErrors($validator);
}

Related

Yii2 : Require at least one of the two fields

One of the two phone numbers phone_parent or phone_students must be provided AND they must be an integer. When combined, only atLeastValidator works, when I leave it out, the integer works. Out of ideas. Any hint?
[['phone_parent', 'phone_student'], 'integer'],
['phone_student', AtLeastValidator::class, 'in' => ['phone_student', 'phone_parent']],
['phone_parent', AtLeastValidator::class, 'in' => ['phone_student', 'phone_parent']],
update: I've just discovered that integer works when I try to submit (no request is sent yet, I remain on form page); However it should work on focus out - just like all the other validators; It's an instance of ActiveForm.
I don't think you need to have that custom AtLeastValidator, you can use when and whenClient in the following way to work the way you want.
Your rules should look like below
[
['phone_parent'],
'required',
'when' => function ($model) {
return ($model->phone_student == '');
},
'whenClient' => 'function(attribute,value){
return ($("#testform-phone_student").val()=="");
}',
'message' => 'Either Parent or Student Phone must be filled',
],
[
['phone_student'],
'required',
'when' => function ($model) {
return ($model->phone_parent == '');
},
'whenClient' => 'function(attribute,value){
return ($("#testform-phone_parent").val()=="");
}',
'message' => 'Either Parent or Student Phone must be filled',
],
[['phone_parent', 'phone_student'], 'integer'],
Above all i would use a regular expression in order to validate the phone number to be valid rather than just using integer that will allow 0 as a pone number or mobile number which isnt valid. using match validator with a regex in the pattern will make it solid.

How do I make the most effective and efficient logic to check the data in the database exist or not?

I use laravel 5.6
I have a json file containing 500 thousand records. I want to create a logic to check whether the id of each record already exists or not in the database. If it doesn't already exist, then there will be a data insert process. If it already exists, there will be a data update process
I have made logic. I just want to make sure whether my logic is effective or not
My logic code like this :
$path = storage_path('data.json');
$json = json_decode(file_get_contents($path), true);
foreach ($json['value'] as $value) {
$data = \DB::table('details')->where('id', '=', $value['Code'])->get();
if ($data->isEmpty()) {
\DB::table('details')->insert(
[
'id' => $value['Code'],
'number' => $value['Number'],
...
]
);
}
else {
\DB::table('details')
->where('id', '=', $value['Code'])
->update([
'id' => $value['Code'],
'number' => $value['Number'],
...
]);
}
}
The code is working. But the process seems really long
Do you have another solution that is better?
updateOrCreate
You may also come across situations where you want to update an existing model or create a new model if none exists. Laravel provides an updateOrCreate method to do this in one step. Like the firstOrCreate method, updateOrCreate persists the model, so there's no need to call save():
// If there's a flight from Oakland to San Diego, set the price to $99.
// If no matching model exists, create one.
$flight = App\Flight::updateOrCreate(
['departure' => 'Oakland', 'destination' => 'San Diego'],
['price' => 99]
);
in your case your code should be like this (create Details model first) :
$path = storage_path('data.json');
$json = json_decode(file_get_contents($path), true);
foreach ($json['value'] as $value) {
Details::updateOrCreate(
[ 'id' => $value['Code'] ],
[ 'number' => $value['Number'], ... ]
);
}
i think that's the best way to do it. Eloquent return's a collection so you cant just validate that your string is null.

Laravel/PHPUnit: Assert json element exists without defining the value

I'm sending a post request in a test case, and I want to assert that a specific element, let's say with key 'x' exists in the response. In this case, I can't say seeJson(['x' => whatever]); because the value is unknown to me. and for sure, I can't do it with seeJson(['x']);.
Is there a way to solve this?
If it matters:
Laravel: v5.2.31
PHPUnit: 5.3.4
May it will be helpful for anyone else. You can write this test for your check response json structure
$this->post('/api/login/', [
'email' => 'customer3#example.com',
'password' => '123123123',
])->assertJsonStructure([
'status',
'result' => [
'id',
'email',
'full_name',
],
]);
Although it's not optimal at all, I chose to use this code to test the situation:
$this->post(URL, PARAMS)->see('x');
X is a hypothetical name, and the actual element key has a slim chance of popping up in the rest of the data. otherwise this nasty workaround wouldn't be practical.
UPDATE:
Here's the solution to do it properly:
public function testCaseName()
{
$this->post(route('route.name'), [
'param1' => 1,
'param2' => 10,
], [
'headers_if_any' => 'value'
]);
$res_array = (array)json_decode($this->response->content());
$this->assertArrayHasKey('x', $res_array);
}

Yii2: Add 'user_id' when create a post

I have a 'post' table with attribute 'user_id' in it to know who have posted that post. I run into a problem, when create a post, the 'user_id' didn't add into database, which can't be null, so I can't continue from there. So how can I add 'user_id' of the user that is currently logging in, automatically.
I'm using Yii2 basic template.
Thanks
Or you could have a look at Blameable Behavior
BlameableBehavior automatically fills the specified attributes with the current user ID.
I use this in alot of my projects (often combined with sluggable and timeable) and its easy to use, just put the following in your Post model:
use yii\behaviors\BlameableBehavior;
public function behaviors()
{
return [
[
'class' => BlameableBehavior::className(),
'createdByAttribute' => 'user_id',
'updatedByAttribute' => false,
'attributes' => [
ActiveRecord::EVENT_BEFORE_VALIDATE => ['user_id'] // If usr_id is required
]
],
];
}
Referencing Behavior validation on validation behaviors.
If you want to do it manually like the other answers suggest, you need to change
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return $this->redirect(['view', 'id' => $model->id]);
}
to
if ($model->load(Yii::$app->request->post()) && $model->validate()) {
$model->user_id = \Yii::$app->user->identity->id
$model->save()
return $this->redirect(['view', 'id' => $model->id]);
}
Remember: when you validate before inputting the user id, the user_id can't be required in your model rules!
Apart from what Bloodhound suggest, you can also use the following code to get the currently logged in user ID:
$loggedInUserId = \Yii::$app->user->getId();
you can try this code
//To get whole logged user data
$user = \Yii::$app->user->identity;
//To get id of the logged user
$userId = \Yii::$app->user->identity->id
Look at the documentation for more details: doc .

Yii 2 Gridview - Search Query generates ambiguous fields

I am generating related records search query for Gridview use
I get this error :
SQLSTATE[23000]: Integrity constraint violation: 1052 Column 'dbowner' in where clause is ambiguous
The SQL being executed was: SELECT COUNT(*) FROM tbl_iolcalculation LEFT JOIN tbl_iolcalculation patient ON tbl_iolcalculation.patient_id = patient.id WHERE (dbowner=1) AND (dbowner=1)
I have two related models 1) iolcalculation and patient - each iolcalculation has one patient (iolcalculation.patient_id -> patient.id)
The relevant code in my model IolCalculationSearch is :
public function search($params)
{
$query = IolCalculation::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
$dataProvider->sort->attributes['patient.lastname'] = [
'asc' => ['patient.lastname' => SORT_ASC],
'desc' => ['patient.lastname' => SORT_DESC],
];
$query->joinWith(['patient'=> function($query) { $query->from(['patient'=>'tbl_iolcalculation']); } ]);
if (!($this->load($params) && $this->validate())) {
return $dataProvider;
}
$query->andFilterWhere([
'id' => $this->id,
'patient_id' => $this->patient_id,
'preop_id' => $this->preop_id,
'calculation_date' => $this->calculation_date,
'iol_calculated' => $this->iol_calculated,
The reason this error is generated is that each model has an override to the default Where clause as follows, the reason being that multiple users data needs to be segregated from other users, by the field dbowner:
public static function defaultWhere($query) {
parent::init();
$session = new Session();
$session->open();
$query->andWhere(['t.dbowner' => $session['dbowner']]);
}
this is defined in a base model extending ActiveRecord, and then all working models extend this base model
How Can I resolve this ambiguous reference in the MySQL code?
Thanks in advance
$query->andFilterWhere([
// previous filters
self::tableName() . '.structure_id' => $this->structure_id,
// next filters
]);
I think, that you are searching for table aliases.
(https://github.com/yiisoft/yii2/issues/2377)
Like this, of course you have to change the rest of your code:
$query->joinWith(['patient'=> function($query) { $query->from(['patient p2'=>'tbl_iolcalculation']); } ]);
The only way I can get this to work is to override the default scope find I had set up for most models, so that it includes the actual table name as follows - in my model definition:
public static function find() {
$session = new Session();
$session->open();
return parent::find()->where(['tbl_iolcalculation.dbowner'=> $session['dbowner']]);
}
There may be a more elegant way using aliases, so any advice would be appreciated - would be nice to add aliases to where clauses, and I saw that they are working on this....