laravel pivot table unique - php

order_id....product_id....product_quantity....created_at....updated_at
this is my pivot table...In my OrderRequest table I want to assign product_id as unique. But when I write like this;
public function rules()
{
return [
'product_id' => 'unique:order_product,product_id'
];
}
I encounter a problem. product_id becomes unique. but not only in an order, it becomes totally unique. I want to use this product_id in other orders but I can't. what can I do? How can I assign product_id as unique for each order_id values?

In your controller assuming that you call saveProducts method so :
function saveProducts($request){
validateProductList($request->input('product_list'))
$order->product()
->updateExistingPivot($product_id[$i],
array(
'product_quantity' => $product_quantity[$i],
'product_status' => $product_status[$i],
'updated_at' => Carbon::now() ));
// ....
}
function validateProductList($productIds){
if(isProductIdDuplicated($productIds)){
$error = 'You have a duplicated product in your Order, please edit it'
return redirectBack()-withError();
}
}
function isProductIdDuplicated($productIds){
$occureces_array = productIds();
foreach($productIds as $id){
if(++$occureces_array[$id] > 1){
return true;
}
}
return false;
}
And in your view you have access to this $error variable.

Thank you for your help. I have ended up the issue and it works now...
this is a part of my view;
<div class="grid1">
{!! Form::label('product_list'.$product_row, Lang::get('home.Select Product')) !!}
</div>
<div class="grid2 searchDrop">
{!! Form::select('product_list[]', $product_list, null, ['style'=>'width:150px;'])!!}
and this is part of my controller;
public function store(OrderRequest $request)
{
$order = Order::create( $request->all());
$product_list= $request->input('product_list');
$product_quantity = $request->input('product_quantity');
$product_status = $request->input('product_status' );
/* attach pivot table */
$order->product()->attach($product_list);
/* get the product list as array */
foreach($product_list as $key => $product_id)
{
$order->product()->updateExistingPivot($product_id, array(
'product_quantity' => $product_quantity[$key], // product_quantity is array
'product_status' => $product_status[$key], // product_status is array
'updated_at' => Carbon::now()
));
}
flash(Lang::get('home.The order has been created!'));
return redirect(url('/admin/orders/details',$order->id))->with('flash_message');
}
this is my OrderRequest;
public function rules()
{
return [
'customer_id' => 'required',
'product_quantity.*' =>'not_in:0',
'product_list' => 'product_unique', //custom validation in AppServiceProvider
];
}
and this is my AppServiceProvider;
public function boot()
{
Validator::extend('product_unique', function($attribute, $value, $parameters, $validator) {
if ( count(array_unique($value))!=count($value) ) {
return false;
}
return true;
});
}
Finally, in my validation.php I added;
"product_unique" => "Please select a product only once!",

Related

`does not write information to the database`

does not save to database
help me understand my mistake
Controller
public function store(Request $request)
{
$item = Cart::where('product_id', $request->product_id);
if ($item->count()) {
$item->increment('quantity');
$item = $item->first();
} else {
$item = Cart::forceCreate([
'product_id' => $request->product_id,
'quantity' => 1,
]);
}
return response()->json([
'quantity' => $item->quantity,
'product' => $item->product
]);
}
Store
addProductToCart (product, quantity) {
axios.post('http://127.0.0.1:8000/api/cart', {
product_id: product.id,
quantity
})
},
when clicking on the addItems(for instance) button, the items are not added to the database
my mutation happened to be in the wrong module
add_to_cart(state, {product, quantity}) {
let productInCart = state.cart.find(item => {
return item.product.id === product.id;
});
if (productInCart) {
productInCart.quantity += quantity;
return;
}
state.cart.push({
product,
quantity
})
},

Can i ignore unique value when update record laravel 5.8? [duplicate]

I have a Laravel User model which has a unique validation rule on username and email. In my Repository, when I update the model, I revalidate the fields, so as to not have a problem with required rule validation:
public function update($id, $data) {
$user = $this->findById($id);
$user->fill($data);
$this->validate($user->toArray());
$user->save();
return $user;
}
This fails in testing with:
ValidationException: {"username":["The username has already been
taken."],"email":["The email has already been taken."]}
Is there a way of fixing this elegantly?
Append the id of the instance currently being updated to the validator.
Pass the id of your instance to ignore the unique validator.
In the validator, use a parameter to detect if you are updating or creating the resource.
If updating, force the unique rule to ignore a given id:
//rules
'email' => 'unique:users,email_address,' . $userId,
If creating, proceed as usual:
//rules
'email' => 'unique:users,email_address',
Another elegant way...
In your model, create a static function:
public static function rules ($id=0, $merge=[]) {
return array_merge(
[
'username' => 'required|min:3|max:12|unique:users,username' . ($id ? ",$id" : ''),
'email' => 'required|email|unique:member'. ($id ? ",id,$id" : ''),
'firstname' => 'required|min:2',
'lastname' => 'required|min:2',
...
],
$merge);
}
Validation on create:
$validator = Validator::make($input, User::rules());
Validation on update:
$validator = Validator::make($input, User::rules($id));
Validation on update, with some additional rules:
$extend_rules = [
'password' => 'required|min:6|same:password_again',
'password_again' => 'required'
];
$validator = Validator::make($input, User::rules($id, $extend_rules));
Nice.
Working within my question:
public function update($id, $data) {
$user = $this->findById($id);
$user->fill($data);
$this->validate($user->toArray(), $id);
$user->save();
return $user;
}
public function validate($data, $id=null) {
$rules = User::$rules;
if ($id !== null) {
$rules['username'] .= ",$id";
$rules['email'] .= ",$id";
}
$validation = Validator::make($data, $rules);
if ($validation->fails()) {
throw new ValidationException($validation);
}
return true;
}
is what I did, based on the accepted answer above.
EDIT: With Form Requests, everything is made simpler:
<?php namespace App\Http\Requests;
class UpdateUserRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'name' => 'required|unique:users,username,'.$this->id,
'email' => 'required|unique:users,email,'.$this->id,
];
}
}
You just need to pass the UpdateUserRequest to your update method, and be sure to POST the model id.
Unique Validation With Different Column ID In Laravel
'UserEmail'=>"required|email|unique:users,UserEmail,$userID,UserID"
or what you could do in your Form Request is (for Laravel 5.3+)
public function rules()
{
return [
'email' => 'required|email|unique:users,email,'. $this->user
//here user is users/{user} from resource's route url
];
}
i've done it in Laravel 5.6 and it worked.
'email' => [
'required',
Rule::exists('staff')->where(function ($query) {
$query->where('account_id', 1);
}),
],
'email' => [
'required',
Rule::unique('users')->ignore($user->id)->where(function ($query) {
$query->where('account_id', 1);
})
],
Laravel 5 compatible and generic way:
I just had the same problem and solved it in a generic way. If you create an item it uses the default rules, if you update an item it will check your rules for :unique and insert an exclude automatically (if needed).
Create a BaseModel class and let all your models inherit from it:
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class BaseModel extends Model {
/**
* The validation rules for this model
*
* #var array
*/
protected static $rules = [];
/**
* Return model validation rules
*
* #return array
*/
public static function getRules() {
return static::$rules;
}
/**
* Return model validation rules for an update
* Add exception to :unique validations where necessary
* That means: enforce unique if a unique field changed.
* But relax unique if a unique field did not change
*
* #return array;
*/
public function getUpdateRules() {
$updateRules = [];
foreach(self::getRules() as $field => $rule) {
$newRule = [];
// Split rule up into parts
$ruleParts = explode('|',$rule);
// Check each part for unique
foreach($ruleParts as $part) {
if(strpos($part,'unique:') === 0) {
// Check if field was unchanged
if ( ! $this->isDirty($field)) {
// Field did not change, make exception for this model
$part = $part . ',' . $field . ',' . $this->getAttribute($field) . ',' . $field;
}
}
// All other go directly back to the newRule Array
$newRule[] = $part;
}
// Add newRule to updateRules
$updateRules[$field] = join('|', $newRule);
}
return $updateRules;
}
}
You now define your rules in your model like you are used to:
protected static $rules = [
'name' => 'required|alpha|unique:roles',
'displayName' => 'required|alpha_dash',
'permissions' => 'array',
];
And validate them in your Controller. If the model does not validate, it will automatically redirect back to the form with the corresponding validation errors. If no validation errors occurred it will continue to execute the code after it.
public function postCreate(Request $request)
{
// Validate
$this->validate($request, Role::getRules());
// Validation successful -> create role
Role::create($request->all());
return redirect()->route('admin.role.index');
}
public function postEdit(Request $request, Role $role)
{
// Validate
$this->validate($request, $role->getUpdateRules());
// Validation successful -> update role
$role->update($request->input());
return redirect()->route('admin.role.index');
}
That's it! :) Note that on creation we call Role::getRules() and on edit we call $role->getUpdateRules().
I have BaseModel class, so I needed something more generic.
//app/BaseModel.php
public function rules()
{
return $rules = [];
}
public function isValid($id = '')
{
$validation = Validator::make($this->attributes, $this->rules($id));
if($validation->passes()) return true;
$this->errors = $validation->messages();
return false;
}
In user class let's suppose I need only email and name to be validated:
//app/User.php
//User extends BaseModel
public function rules($id = '')
{
$rules = [
'name' => 'required|min:3',
'email' => 'required|email|unique:users,email',
'password' => 'required|alpha_num|between:6,12',
'password_confirmation' => 'same:password|required|alpha_num|between:6,12',
];
if(!empty($id))
{
$rules['email'].= ",$id";
unset($rules['password']);
unset($rules['password_confirmation']);
}
return $rules;
}
I tested this with phpunit and works fine.
//tests/models/UserTest.php
public function testUpdateExistingUser()
{
$user = User::find(1);
$result = $user->id;
$this->assertEquals(true, $result);
$user->name = 'test update';
$user->email = 'ddd#test.si';
$user->save();
$this->assertTrue($user->isValid($user->id), 'Expected to pass');
}
I hope will help someone, even if for getting a better idea. Thanks for sharing yours as well.
(tested on Laravel 5.0)
A simple example for roles update
// model/User.php
class User extends Eloquent
{
public static function rolesUpdate($id)
{
return array(
'username' => 'required|alpha_dash|unique:users,username,' . $id,
'email' => 'required|email|unique:users,email,'. $id,
'password' => 'between:4,11',
);
}
}
.
// controllers/UsersControllers.php
class UsersController extends Controller
{
public function update($id)
{
$user = User::find($id);
$validation = Validator::make($input, User::rolesUpdate($user->id));
if ($validation->passes())
{
$user->update($input);
return Redirect::route('admin.user.show', $id);
}
return Redirect::route('admin.user.edit', $id)->withInput()->withErrors($validation);
}
}
If you have another column which is being used as foreign key or index then you have to specify that as well in the rule like this.
'phone' => [
"required",
"phone",
Rule::unique('shops')->ignore($shopId, 'id')->where(function ($query) {
$query->where('user_id', Auth::id());
}),
],
I am calling different validation classes for Store and Update. In my case I don't want to update every fields, so I have baseRules for common fields for Create and Edit. Add extra validation classes for each. I hope my example is helpful. I am using Laravel 4.
Model:
public static $baseRules = array(
'first_name' => 'required',
'last_name' => 'required',
'description' => 'required',
'description2' => 'required',
'phone' => 'required | numeric',
'video_link' => 'required | url',
'video_title' => 'required | max:87',
'video_description' => 'required',
'sex' => 'in:M,F,B',
'title' => 'required'
);
public static function validate($data)
{
$createRule = static::$baseRules;
$createRule['email'] = 'required | email | unique:musicians';
$createRule['band'] = 'required | unique:musicians';
$createRule['style'] = 'required';
$createRule['instrument'] = 'required';
$createRule['myFile'] = 'required | image';
return Validator::make($data, $createRule);
}
public static function validateUpdate($data, $id)
{
$updateRule = static::$baseRules;
$updateRule['email'] = 'required | email | unique:musicians,email,' . $id;
$updateRule['band'] = 'required | unique:musicians,band,' . $id;
return Validator::make($data, $updateRule);
}
Controller:
Store method:
public function store()
{
$myInput = Input::all();
$validation = Musician::validate($myInput);
if($validation->fails())
{
$key = "errorMusician";
return Redirect::to('musician/create')
->withErrors($validation, 'musicain')
->withInput();
}
}
Update method:
public function update($id)
{
$myInput = Input::all();
$validation = Musician::validateUpdate($myInput, $id);
if($validation->fails())
{
$key = "error";
$message = $validation->messages();
return Redirect::to('musician/' . $id)
->withErrors($validation, 'musicain')
->withInput();
}
}
public static function custom_validation()
{
$rules = array('title' => 'required ','description' => 'required','status' => 'required',);
$messages = array('title.required' => 'The Title must be required','status.required' => 'The Status must be required','description.required' => 'The Description must be required',);
$validation = Validator::make(Input::all(), $rules, $messages);
return $validation;
}
I had the same problem.
What I've done: add in my view hidden field with id of a model and in validator check the unique, only if I've get some id from view.
$this->validate(
$request,
[
'index' => implode('|', ['required', $request->input('id') ? '' : 'unique:members']),
'name' => 'required',
'surname' => 'required',
]
);
You can trying code bellow
return [
'email' => 'required|email|max:255|unique:users,email,' .$this->get('id'),
'username' => 'required|alpha_dash|max:50|unique:users,username,'.$this->get('id'),
'password' => 'required|min:6',
'confirm-password' => 'required|same:password',
];
Laravel 5.8 simple and easy
you can do this all in a form request with quite nicely. . .
first make a field by which you can pass the id (invisible) in the normal edit form. i.e.,
<div class="form-group d-none">
<input class="form-control" name="id" type="text" value="{{ $example->id }}" >
</div>
...
Then be sure to add the Rule class to your form request like so:
use Illuminate\Validation\Rule;
... Add the Unique rule ignoring the current id like so:
public function rules()
{
return [
'example_field_1' => ['required', Rule::unique('example_table')->ignore($this->id)],
'example_field_2' => 'required',
];
... Finally type hint the form request in the update method the same as you would the store method, like so:
public function update(ExampleValidation $request, Examle $example)
{
$example->example_field_1 = $request->example_field_1;
...
$example->save();
$message = "The aircraft was successully updated";
return back()->with('status', $message);
}
This way you won't repeat code unnecessarily :-)
public function rules()
{
if ($this->method() == 'PUT') {
$post_id = $this->segment(3);
$rules = [
'post_title' => 'required|unique:posts,post_title,' . $post_id
];
} else {
$rules = [
'post_title' => 'required|unique:posts,post_title'
];
}
return $rules;
}
For a custom FormRequest and Laravel 5.7+ you can get the id of your updated model like this:
public function rules()
{
return [
'name' => 'required|min:5|max:255|unique:schools,name,'.\Request::instance()->id
];
}
For anyone using a Form request
In my case i tried all of the following none of them worked:
$this->id, $this->user->id, $this->user.
It was because i could not access the model $id nor the $id directly.
So i got the $id from a query using the same unique field i am trying to validate:
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
$id = YourModel::where('unique_field',$this->request->get('unique_field'))->value('id');
return [
'unique_field' => ['rule1','rule2',Rule::unique('yourTable')->ignore($id)],
];
}
It will work 100%
I have both case implement like One case is same form field in database table products and other is products_name is form field and in table, it's name is name, how we can validate and ignore that id while updating. I have encrypted that so i'm decrypted id, if you are encrypt then you will decrypt otherwise pass it as it's coming from the form.
$request->validate([
'product_code' => 'required|unique:products,product_code,'.decrypt($request->hiddenProductId),
'products_name' => 'required|unique:products,name,'.decrypt($request->hiddenProductId),
]);
there is detailed and straightforward answer to this question, I was looking for too
https://laravel.com/docs/9.x/validation#rule-unique

In an update function during the validation with custom rules ignore current id for duplicates in laravel

I am using Laravel 6. I created a form to update a meeting and also some validation rules in the controller that check if the room is free at that time and if the participants are already occupied in another meeting at that time. Unfortunately when I submit the form and I change for example only the description of the meeting, the validation process doesn't work correctly because it says that the current room is already occupied at that time and also the participants are already occupied in another meeting at that time... that occurs because the validation process doesn't exclude to check the current id of the meeting. So the meeting is a duplicate of itself.
I tried many ways to change the validate method excluding the $id passed as second argument to the function update_meeting but they didn't work.
Controller:
public function update_meeting(Request $request, $id)
{
$this->validate($request, [
'participants' => [ 'required', new CheckParticipant() ],
'description' => 'required',
'room' => [ 'required', new CheckRoom() ],
'date_meeting' => [ 'required', new CheckDateTime() ],
'start' => [ 'required', new CheckTime() ],
'end' => 'required',
]);
$meeting = Meeting::find($id);
$participants = request('participants');
$meeting->id_participants = implode(';', $participants);
$meeting->description = request('description');
$meeting->id_room = request('room');
$meeting->date = request('date_meeting');
$meeting->start_hour = request('start');
$meeting->end_hour = request('end');
$meeting->save();
$message_correct = "The meeting has been correctly updated!";
return redirect()->route('home')->with('success', $message_correct);
}
A Custom Rule (CheckRoom):
public function passes($attribute, $value)
{
$meetings = DB::table('meetings')
->where('id_room', request('room'))
->where('date', request('date_meeting'))
->where(function ($query) {
$query->where(function($sub_q) {
$sub_q->where('start_hour', '>=', request('start'))
->where('start_hour', '<', request('end'));
})
->orWhere(function($sub_q) {
$sub_q->where('start_hour', '<', request('start'))
->where('end_hour', '>=', request('end'));
})
->orWhere(function($sub_q) {
$sub_q->where('end_hour', '>', request('start'))
->where('end_hour', '<=', request('end'));
});
})->get();
if(count($meetings) > 0) {
return false;
} else {
return true;
}
}
Is there a way to ignore current id in the validate method or should I modify the rule excluding the id in the query?
You can use it in this way here in my case my field is username and table name id admins and the id to ignored is $id
'username'=>'required|unique:admins,username,'.$id
Have you tried passing the value in the constructor? new CheckRoom($id)
class CheckRoom implements Rule
{
protected $excludeId = null;
public function __construct($id = null)
{
$this->excludeId = $id;
}
public function passes($attribute, $value)
{
return DB::table('meetings')
...
->when($this->excludeId, function ($query, $exclude) {
$query->where('id', '<>', $exclude);
})->doesntExist();
}
...
}

DropDown: Validate 2 items on 3 only

I have 2 tables, the first is Students with 3 fields (name, firstname, fk_diploma).Then, my second table is named Diplomas and there is 1 field named (type_diploma).
For information, I have 3 values in my field type_diploma:
1) DiplomaA
2) DiplomaB
3) DiplomaC
In my validate system, I want the DiplomaA or DiplomaB to be validated but not the DiplomaC, I must have an error message.
For example: * "Sorry, you do not have the skills for the diplomaC."
Do you have an idea of how I can do that ?
public function store(Request $request)
{
$diploma = Diploma::select('type_diploma')->where('id',$request->fk_diploma)->get();
if($diploma->type_diploma != 'DiplomaC')
{
$request->validate([
'name' => 'required|min:3',
'firstname' => 'required|min:2|max:200',
'fk_diploma' => 'required'
]);
}
$exists = Student::where('name', $request->get('name'))->where('firstname', $request->get('firstname'))->where('fk_diploma', $request->get('fk_diploma'))->count();
if (!$exists){
Student::create($request->all());
return redirect()->route('students.index')
->with('success', 'new data created successfully');
}
else{
return redirect()->route('students.index')
->with('error', 'duplicate');
}
}
My model Diploma
class Diploma extends Model
{
protected $fillable = ['type_diploma'];
public function diplomas(){
return $this->hasMany('App\Student', 'fk_diploma');
}
}
Model Student
class Student extends Model
{
protected $fillable = ['name', 'firstname', 'fk_diploma'];
public function diplomas(){
return $this->belongsTo('App\Diploma' , 'fk_diploma');
}
This is not the best way to do it, but its the only one i could think right now:
1) change the type of your request to public function store(Request $request)
2) Do this in your function:
public function store(dateRequest $request)
{
$diploma = Diploma::select('type_diploma')->where('id',$request->fk_diploma)->get();
if($diploma->type_diploma != 'DiplomaA' && $diploma->type_diploma != 'DiplomaB')
{
$request->validate([
'name' => 'required|min:3',
'firstname' => 'required|min:2|max:200',
'fk_diploma' => 'required'
]);
}
$exists = Student::where('name', $request->get('name'))->where('firstname', $request->get('firstname'))->where('fk_diploma', $request->get('fk_diploma'))->count();
if (!$exists){
Student::create($request->all());
return redirect()->route('students.index')
->with('success', 'new data created successfully');
}
else{
return redirect()->route('students.index')
->with('error', 'duplicate');
}
}
This will work for you:
$this->validate($request, [
'fk_diploma' => 'required|not_in:XXX',
]);
XXX - id of the diploma you don't want to accept

Symfony2. Doctrine Query for check

How to check for author with Doctrine Query?
class UserController extends Controller
{ ...
/**
* #Route("/join/{id}", name="join_event")
*/
public function joinAct(Request $request, $id)
{
What Query for check? Condition: IF $id (field 'content_id') AND UserID (field 'user_id') exist in table, THEN message: 'You are an author!', ELSE do some code.
$authorcheck = $this->getDoctrine()
->getRepository('MyBundle:User')
->find($id AND $this->getUser()->getId());
End Query
if ($authorcheck) {
$message = ['text' => 'You are an author!', 'type' => 'success'];
}
else {
DoSomeCode...
}
}
}
Any ideas?
$authorcheck = $this
->getDoctrine()
->getRepository('MyBundle:User')
->findBy(array(
'id' => $id,
'user' => $this->getUser()
));
Should be fine for what you need.
Disclaimer
As I don't know fields name and so on, you'll probably need to arrange this in order to work

Categories