Search code examples
phplaravellaravel-validation

Custom validation not calling the passes() function


I am trying to make a validation that will check whether at least one item is provided in an array following the steps in Custom Validation Rules Routes.php

Route::middleware(['auth:api', 'bindings'])->group(function () {
  Route::prefix('api')->group(function () {
    Route::apiResources([
      'exam-papers/{examPaper}/questions' => ExamPaperQuestionsController::class
    ]);
  });
});

ValidateArrayElementRule.php


namespace App\Rules;

use Illuminate\Contracts\Validation\Rule;

class ValidateArrayElementRule implements Rule
{
  public function __construct()
  {
    //
  }

  public function passes($attribute, $value)
  {
    echo "there";
    return count($value) > 0;
  }

  public function message()
  {
    return 'At least one element is required!';
  }
}

ExamPaperQuestionsController.php

 public function store(ExamPaperQuestionStoreRequest $request, ExamPaper $examPaper)
 {
    return response()->json([])->setStatusCode(201);
 }

In my test file I have

  public function error_422_if_no_questions_provided()
  {
    Permission::factory()->state(['name' => 'create exam paper question'])->create();
    $this->user->givePermissionTo('create exam paper question');
    $this->actingAs($this->user, 'api')
      ->postJson('/api/exam-papers/' . $this->examPaper->id . '/questions', [])
      ->assertStatus(422);

  }

ExamPaperQuestionStoreRequest.php


class ExamPaperQuestionStoreRequest extends FormRequest
{
  /**
   * Determine if the user is authorized to make this request.
   *
   * @return bool
   */
  public function authorize()
  {
    return auth()->user()->can('create exam paper question');
  }

  /**
   * Get the validation rules that apply to the request.
   *
   * @return array
   */
  public function rules()
  {
    echo "HERE";
    return [
      'questions' => [new ValidateArrayElementRule],
      'questions.*.description' => 'required'
    ];
  }


}

The test is failing

Expected status code 422 but received 201.

I can see the text "HERE" is logged but "there" is not. Why is my validation passes() function not being called?


Solution

  • Suppose if your request contain empty then it wont call custom validation. So you must add required filed to ensure request has key questions

    'questions' => ["required",new ValidateArrayElementRule]
    

    Incase questions is optional and if entered then at least two or three item required then you can use required if validation.

    By default laravel support min in array

    'questions' => ["required","array","min:1"]