What is the better way to create a model with has many relationship?
For example:
I have two models:
Client (id, name, ...)
Contact (id, type, value, description)
A client has many Contacts.
Example of create client view: http://laravel.io/bin/mGXEE
Problems:
how to deal with validations?
if validation fails, going back and fill in the contact with the respective errors?
With php artisan make:request you can make a request file that will validate your information. Take a look at the documentation:
https://laravel.com/docs/5.1/validation
Example:
public function rules()
{
return [
'name' => 'required|min:3|max:20',
'lastname' => 'required|min:3|max:20',
'adres' => 'required|min:3|max:20',
'zip' => 'required|min:3|max:20',
'city' => 'required|min:3|max:20'
];
}
View:
#foreach ($errors->all() as $error)
<p>{{ $error }}</p>
#endforeach
Related
I'm currently making a sort of 'quiz' to get a user's starter class based on their given answers. A personality test, basically.
Here is an example of my forms
<div class="form-group">
<h4>{{Form::label('title', 'Favourite season?')}}<br></h4>
<div class="container">
<div class="option">
Spring - {{Form::radio('q4', 1, false)}}<br>
Summer - {{Form::radio('q4', 2, false)}}<br>
Autumn - {{Form::radio('q4', 3, false)}}<br>
Winter - {{Form::radio('q4', 4, false)}}
</div>
</div>
</div>
My controller is barren at the moment, seeing as I am not sure how to grab each value, then combine them into a final result
public function store(Request $request)
{
$this->validate($request, [
'q1' => 'required',
'q2' => 'required',
'q3' => 'required',
'q4' => 'required',
'q5' => 'required',
'q6' => 'required',
'q7' => 'required',
'q8' => 'required',
'q9' => 'required',
'q10' => 'required',
]);
return $request;
}
}
My post correctly gets the values from the inputs, I just need to know how I can get these into one final score and store it into the database
I have tried using JavaScript, however I cannot figure out how to get the result into the controller to store in the database.
Well you could try to name your radio inputs as an array so then you can retrieve the values in one shot:
{{ Form::radio('q[3]', 1, false) }}
{{ Form::radio('q[3]', 2, false) }}
...
{{ Form::radio('q[4]', 1, false) }}
{{ Form::radio('q[4]', 2, false) }}
...
Then in your Controller you can get all the values into a single array:
$values = $request->input('q', []);
Then you can get the sum of this pretty easily:
$sum = array_sum($values);
You would probably want to do some validation to make sure you are getting the right amount of inputs within certain value ranges.
In my Laravel 7 app, to have nicer error messages in forms, I am using custom validations attributes. For instance for the field id it shows inventory number needed when missing in the form field for submission. Now the issue is that I have several forms for different models in my app and there is ofc more than one id field. There is also an id which is an employee number or a process number.
But in resources/lang/en/validation.php I don't see a way to define the same field name for different models. My idea was to rename the field for error checking, e.g. id rename to employee_id but then no error message comes up.
From my view:
<div class="form-group{{ $errors->has('id') ? ' ' : '' }}">
<input class="form-control{{ $errors->has('id') ? ' is-invalid' : '' }}" name="id" type="text" value="{{ old('id', $process->id) }}" aria-required="true"/>
#include('alerts.feedback', ['field' => 'employee_id']) //not working
</div>
From my validation.php:
'attributes' => [
'email' => 'Mail Address',
'old_password' => 'Current Password',
'password' => 'Password',
'id' => 'Inventory Number', //working, for other form/model
'employee_id' => 'Employee ID' //not working
]
I think the issue is that only field names are accepted that actually exist in the database for the model. How to overcome this?
I just found the solution: A much better way to define custom error attributes than in the validation.php is to create a form request for the model (https://laravel.com/docs/7.x/validation#creating-form-requests) and use the method function attributes(). So there are no conflicts with other model field names and it's more clear, because the attributes are set in the model's form request:
<?php
namespace App\Http\Requests;
use App\Employee;
use Illuminate\Validation\Rule;
use Illuminate\Foundation\Http\FormRequest;
class EmployeeRequest extends FormRequest
{
(...)
public function attributes()
{
return [
'id' => 'Employee ID',
];
}
}
You can set custom messages when you validate your request, it would go something like this:
public function store(Request $request)
{
$request->validate([
'id' => 'required',
'employee_id' => 'required'
],
[
'id.required' => 'ID field is required',
'employee_id.required' => 'Employee field is required'
]);
}
I have a many-to-many relationship between Order and Product
Product.php
public function orders()
{
return $this->belongsToMany(Order::class)
->withTimestamps()
->withPivot('qty');
}
Order.php
public function products()
{
return $this->belongsToMany(Product::class)
->withTimestamps()
->withPivot('qty');
}
Now whenever I try to utilize an iteration in a view (in this case I am just trying to show the form which iterates through all available Products, I always receive the error...
Property [products] does not exist on this collection instance.
create.blade.php
#foreach ($products->orders as $product)
# Order inputs are here
{{ Form::text('qty', $product->pivot->qty, [
'type' => 'tel',
'min' => 0,
'max' => 20,
'step' => 1,
'placeholder' => '0',
'class' => 'meal'
]) }}
#endforeach
I have also attempted #foreach ($products->orders as $product) and both approaches give me that same error.
I have attempted many different ways in my Controller to fix this error, here is my last attempt:
OrderControlller.php
public function create()
{
$user = Auth::user();
$products = Product::get();
$orders = $user->orders;
return view('orders.create', compact('products', 'orders', 'user'));
}
UPDATE
#alan's answer is correct, I am sure, however...
I am still getting "Property [pivot] does not exist on this collection instance" whenever I try to run an iteration.
The concept of an iteration inside of an iteration in this instance is confusing for me.
I cannot visualize how Laravel is handling the pivot connection. In tinker when I load up just the Product table, there is no qty column. (This makes sense because that is on the pivot table). This also explains this new error.
Should I be doing something in the vein of this? :
changed create.blade.php
#foreach ($products as $product)
{{ Form::text('qty', $product->orders->pivot->qty }}
OrderController.php
$user = Auth::user();
$orders = $user->orders;
$products= []; #pass products to view as an array
$p = $orders->products; #this relationship brings in pivot data?
foreach ($p as $orders) {
#would I then somehow pass just this qty here?
}
Problem is I am always getting a "Property does not exist" error, be it with 'products', 'orders', or 'pivot'.
This should work. You were trying to access the orders property on the $products variable, which is a Laravel Collection (get method on model returns a collection). So instead of doing that you just iterate through the products and access the pivot table from the individual product model.
#foreach ($products as $product)
# Order inputs are here
{{ Form::text('qty', $product->orders->pivot->qty, [
'type' => 'tel',
'min' => 0,
'max' => 20,
'step' => 1,
'placeholder' => '0',
'class' => 'meal'
]) }}
#endforeach
Update:
Actually that makes sense. A record on the pivot table defines an association between an order and a product. So for you to access a record in the pivot table you must access the product or order from its relationship. This is what I would do.
OrderController.php
$user = Auth::user();
$user->load("orders.products"); // eager load relationship to avoid N+1 problem
$orders = $user->orders;
return view('orders.create', compact('orders', 'user'));
create.blade.php
#foreach ($orders as $order)
#foreach ($order->products as $product)
{{ Form::text('qty', $product->pivot->qty, [
'type' => 'tel',
'min' => 0,
'max' => 20,
'step' => 1,
'placeholder' => '0',
'class' => 'meal'
]) }}
#endforeach
#endforeach
Some resources:
Eager loading
Many to Many relations
I am simply needing to know how to validate my array of checkbox values to be in a certain list of values. So, I am using the "in:" validation rule as shown below, but it's returning the error that the value of the checked box is invalid. Do I need to do something different since it's an array of values sent via AJAX?
Controller:
if ($request->ajax())
{
/*Create record in UserType Model with the values from the Type checkboxes*/
$Type = Input::get('Type');
$this->validate($request, [
'Type' => 'required|in:A,B,C,D',
],[
'required' => 'You must select at least one.',
]);
foreach ($Type as $key => $value)
{
Auth::user()->userType()->create([
'profile_id' => Auth::user()->id,
'type' => $value,
]);
}
}
In my form, I have the following inputs...
<input type="checkbox" name="Type[]" value="A"/>
<input type="checkbox" name="Type[]" value="B"/>
<input type="checkbox" name="Type[]" value="C"/>
UPDATE:
So, I found in the Laravel documentation that you can validate arrays using * to get the key/values in an array. However, in my array it's just Type[] so I've tried the following with no luck.
$this->validate($request,[
'type.*' => 'required|in:A,B,C,D'
// or
'type*' => 'required|in:A,B,C,D'
]);
Just not working. I know I need to retrieve the array value something with the *.
UPDATE:
I was running Laravel 5.1 when this option for validation is only available in Laravel 5.2. Solved.
First: The required isn't necessary when using in because it must be A, B or C. That is like a "multiple" required already.
Second: As shown in the docs just use:
$this->validate($request,[
'Type.*' => 'in:A,B,C,D'
],[
'in' => 'You must select at least one.',
]);
As your Input array is named Type. That would validate all Inputs named Type.
To be clear the asteriks could be replaced by e.g. one to just validate the Input named Type[one]:
'Type.one' => 'in:A,B,C,D'
or if the Input would be named Type[one][name]
'Type.one.name' => 'in:A,B,C,D'
You try this
if($this->has('Type') && is_array($this->get('Type'))){
foreach($this->get('Type') as $key => $Type){
$rules['Type'.$key.'] = 'required|in:A,B,C,D';
}
In laravel 5 ..
$this->validate($request, [
'Type' => 'required|array'
]);
Worked for me for checkboxes
I have an insert form and a dropdownbox which displays all cars names and when selected one it saves the id in column "car_id" which is unique. What I want is to check if this id already exists and if yes to display a validation message:
create controller
public function create() {
$cars = DB::table('cars')->orderBy('Description', 'asc')->distinct()->lists('Description', 'id');
return View::make('pages.insur_docs_create', array(
'cars' => $cars
));
}
insur_docs_blade.php
<div class="form-group">
{{ Form::label('car', 'Car', array('class'=>'control-label col-lg-4')) }}
<div class="col-lg-8">
{{ Form::select('car', $cars, Input::old('class'), array(
'data-validation' => 'required',
'data-validation-error-msg' => 'You did not enter a valid car',
'class' => 'form-control'))
}}
</div>
</div>
You can use Laravel's Validator class for this. These are a few snippits of how it works. This methods works by using your data model. Instead of writing everything out I added a few links that provide you all the information to complete your validation.
$data = Input::all();
$rules = array(
'car_id' => 'unique'
);
$validator = Validator::make($data, $rules);
if ($validator->passes()) {
return 'Data was saved.';
}
http://laravelbook.com/laravel-input-validation
http://laravel.com/docs/validation
http://daylerees.com/codebright/validation
You can use Laravel's "exists" method like this:
if (User::where('email', $email)->exists()) {
// that email already exists in the users table
}