phparrayslaravelvalidation

How to validate an array of dates in Laravel


The below validation does not pass for start_date and end_date fields.

ErrorException: strtotime() expects parameter 1 to be string, array given

public function rules()
{
    return [
      'location_id.*' => 'required_without_all:user_id,service_id|integer|gt:0',
      'service_id.*' => 'required_without_all:user_id,location_id|integer|gt:0',
      'user_id.*' => 'required_without_all:location_id,service_id|integer|gt:0',
      'start_date.*' => 'required|date|after_or_equal:now',
      'end_date.*' => 'nullable|date|after_or_equal:start_date',
      'day_name.*' => 'nullable|integer|between:1,7',
      'start_time.*' => 'required|date_format:H:i|before:end_time',
      'end_time.*' => 'required|date_format:H:i|after:start_time',
      'created_by_user_id.*' => 'required|integer|gt:0',
    ];
}

protected function prepareForValidation()
{
  $row = count($this->day_name);

  $this->merge([
      'location_id' => array_fill(0, $row, $this->location_id),
      'service_id' => array_fill(0, $row, $this->service_id),
      'user_id' => array_fill(0, $row, $this->user_id),
      'start_date' => array_fill(0, $row, Carbon::parse($this->start_date)),
      'end_date' => array_fill(0, $row, Carbon::parse($this->end_date)),
      'day_name' => array_fill(0, $row, $this->day_name),
      'start_time' => array_fill(0, $row, $this->start_time),
      'end_time' => array_fill(0, $row, $this->end_time),
      'created_by_user_id' => array_fill(0, 3, $this->created_by_user_id),
  ]);

The start_date is a carbon instance as given below:

dd($this->start_date)); // In the start of public function rules()

array:3 [
  0 => Carbon\Carbon @1587484783^ {#1470
    #constructedObjectId: "000000006789d240000000000f12e56f"
    #localMonthsOverflow: null
    #localYearsOverflow: null
    #localStrictModeEnabled: null
    #localHumanDiffOptions: null
    #localToStringFormat: null
    #localSerializer: null
    #localMacros: null
    #localGenericMacros: null
    #localFormatFunction: null
    #localTranslator: null
    #dumpProperties: array:3 [
      0 => "date"
      1 => "timezone_type"
      2 => "timezone"
    ]
    #dumpLocale: null
    date: 2020-04-21 15:59:43.430962 UTC (+00:00)
    timezone: "UTC"
  }
  1 => Carbon\Carbon @1587484783^ {#1470}
  2 => Carbon\Carbon @1587484783^ {#1470}
]

All the fields belong to the same table. Some were non-arrays and some were array inputs. So converted them all to arrays to do multiple record inserts.


Solution

  • The problem that you are having is that you are passing an array of dates to compare to each single 'start_date' or each 'end_date'. The only way you will be able to validate this using Laravel's existing validation rules is if you change how your request is formed.

    Instead of passing this to your request:

    {
        start_date: ['YYYY-MM-DD', 'YYYY-MM-DD', 'YYYY-MM-DD'],
        end_date: ['YYYY-MM-DD', 'YYYY-MM-DD', 'YYYY-MM-DD']
    }
    

    try passing this:

    {
        dates: [
            {start_date: 'YYYY-MM-DD', end_date: 'YYYY-MM-DD'},
            {start_date: 'YYYY-MM-DD', end_date: 'YYYY-MM-DD'},
            {start_date: 'YYYY-MM-DD', end_date: 'YYYY-MM-DD'}
        ]
    }
    

    With this syntax you can then validate each 'start_date' with it's respective 'end_date' and viceversa:

    public function rules()
    {
        return [
            'dates.*.start_date' => 'required|date|after_or_equal:now',
            'dates.*.end_date' => 'nullable|date|after_or_equal:start_date'
        ];
    }