3

Im developing inventory system using laravel.

Everything were going as expected until im facing a problem on form validation.

So below is my insert function in my order controller code,

public function insert(Request $request) {
    // Save data to "orders" table
    $orderer = [
      'orderId' => $request->get('orderId'),
      'customerId' => $request->get('customerId'),
      'orderTotal' => $request->get('orderTotal'),
      'paymentMethodId' => $request->get('paymentMethodId'),
      'orderStatusId' => $request->get('orderStatusId'),
      'created_at' =>  \Carbon\Carbon::now(), # \Datetime()
      'updated_at' => \Carbon\Carbon::now()  # \Datetime()
    ];

    // Looping on dynamic "New Added" input field
    $orderedItems_Sku = $request->get('productSku');
    foreach($orderedItems_Sku as $key => $v)
    {
      $productSku = $request->get('productSku') [$key];
      $product = \App\Product::find($productSku);
      $rules = [
              'orderId' => 'unique:orders',
              'customerId' => 'required',
              'orderStatusId' => 'required',
              'paymentMethodId' => 'required',
              'uomId.*' => 'required',
              'productSku.*' => 'required',
              'productQty.*' => 'required',
              // 'lte' means Less Than or Equal to available stock quantity
              'orderQty.*' => 
              'required|numeric|min:1|lte:'.$product['productQty'],
              'orderPrice.*' => 'required'
          ];

      $messages = [
                'customerId.required' => 'Please select Customer',
                'orderStatusId.required' => 'Please select Order Status',
                'paymentMethodId.required' => 'Please select Payment Method',
                'uomId.*.required' => 'Please select UOM',
                'productSku.*.required' => 'Please select Product',
                'orderQty.*.required' => 'Please enter Order Quantity',
                'orderQty.*.min' => 'Quantity must be at least 1',
                'orderQty.*.lte' => 'Quantity of product no. 
                '.$product['productSku'].' must be not greater than 
                '.$product['productQty'],
                'orderPrice.*.required' => 'Please enter Product Price'
          ];

      // Validate "Rules" and "Messages" to running.
      $this->validate($request, $rules, $messages); 

      $data = [
        'orderId' => $request->get('orderId'),
        'productSku' => $v,
        'orderQty' => $request->get('orderQty') [$key],
        'uomId' => $request->get('uomId'),
        'orderPrice' => $request->get('orderPrice') [$key],
        'orderDiscount' => $request->get('orderDis') [$key],
        'orderPerAmount' => $request->get('orderPerAmount') [$key],
        'created_at' =>  \Carbon\Carbon::now(), # \Datetime()
        'updated_at' => \Carbon\Carbon::now()  # \Datetime()
      ];
      \App\orderedItem::insert($data);
      // "Decrement" means, product quantity will be deducted based on how 
      much quantity that customer has ordered.
      \App\Product::where("productSku", $v)->decrement("productQty", 
      $request->orderQty [$key]);
    }
    \App\Order::insert($orderer);
    return redirect('orders')->with('success', 'Order Successfully Added!'); 
  }

Here's is my html code inside create.blade.php,

https://pastebin.com/cn2X1aVL

as you can see, there's "orderQty" and "productQty" field.

So, im trying to validate the dynamic "orderQty" field with the dynamic "productQty" field to prevent user from entering quantity greater than value inside "productQty" field.

im also using lte (less than equal to) command inside $rules array in my code as per recommended by most of laravel communities.

This thing only works perfectly on single input but not on dynamically added input. Refer to the image below, you can see, the second input of the product not validated properly as i wanted.

create blade file

even the error messages not showing the dynamic message as wanted.

Please help me to find out what is the problem. I have trying so many solutions but still not working. :'(

Zarul Izham
  • 143
  • 1
  • 1
  • 10
  • Can you please post your html field for "orderQty" and "productQty" – Jesus Erwin Suarez Nov 19 '18 at 02:49
  • Try this: 'orderQty.*' => 'required|numeric|min:1|max:'.$product['productQty'] – Jesus Erwin Suarez Nov 19 '18 at 02:54
  • try to make an custom validation rule. their you will get the array parameters. and you can make your own rule. – Emtiaz Zahid Nov 19 '18 at 02:55
  • I agree with custom rule validation. – Jesus Erwin Suarez Nov 19 '18 at 02:56
  • @JesusErwinSuarez i have updated my html code. – Zarul Izham Nov 19 '18 at 03:02
  • Okay did you try this one? Try this: 'orderQty.*' => 'required|numeric|min:1|max:'.$product['productQty'] – Jesus Erwin Suarez Nov 19 '18 at 03:04
  • @EmtiazZahid this not solving my problem at all. the validation using lte is working perfectly. the problem is on dynamic added fields. which the lte rule only working on the first field and not working on the second field, third field, and so on. – Zarul Izham Nov 19 '18 at 03:08
  • How are you validating the data? Can you please show the method that you are calling ($this->validate) and how are you passing the $errors back to the view? – Josh Nov 19 '18 at 04:55
  • @Josh hey Josh. Its fixed! by create new Request in different file like you mention it earlier. I dont know how but i think there's conflict when i put the validation along with insert function in controller file. I will post my answer below.. – Zarul Izham Nov 19 '18 at 06:23
  • @Zural I think that you had issues with how you were passing back the errors to the view and creating the custom request automatically does that for you. It also makes your controller a lot cleaner as all you have is the functionality of saving the validated data – Josh Nov 19 '18 at 06:24
  • @Josh yes. I think so. Must be conflict somewhere when passing back the errors to the view because when i remove the code inside insert function and pass it to my new Request file, it makes me easier to understand in passing back the errors to view. – Zarul Izham Nov 19 '18 at 06:44

3 Answers3

9

After testing all possible solutions suggested by answerers,

Now its fixed!

Here's my insert function code in OrderController,

public function insert(OrderRequest $request) {
    // Save data to "orders" table
    $orderer = [
      'orderId' => $request->get('orderId'),
      'customerId' => $request->get('customerId'),
      'orderTotal' => $request->get('orderTotal'),
      'paymentMethodId' => $request->get('paymentMethodId'),
      'orderStatusId' => $request->get('orderStatusId'),
      'created_at' =>  \Carbon\Carbon::now(), # \Datetime()
      'updated_at' => \Carbon\Carbon::now()  # \Datetime()
    ];

    // Looping on dynamic "New Added" input field
    $orderedItems_Sku = $request->get('productSku');
    foreach($orderedItems_Sku as $key => $v)
    {

      $data = [
        'orderId' => $request->get('orderId'),
        'productSku' => $v,
        'orderQty' => $request->get('orderQty') [$key],
        'uomId' => $request->get('uomId'),
        'orderPrice' => $request->get('orderPrice') [$key],
        'orderDiscount' => $request->get('orderDis') [$key],
        'orderPerAmount' => $request->get('orderPerAmount') [$key],
        'created_at' =>  \Carbon\Carbon::now(), # \Datetime()
        'updated_at' => \Carbon\Carbon::now()  # \Datetime()
      ];
      \App\orderedItem::insert($data);
      // "Decrement" means, product quantity will be deducted based on how much quantity that customer has ordered.
      \App\Product::where("productSku", $v)->decrement("productQty", $request->orderQty [$key]);
    }
    \App\Order::insert($orderer);

    $validated = $request->validated();
    return redirect('orders')->with('success', 'Order Successfully Added!'); 
}

and this is my code inside OrderRequest

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\Request;

class OrderRequest extends FormRequest
{
/**
 * 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()
{ 
    $rules = [
        'name' => 'required',
    ];

    foreach($this->request->get('productSku') as $key => $val)
    {
        $product = \App\Product::find($val);
        $rules['orderId'] = 'unique:orders'; 
        $rules['customerId'] = 'required';
        $rules['orderStatusId'] = 'required';
        $rules['paymentMethodId'] = 'required';
        $rules['uomId'] = 'required';
        $rules['productSku.'.$key] = 'required';
        $rules['orderQty.'.$key] = 'required|numeric|min:1|lte:'.$product['productQty'];
        $rules['orderPrice.'.$key] = 'required';
    }
    return $rules;
}

public function messages() 
{
    $messages = [];
      foreach($this->request->get('productSku') as $key => $val)
      {
        $product = \App\Product::find($val);
        $messages['orderQty.'.$key.'.lte'] = 'Quantity of product no. 
'.$product['productSku'].' must be not greater than '.$product['productQty'];
      }
      return $messages;
}
}

As you can see, i've created my own Request file (OrderRequest) and call it from OrderController.

Inside the OrderRequest file, i've made a foreach loop to make sure the validation works on my dynamic field including lte/gte rules in it.

For custom messages, i've also made a foreach loop as i wanted to show the error dynamically as below (refer image),

create blade file

Thank you everyone who suggests me various possible solutions to me to fix this problem. :D

Zarul Izham
  • 143
  • 1
  • 1
  • 10
0

Try this one

'orderQty.*' => 'required|numeric|min:1|max:'.$product['productQty'] 
Jesus Erwin Suarez
  • 1,571
  • 16
  • 17
  • the validation using either lte or min, max is working perfectly. the problem is on dynamic added fields. which the lte rule only working on the first field and not working on the second field, third field, and so on. you can refer the image in my post. – Zarul Izham Nov 19 '18 at 03:13
  • @Jesus That was already suggested in the comments of the answer below – Josh Nov 19 '18 at 03:34
  • I am wondering why its not working but it should work both max or lte rules. – Jesus Erwin Suarez Nov 19 '18 at 04:51
-1

You can create your own request:

php artisan make:request {request name}

Then you can use this request in the same way as the default Request as shown in these docs

https://laravel.com/docs/5.7/requests

if you add another method called "messages" you can add messages like this:

public function messages() {
    return [
        '{variable name}.{validation method}' => '{message to user}'
    ]
}

Then you will get an ajax response with the error messages in it.

Hope that helps

Update

The above suggestion is best practice because you are passing all your data through the blank Request

change:

'required|numeric|min:1|lte:'.$product['productQty'],

To:

'required|numeric|min:1|lte:productQty',

This tells the validator that the orderQty must be less than or equal to the input for productQty

Josh
  • 1,316
  • 10
  • 26
  • the problem was not that he cant make request validation. his problem is validation for greater then or equal in dynamic input fields – Emtiaz Zahid Nov 19 '18 at 02:43
  • Please see the updated reponse. You editied the question details after I had started to respond. – Josh Nov 19 '18 at 02:48
  • @EmtiazZahid yes. My problem is on gte, lte validation for dynamic input fields.. Not the request issue. – Zarul Izham Nov 19 '18 at 02:49
  • @Josh according to your updated answer, now im facing the error, "The values under comparison must be of the same type" – Zarul Izham Nov 19 '18 at 02:53
  • @Josh productQty is not an input field value. its value comming from DB. – Emtiaz Zahid Nov 19 '18 at 02:53
  • try this to see if it solves your problem "max:' . $product['productQty'] – Josh Nov 19 '18 at 02:57
  • @Josh actually, the lte is working. but its only working on single field. when i add new field, the validation not validate that new added field. its still show validation from the first field. – Zarul Izham Nov 19 '18 at 03:18
  • @Zarul can you please add this to your view and then paste the results. "@php Log::info($errors); @endphp" – Josh Nov 19 '18 at 03:37