Map form field to eloquent model with different name - laravel-5

I'm wondering how to map form field to eloquent model. Thing is that form input field has different name than eloquent model.
This is what i have
Model
class Message extends Model
{
protected $fillable = [
'name', 'email', 'subject_id',
];
}
Form
<form action="{{ action('MessageController#store') }}" method="post">
<input id="name" name="name" type="text">
<input id="email" name="email" type="text">
<select id="subject" name="subject">
#foreach ($subjects as $subject)
<option value="{{ $subject->id }}">{{ $subject->title}}</option>
#endforeach
</select>
</form>
Controller
public function store(Request $request)
{
$message = $this->validate(request(), [
'name' => 'required',
'email' => 'required',
'subject' => 'required',
]);
Message::create($message);
}
Notice that form select field name is subject and Message model field is subject_id.
Is it possible to map these two fields in Message model?
I guess it's possible in controller with something like
Message::create([
'name' => $request->input('name');
'email' => $request->input('email');
'subject_id' => $request->input('subject');
]);
but that's not what i want.
I don't expect some code improvements or suggestions as i'm complete Laravel noob :)

You could add a mutator on the Message model.
public function setSubjectAttribute($value) {
$this->attributes['subject_id'] = $value;
}
That essentially tells eloquent there is a subject attribute on the model but under the hood you're modifying subject_id

Related

trying to insert an array but Cannot access offset of type string on string laravel 8

i want to insert an array but it tells me Cannot access offset of type string on string
and i made foreach and when i do $return->request
it looks like
{
_token: "qb7dTYdsDVtw1RJnQQARzJMEqIfHPeQbHobiC8u2",
_method: "POST",
name: "Wanda Rojas",
phone: [
"+1 (841) 393-5088",
"+1 (769) 441-1936"
],
address: "Et est cum delectus"
}
and here is my model for clients
and i make phone field as array in protected $casts
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Client extends Model
{
use HasFactory;
protected $fillable = [
'name',
'address',
];
protected $casts = [
'phone' => 'array'
];
}
here is my form
<form action="{{route('clients.store')}}" method="POST">
#csrf
#method('POST')
<input type="text" placeholder="add name" name="name"><br>
#for ($i = 0; $i < 2; $i++) <div class="form-group">
<label>#lang('site.phone')</label>
<input type="text" name="phone[]" class="form-control">
</div>
#endfor
<input type="text" placeholder="add address" name="address"><br>
<button type="submit" class="btn btn-primary">add</button>
</form>
and here is my controller at store method
public function store(Request $request)
{
//return $request;
$this->validate($request,[
'name' => 'required',
'phone' => 'required|array|min:1',
'phone.*' => 'required',
'address' => 'required'
]);
$phone = $request->phone;
foreach ($phone as $p){
$add = new Client();
$add->name = $request->name;
$add->phone = $p['phone'];
$add->address = $request->address;
$add->save();
};
return redirect()->route('clients.index');
}
Your code when you store client should looks like this
public function store(Request $request)
{
//return $request;
$this->validate($request,[
'name' => 'required',
'phone' => 'required|array|min:1',
'phone.*' => 'required',
'address' => 'required'
]);
$phone = $request->phone;
$add = new Client();
$add->name = $request->name;
$add->phone = $phone; // $phone it's already an array, so you should only set it to property
$add->address = $request->address;
$add->save();
return redirect()->route('clients.index');
}
and in clients.index.blade.php to access phone
#foreach($client->phone as $phone)
...
{{ $phone }}
...
#endforeach
You are iterating through the array of phone numbers so $p is the phone number. $add->phone = $p should resolve your issue.

Livewire validateOnly with validate in the same component

I have a little problem with the data validation with livewire ( laravel ).
I noticed that when I set up the validation in real time ( validateOnly() ), the information entered in the form is validated in real time. At this level everything is fine.
But when I click on the button to submit the form (even though the form contains errors), the form is unfortunately sent to my function defined in the wire:submit.
So my question is : is it possible to revalidate the information in the wire:submit method that receives the data after the form is submitted ? If so, how can I do that?
PS: I tried to set the validate method in my wire:submit function but nothing happens. It blocks the form from being submitted but it doesn't give me an error .
My source code :
<?php
class UserProfile extends Component
{
use WithFileUploads;
public $countries = [];
public $profile = [];
protected function rules() {
if ( !LivewireUpdateProfileRequest::authorize() ) {
return abort(403, "Your are not authorized to make this request !");
}
$rules = LivewireUpdateProfileRequest::rules();
if ( !empty($this->profile['phone']) ) {
$rules['profile.phone'] = [ 'required', 'phone_number:' . $this->profile['phone'] ];
}
return $rules;
}
public function mount()
{
$this->countries = Countries::all();
$this->profile = Auth::user()->toArray();
}
public function updateUserProfile()
{
$validatedData = $this->validate();
dd( $validatedData );
}
public function updated($key, $value)
{
$this->validateOnly($key);
}
public function render()
{
return view('livewire.user-profile');
}
}
Html source :
<form action="" method="POST" wire:submit.prevent="updateUserProfile">
<input name="profile.email" type="email" wire:model="profile.email" />
#error('profile.email') {{ $message }} #enderror
<input name="profile.phone" type="tel" wire:model="profile.phone" />
#error('profile.phone') {{ $message }} #enderror
</form>
Here is LivewireUpdateProfileRequest content :
<?php
namespace App\Http\Requests\Web;
use Illuminate\Foundation\Http\FormRequest;
class LivewireUpdateProfileRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public static function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public static function rules()
{
return [
'profile' => ['required', 'array', 'size:10'],
'profile.firstname' => ['required', 'string'],
'profile.lastname' => ['required', 'string'],
'profile.email' => ['required', 'email'],
'profile.phone' => ['required', 'phone_number:33'],
'profile.gender' => ['required', 'gender'],
'profile.image' => ['sometimes', 'image', 'mimes:png,jpg,jpeg'],
'profile.address' => ['required', 'string'],
'profile.city' => ['required', 'string'],
'profile.country_id' => ['required', 'exists:countries,id'],
'profile.birth_at' => ['required', 'date', 'min_age:18'],
];
}
}
Usually in your saving method you would run validation once more for all fields. The livewire docs share this example:
Livewire Component:
class ContactForm extends Component
{
public $name;
public $email;
protected $rules = [
'name' => 'required|min:6',
'email' => 'required|email',
];
public function updated($propertyName)
{
$this->validateOnly($propertyName);
}
public function saveContact()
{
$validatedData = $this->validate();
Contact::create($validatedData);
}
}
With this HTML:
<form wire:submit.prevent="saveContact">
<input type="text" wire:model="name">
#error('name') <span class="error">{{ $message }}</span> #enderror
<input type="text" wire:model="email">
#error('email') <span class="error">{{ $message }}</span> #enderror
<button type="submit">Save Contact</button>
</form>
This should validate the inputs near-realtime using the updated-method and on submit using the saveContact-method.
If you could share your code, we could debug it easier.
Source: https://laravel-livewire.com/docs/2.x/input-validation#real-time-validation

Retrieve session data in blades

I would like to create a multi step form with validations, but the values are not stored in the inputs through the sessions.
In the controller I have:
use Illuminate\Support\Facades\Session;
My code at the moment is this:
public function addItemStep1(Request $request)
{
$product = $request->session()->get('product');
return view('admin.items.add', compact('product'))->with([
'page_name' => __('Add Item')
]);
}
public function storeNewItemStep1(Request $request)
{
$validatedData = $request->validate([
'title' => 'required',
'body' => 'required'
]);
if(empty($request->session()->get('product')))
{
$product = new Items();
$product->fill($validatedData);
$request->session()->put('product', $product);
} else {
$product = $request->session()->get('product');
$product->fill($validatedData);
$request->session()->put('product', $product);
}
return redirect('/');
}
The validations work, everything is ok, but unfortunately after sending the form the data just entered does not appear.
<input type="text" class="form-control #error('title') is-invalid #enderror" value="{{ Session::get('title') }}" name="title">

update is not working - error passing data from form to the update method

I have a form to edit the administrators of a post.
This form has some radio buttons. Each radio button corresponds to a administrator of a a post, so the id of each radio button
is the id of the admin in the administrators table.
When the submit button is clicked I want to update just the administrator with the id of the checked administrator/radio button.
For that it should be necessary to pass to the update method the id of the post and the id of the checked radio button (administrator) and then update only that administrator id.
Im passing the id of the post with success but the admin id not. It appears syntax error, unexpected '{'.
Edit admins form:
<form method="post" class="clearfix" action="{{route('admins.update', ['id' => $post->id], ['adminID' => $admin->id])}}" enctype="multipart/form-data">
{{csrf_field()}}
#foreach($administrators $admin)
<div class="form-check">
<input class="form-check-input" type="radio" name="radiobutton" id="{{$admin->id}}" value="">
<label class="form-check-label" for="">
{{$admin->first_name}}
</label>
</div>
#endforeach
<!-- below I have form fields like administrator name, email, etc -->
</form>
// update admins routes
Route::get('post/edit/{id}/admins', [ 'uses' => 'AdminController#edit', 'as'=>'admins.edit']);
Route::post('post/update/{id}/admins', [ 'uses' => 'AdminController#update', 'as'=>'admins.update']);
// Admin controller
class AdministratorController extends Controller
{
public function edit($id)
{
$post = Post::find($id);
$administrators = Administrator::where('post_id', $id)->get();
return view('administrators.edit')
->with('post', $post)
->with('administrators', $administrators));
}
public function update(Request $request, $id, $adminID){
$this->validate($request, [
'name' => 'required|string',
'email' => 'required|integer',
'...' => '...',
]);
$post = Post::find($id);
$admin = Administrator::find($post->id);
$administratorToUpdate = Administrator::find($adminID);
$administratorToUpdate->name = $request->name;
$administratorToUpdate->email = $request->email;
....
$administratorToUpdate->save();
}
// Admin model
class Administrator extends Model
{
protected $fillable = [
'first_name', 'email', 'password', 'description', 'post_id'
];
public function post(){
return $this->belongsTo('App\Post');
}
}
Edit the route from :
{{route('admins.update', ['id' => $post->id], ['adminID' => $admin->id])}}
to:
{{route('admins.update', ['id' => $post->id, 'adminID' => $admin->id])}}
Edit: make sure to iterate over the administrators before defining the route.
There are some other mistakes on the form like foreach($administrators as $admin) $admin will be not be available for the route above so tweak that.

Laravel checkbox validation, always empty?

I have a checkboxes like this:
<div class="form-group">
<div style="display:none ;" class="weekday_message form-control alert-warning"></div>
<label id="weekday2" for="weekday" class="col-md-4 control-label">Weekday</label>
<div class="required form-field" name="weekday" id="weekday">
<input class="weekday" type="checkbox" name="weekdays[]" value="MO">Monday
<input class="weekday" type="checkbox" name="weekdays[]" value="TU">Tuesday
<input class="weekday" type="checkbox" name="weekdays[]" value="WE">Wednesday
<input class="weekday" type="checkbox" name="weekdays[]" value="TH">Thursday
<input class="weekday" type="checkbox" name="weekdays[]" value="FR">Friday
<input class="weekday" type="checkbox" name="weekdays[]" value="SA">Saturday
<input class="weekday" type="checkbox" name="weekdays[]" value="SU">Sunday
</div>
<span class="help-block">
<strong></strong>
</span>
</div>
My validation:
public function rules()
{
return [
'startdate' => 'required|date',
'endate' => 'nullable|date',
'startime' => ['required', new Time],
'endtime' => ['required', new Time],
'title' => 'required',
'entity_id' => 'required',
'type' => 'required|exists:entities,type',
'description' => 'required',
'frequency' => 'required',
'interval' => 'nullable|numeric',
'monthday' => 'nullable|numeric|min:1|max:3',
'weekdays' => 'array|max:3',
'month' => 'nullable|numeric',
'until' => 'nullable|date',
'tags' => 'nullable',
];
}
and controller:
public function storeEvent(EventRequest $request)
{
$test = ($request->input('weekdays'));
dd($test);
$weekday_string = implode(",", $request->input('weekdays'));
$request->merge(array('weekday', $weekday_string));
dd($request->all());
$event = DirtyEvent::create($request->all());
$geoloc_id = Entity::find($event->entity_id)
->first();
$user_id = Auth::id();
// Save Geoloc + user id into newly created event
$event->_geoloc()->associate($geoloc_id);
$event->users()->associate($user_id);
$event->save();
Now, validation seems to pass because it does data dump, however both dd($test) as well as $request->all() are giving me back empty weekdays, like it would not be defined. What could be the possible cause of this?
If you want to make sure you have always at least one weekday selected you should change:
'weekdays' => 'array|max:3',
into:
'weekdays' => 'array|required|max:3',
Also I suppose you don't send data using standard HTML form because you set for example name for divs so maybe you forget to attach weekdays or have bug in code elsewhere?
Your HTML says weekday (singular) but your rules set says weekdays (plural).
There needs to be at least one checkbox selected to make the input weekdays to be included in the request. You can use a default value in case none was selected by adding a hidden input before the checkboxes.
<input type="hidden" name="weekdays" value="defaultValue">

Resources