How to add validation for checkbox in laravel 5? - laravel

I have an array of checkboxes including a hidden checkbox so i can send a value 0 if a checkbox is not checked.
#foreach($records as $record)
<tr>
<td>{{ $record->name }}</td>
<td>{{ $record->id }}</td>
<td>
<input type="hidden" name="record_checkbox[{{ $loop->index }}]" value="0" />
<input type="checkbox" class="form-control name="record_checkbox[{{ $loop->index }}]" value="1" />
</td>
</tr>
#endforeach
I want to validate that only 0 or 1 is sent when a user submits the form.
In my controller I have tried using this:
$this->validate($request, [
'record_checkbox[]' => 'integer|boolean|min:0|max:1',
]);
But when I use browser developer tools and manually update the value field of checkbox to 100, it still accepts it and stores it in database.
So how can I only allow 0 or 1 by proper validation?

Remove brackets if you want to validate all array inputs:
$this->validate($request, [
'record_checkbox' => 'in:0,1',
]);
Edit
Create custom rule: inside app/Providers/AppServiceProvider.php under boot method add the following:
use Illuminate\Support\Facades\Validator;
...
public function boot() {
Validator::extend('validate_checkboxes', function ($attribute, $values, $parameters, $validator) {
foreach( $values as $value ) {
if (!in_array($value, [0, 1])) {
return false;
}
return true;
}
});
}
And then in your controller:
$this->validate($request, [
'record_checkbox' => 'validate_checkboxes',
]);

I've been trying to find a good answer to this for about a month and I think I finally got a good solution, so I'll share it. I have something similar, where I have like 3 or 4 checkbox fields that determine tiny int switches in my database. The way I did this is to add this line in app/Providers/AppServiceProvider.php:
Validator::extendImplicit('checkbox', function($attribute, $value, $parameters, $validator)
{
$data = $validator->getData();
$data[$attribute] = ($value == "1" || strtolower($value) == "true" || strtolower($value) == "on")? "1": "0";
$validator->setData($data);
return true;
});
Explanation:
Validator::extendImplicit
This makes sure that, regardless of whether the attribute is in the request object or not (and if it was unchecked it will not be) it will still run this rule anyways.
$data = $validator->getData();
$data[$attribute] = ($value == "1" || strtolower($value) == "true" || strtolower($value) == "on")? "1": "0";
$validator->setData($data);
Once we enter this function we will get the data array and add the entry for the checkbox as either a 0 or a 1 (note I'm not changing the request object, although you could do that too with something like request->merge() or request()->add()), it then sets the new data array. So in your controller you would simply:
$data = $request->validate(['record_checkbox' => 'checkbox']);
And your data array will contain the field 'record_checkbox' set to either 0 or 1. You can now use this array to fill() your model.
Hope this helps!

Let try:
use Illuminate\Validation\Rule;
$request->validate([
'record_checkbox[]' => [
'required|in_array:[0, 1]'
]
]);

Related

Validate the array inputs value to already selected or not

I want to validate the array inputs value to already selected or not. In my case, I am using Laravel Livewire and I have dynamic inputs such as I can add new options like Size, Color. But I do not want to select the same value in two inputs like the select size in two inputs. Basically, If select the same value in the second input, I want to show it already selected.
Below code livewire controller,
public $i = -1;
public $inputs = [];
public $options = ['Size', 'Color', 'Material', 'Style'];
public $option_name;
function rules()
{
$rules = [];
if ($this->inputs) {
foreach ($this->inputs as $key => $val) {
$rules['option_name.' . $val] = ['required'];
}
return $rules;
}
}
public function addLine($i)
{
$i = $i + 1;
$this->i = $i;
array_push($this->inputs, $i);
}
public function updated($propertyName)
{
if ($this->inputs) {
$this->validateOnly($propertyName);
}
}
Below code livewire view code,
#forelse ($inputs as $key => $value)
<x-native-select label="Option name" :options="$options" wire:model="option_name.{{ $value }}"/> // I am using livewire-wireui
#empty
#endforelse
<a wire:click="addLine({{ $i }})" class="mt-4 text-sm cursor-pointer">
+ Add another option
</a>
Any idea how to validate this?
Try this and let me see how it goes.
public function updatedOptionName($selectedOption) {
//You can use laravel collection filter as well depending on how commplicated you want it
$this->options = array_filter($this->options, function ($value) {
return $value != $selectedOption;
}, ARRAY_FILTER_USE_BOTH));
}
The above function would filter out the selected option so that the option is not available when it is already selected. It might be overkill and subject to improvement from the community. All reviews are welcome. One thing to note is that you might want a sort of reset method in case the user decides to start all over again. Something along the lines of public $originalOptions that you would want to set on mount and then a reset function that assigns this->options to it. Let me know if it works.
More info on those functions Lifecycle hooks

send some variable to the blade view laravel in an addColumn () function of datatable

Its possibility of sending a variable to the blade view through the addColumn() function of datatable jquery?
I want to pass another variable to compare values ​​of the result of the query.
this is the code:
if ($request->ajax()) {
$products = Product::with('categories', 'featureds')->orderBy('name', 'ASC');
$selecteds = [];
$products_selecteds = Product::all();
foreach($products_selecteds as $products_selected){
foreach($products_selected->featureds as $featured){
array_push($selecteds, $products_selected->id);
}
}
return Datatables::of($products)->addColumn('format_price', function($product) {
return $product->format_price;
})->addColumn('checkbox', function ($product, $selecteds) {
return view('pages.products.components.table.checkbox', ['product' => $product, 'selecteds' => $selecteds]);
});
}
the array $selecteds its i want to pass to the view checkbox:
<td>
<label>
<input type="checkbox" class="checkbox-item" {{ in_array($product->id, $selecteds) ? 'checked' : "" }} value=""/>
<span></span>
</label>
</td>
Yes, it's possible to render view on additional columns. But to achieve that, you have to make the column as a Raw Column like this:
Datatable::of($products)
->addColumn('selected', function($product) use($selecteds) {
return view('product.selected', compact('product', 'selecteds'));
})
->rawColumns(['selected'])
note:
you also need to declare use keyword since $selecteds is outside the closure

Laravel : how to get $payment_gateway value

I'm trying to create a feature where, when i create a new booking i can choose the payment method like via xendit or transfer. But when i tried to submit the output of the payment method is still offline payment because of this code {{$row->gatewayObj ? $row->gatewayObj->getDisplayName() : ''}} , and not xendit. How do i fix this??
The Controller :
public function create(Request $request){
// $this->checkPermission('news_create');
$allServices = get_bookable_services();
$whatsAppBookableServices = ["art", "food", "gear", "car", "hotel"];
$payment_gateway = ["xendit", "offline payment"];//tambahan Nicho
$row = new BookingOffline();
$row->fill([
'status' => 'publish',
]);
$data = [
// 'categories' => NewsCategory::get()->toTree(),
'row' => $row,
'breadcrumbs' => [
[
'name' => __('Report'),
'url' => 'admin/module/report/booking'
],
[
'name' => __('Add Booking By WA'),
'class' => 'active'
],
],
'bookableServices' => array_keys($allServices),
'whatsAppBookableServices' => $whatsAppBookableServices,
'payment_gateway' => $payment_gateway,//tambahan Nicho
];
return view('Report::admin.booking.create', $data);
}
The Blade file :
<td>
{{$row->gatewayObj ? $row->gatewayObj->getDisplayName() : ''}}
</td>
The gatewayObj :
function get_payment_gateway_obj($payment_gateway)
{
$gateways = get_payment_gateways();
if (empty($gateways[$payment_gateway]) or !class_exists($gateways[$payment_gateway])) {
return false;
}
$gatewayObj = new $gateways[$payment_gateway]($payment_gateway);
return $gatewayObj;
}
There are still missing pieces to the puzzle, so I cannot provide you with a code snippet to implement.
However, I think you should be able to diagnose it this way:
Check your controller.
Do a die-dump of the $data just above the line containing return view.... Like so: dd($data['payment_gateway'])
Then refresh the page in your browser and see if the $data object is exactly how you want it. The value should be ["xendit", "offline payment"].
Check your form
I suppose you have a form element like a <select></select>, which is iterating over the values of the $data['payment_gateway'] array. If you do not have this, how are your users choosing between the payment options?
Next, make sure that each iteration of payment gateway is being submitted properly. YOu did not include the snippet that handles form submission, but if you're using a <select> element, the options each need to be submitted with a value.
If we hardcode the select, you will have something like this:
<select name="payment_gateway">
<option value="xendit">Xendit</option>
<option value="offline">Offline Payment</option>
</select>
So when the server receives this form information, it knows the exact value of payment gateway to use. Dynamically, it could look like this:
<select name="payment_gateway">
#foreach($data['payment_gateways'] as $gateway)
<option value="{{ $gateway }}">{{ $gateway }}</option>
#endforeach
</select>
Intercept the request and check that your payment_gateway is being submitted properly.
Go to the controller method that handles your form, and do something like dd($request->all())
Then inspect the value of payment_gateway.

Why does the old() method not work in Laravel Blade?

My environment is Laravel 6.0 with PHP 7.3. I want to show the old search value in the text field. However, the old() method is not working. After searching, the old value of the search disappeared. Why isn't the old value displayed? I researched that in most cases, you can use redirect()->withInput() but I don't want to use redirect(). I would prefer to use the view(). method
Controller
class ClientController extends Controller
{
public function index()
{
$clients = Client::orderBy('id', 'asc')->paginate(Client::PAGINATE_NUMBER);
return view('auth.client.index', compact('clients'));
}
public function search()
{
$clientID = $request->input('clientID');
$status = $request->input('status');
$nameKana = $request->input('nameKana');
$registerStartDate = $request->input('registerStartDate');
$registerEndDate = $request->input('registerEndDate');
$query = Client::query();
if (isset($clientID)) {
$query->where('id', $clientID);
}
if ($status != "default") {
$query->where('status', (int) $status);
}
if (isset($nameKana)) {
$query->where('nameKana', 'LIKE', '%'.$nameKana.'%');
}
if (isset($registerStartDate)) {
$query->whereDate('registerDate', '>=', $registerStartDate);
}
if (isset($registerEndDate)) {
$query->whereDate('registerDate', '<=', $registerEndDate);
}
$clients = $query->paginate(Client::PAGINATE_NUMBER);
return view('auth.client.index', compact('clients'));
}
}
Routes
Route::get('/', 'ClientController#index')->name('client.index');
Route::get('/search', 'ClientController#search')->name('client.search');
You just need to pass the variables back to the view:
In Controller:
public function search(Request $request){
$clientID = $request->input('clientID');
$status = $request->input('status');
$nameKana = $request->input('nameKana');
$registerStartDate = $request->input('registerStartDate');
$registerEndDate = $request->input('registerEndDate');
...
return view('auth.client.index', compact('clients', 'clientID', 'status', 'nameKana', 'registerStartDate', 'registerEndDate'));
}
Then, in your index, just do an isset() check on the variables:
In index.blade.php:
<input name="clientID" value="{{ isset($clientID) ? $clientID : '' }}"/>
<input name="status" value="{{ isset($status) ? $status : '' }}"/>
<input name="nameKana" value="{{ isset($nameKana) ? $nameKana : '' }}"/>
...
Since you're returning the same view in both functions, but only passing the variables on one of them, you need to use isset() to ensure the variables exist before trying to use them as the value() attribute on your inputs.
Also, make sure you have Request $request in your method, public function search(Request $request){ ... } (see above) so that $request->input() is accessible.
Change the way you load your view and pass in the array as argument.
// Example:
// Create a newarray with new and old data
$dataSet = array (
'clients' => $query->paginate(Client::PAGINATE_NUMBER),
// OLD DATA
'clientID' => $clientID,
'status' => $status,
'nameKana' => $nameKana,
'registerStartDate' => $registerStartDate,
'registerEndDate' => $registerEndDate
);
// sent dataset
return view('auth.client.index', $dataSet);
Then you can access them in your view as variables $registerStartDate but better to check if it exists first using the isset() method.
example <input type='text' value='#if(isset($registerStartDate)) {{registerStartDate}} #endif />

Laravel Validating Arrays Select fields

Laravel easily validates array based form input fields
<input name='input_name[0][0]">
<input name='input_name[0][1]">
with
'input_name.* = 'required',
https://laravel.com/docs/5.5/validation#validating-arrays
But how can I validate array based select fields?
I have a form where customer info is added, user has to choose the customer's gender and it's possible to add infinite number of customer.
So i have a select for 1 customer:
<select name="gender[0]">
<option selected="selected" disabled="disabled" hidden="hidden" value="">Gender</option>
<option value="Male">Male</option>
<option value="Female">Female</option></select>
and then
<select name="gender[1]">...
<select name="gender[N]">
When I set the rule as:
'gender.*' => 'required'
It doesn't recognize an 'unchoosen' select-box as an error....
But if I update validation rules to:
'gender[0]'=>'required'
'gender[1]'=>'required'
'gender[N]'=>'required'
It works absolutely fine... (by "it works", I mean that it returns a mistake "Gender field is required").
So, apparently Laravel has some problems with array based select names.
Appreciate any help!
public function rules() {
$rules = [];
$gender = $this->input('gender');
foreach ($gender as $index => $item) {
$rules["gender.{$index}"] = 'required';
}
return $rules;
}
I've decided o answer the question myself.
1) First solution is to make the first "placeholder" option not disabled (as was in my case, see above - it's because I use LaravelCollective and they have it by default):
<select name="gender[0]">
<option selected="selected" hidden="hidden" value="">Gender</option>
<option value="Male">Male</option>
<option value="Female">Female</option></select>
When you remove 'disabled' from option-1 of your select then it sends ' ' when posting (instead of sending nothing with 'disabled'). So it sends
gender[0] = '';
gender[1] = '';
etc...
Actually, if you have a lot of gender[N] (or maybe other array based selects) I think it's the neatest solution.
2) Second solution is provided below by omadonex:
public function rules() {
$rules = [];
$gender = $this->input('gender');
foreach ($gender as $index => $item) {
$rules["gender.{$index}"] = 'required';
}
return $rules;
}
in this case you'll have a separate rule for every array-based select and it will work (see why in the end of my topicstarter-post). I prefer this solution less than 1st one because you'll have a long list of "gender"-rules if you have a lot of ...
3) Also I've undertood why 'gender[0]'=>'required'
works
and 'gender.*' => 'required'
does not
for array based selects like <select name=gender[0]>
It's kind of obvious if you think about it: when POSTING select tag with first option (a placeholder) being disabled, as in my example above:
<option selected="selected" disabled="disabled" hidden="hidden" value="">Gender</option>
the $POST sends nothing....
So if Laravel's validation rule is 'gender[0]'=>'required' Laravel "thinks": "OKAY, I've received no "gender[0]", but I know what is required exactly ("gender[0]", of course) . I have to send a mistake because there is no "gender[0]".
But if rule is 'gender.*' => 'required' and Laravel get's no input of "gender" kind, then it also doesn't know what EXACTLY is required ('gender.*' may mean gender[0]... gender [12345] ... gender[anything]). Laravel can't send a mistake, because infinite number of gender[...] is missing, so he simply omits it....
PS. If you work with LaravelCollective forms of newer versions, they create placeholder "disabled" by default. Here is a macro to avoid it.
{!!
Form::macro('selectNonDisabled', function($value, $placeholder, $array, $disabled=null, $class=null) {
$select = "<select class='form-control $class' $disabled name='$value'>";
$select .= "<option selected='selected' hidden='hidden' value=''>$placeholder</option>";
foreach ($array as $key => $value) {
$select .= "<option value='$key'>$value</option>";
}
$select .= "</select>";
return $select;
});
!!}

Resources