Checking in the controller

I am very new to Laravel and I need help refactoring my code. Now the method is not considered 100% in the tests, because I cannot mock the validated object and its responses. I have the following method in my controller

public function store(Request $request)
{
    $data = $request->only([
        'name',
        'email',
        'message',
    ]);

    $validator = Validator::make($data, $this->validatorRules);

    if ($validator->fails()) {
        return $this->response->errorFromValidator($validator);
    }

    $savedItem = $this->repository->store($data);

    if (!$savedItem) {
        return $this->response->error('Cannot save');
    }

    return $this->response->succesItem($savedItem);
}

      

I tried to inject a validator into the controller constructor:

function __construct(Response $response, Repository $repository, Validator $validator)
{
    $this->response = $response;
    $this->repository = $repository;
    $this->validator= $validator;
}

      

and use it in a method:

$this->validator::make($data, $this->validatorRules);

      

but I was getting syntax error unexpected '::' (T_PAAMAYIM_NEKUDOTAYIM). How can I format the validator outside of the method so I can mock the validator in tests?

+3


source to share


2 answers


Why are you using Validator to validate your data?

  • Using a query will keep your controller clean and minimal. But, for some time it is reasonable to use the validator in the controller, for example, you know there will be only one field to check, then it will overkill use FormRequest. So it's a matter of preference.
  • Query classes are the best way to validate queries as they help you extract this functionality from the constructor method, which should be as clean as possible.

Instead of using a Validator inside your controller, I suggest you use Requests to validate your form data. From your code, I can see that you are trying to save a contact form, so here's my suggestion:

Run this command, this will create a ContactRequest file inside the Requests folder:

php artisan make:request ContactRequest

      

ContactRequest file:

<?php

namespace App\Http\Requests;

use App\Http\Requests\Request;

class ContactRequest extends Request
{
    /**
     * 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()
    {
        return [
            'name' => 'required|min:5|max:20|alpha',
            'email' => 'required|email',
            'message' => 'required|max:250'
        ];
    }
}

      

Note. You must set the authorization to a value return true;

to avoid an authorized error.



Your controller:

<?php namespace App\Http\Controllers;

use App\Http\Requests\ContactRequest;

class ContactController extends Controller {

function __construct(Repository $repository)
{
    $this->repository = $repository;
}

public function store(ContactRequest $request)
{
    return $this->repository->store($data);
}

}

      

In your view file, you can handle errors like this:

    @if (count($errors) > 0)
        <div class="alert alert-danger">
        <button class="close" data-close="alert"></button>
                @foreach ($errors->all() as $error)
                    <span>{{ $error }}</span>
                @endforeach
        </div>
    @endif

      

Or, if you prefer to show errors one by one, you can do it like this:

{!! $errors->first('name', '<small class="help-block">:message</small>') !!}
{!! $errors->first('email', '<small class="help-block">:message</small>') !!}
{!! $errors->first('message', '<small class="help-block">:message</small>') !!}

      

Your data is only saved if the data is confirmed by ContactRequest.

Your method should now be reviewed in tests and you can see how clean your controller is.

+2


source


If you create a validator class this way, you don't need to use ::

.

Use $this->validator->make($data, $this->validatorRules);

instead and you should easily mock the output of the validation class.



As a side note, why are you mocking your validation? This is clean code and doesn't end up in an external service, so you should consider allowing these validation rules to work during your tests.

0


source







All Articles