excellaravelphpexcellaravel-excel

Laravel Excel `prepareForValidation` method being called twice per row


I'm currently working on an Excel import feature using the Laravel Excel package. I'm implementing OnEachRow, WithHeadingRow, WithValidation, SkipsEmptyRows, SkipsOnFailure, SkipsOnError, and WithEvents interfaces.

My class uses prepareForValidation method to prepare and manipulate the data before it's validated. However, it seems that prepareForValidation is being called twice for each row during the import process. This is leading to unexpected results.

Here's an excerpt of my class where I'm using prepareForValidation:

public function prepareForValidation($data, $index)
{
    dump($index, $data); // debug
    $rules = $this->rules();

    foreach ($data as $key => $value) {
        if (empty($rules[$key]))
            continue;

        if (in_array('date', $rules[$key])) {
            $data[$key] = Date::excelToDateTimeObject($value);
        }

        if (in_array('boolean', $rules[$key])) {
            $data[$key] = human2Bool($value);
        }
    }

    unset($data['']);

    dump($data); //debug

    return $data;
}

As you can see, in the prepareForValidation method, I'm converting Excel dates into a DateTime object and some booleans from human readable format to boolean format. However, it seems that the function is called again with the same row data, after the initial data transformation. The strange thing is, that if I remove the Date::excelToDateTimeObject transformation, this behavior does not happen...

First prepareForValidation call:

"row index:" 3
"data at the beginning of the function:"
array:8 [
  "name" => "Test one"
  "uuid" => "656e9c21-b77a-4a9a-ba3d-e2490effcadd"
  "" => 1
  "execution_structure_id" => "fc1fbdf8-ea73-4d0a-a9a5-f1530a3d49b8"
  "is_locked" => "n"
  "end_at" => 45056
  "duration" => null
  "methodological_status" => null
]
"data at the end of the function:"
array:7 [
  "name" => "Test one"
  "uuid" => "656e9c21-b77a-4a9a-ba3d-e2490effcadd"
  "execution_structure_id" => "fc1fbdf8-ea73-4d0a-a9a5-f1530a3d49b8"
  "is_locked" => false
  "end_at" => "2023-05-10"
  "duration" => null
  "methodological_status" => null
]

Second prepareForValidation call:

"row index:" 3
"data at the beginning of the function:"
array:8 [
  "name" => "Test one"
  "uuid" => "656e9c21-b77a-4a9a-ba3d-e2490effcadd"
  "" => "1"
  "execution_structure_id" => "fc1fbdf8-ea73-4d0a-a9a5-f1530a3d49b8"
  "is_locked" => "n"
  "end_at" => "45056"
  "duration" => null
  "methodological_status" => null
]
"data at the end of the function:"
array:7 [
  "name" => "Test one"
  "uuid" => "656e9c21-b77a-4a9a-ba3d-e2490effcadd"
  "execution_structure_id" => "fc1fbdf8-ea73-4d0a-a9a5-f1530a3d49b8"
  "is_locked" => false
  "end_at" => "2023-05-10"
  "duration" => null
  "methodological_status" => null
]

As seen above, during the first call of prepareForValidation, the 'end_at' field is an integer (Excel's numeric date format). After conversion, it turns into a DateTime object ("2023-05-10"). However, in the second call of prepareForValidation, the 'end_at' field has reverted to being a string again ("45056").

I tried changing the 'end_at' validation rule to date_format:Y-m-d but the issue persists.

Has anyone experienced this before? Is there any explanation for why prepareForValidation would be called twice per row and how can I prevent this from happening?

I'm using the Laravel Excel version 3.1.

Any help would be much appreciated.


Solution

  • Okay, I got it! In my public function onRow(Row $row) I use $row->toCollection() and $row->toArray(). Those are retriggering the validation process and with that the prepareForValidation gets also called again...