0

I use the Laravel framework. I've got controllers, like CustomerActivityController, and I've got a service layer with services like CustomerActivityService. Say I want to create a new customer activity via an API call in JSON format. The controller receives a JSON string as request data, and that JSON is parsed to an array.

array(
    'user_id' => 9,
    'customer_id' => 123,
    'activity' => 'Made a phone call',
    'date' => '...'
)

So my first step (in controller) is converting the input format to some universal data like an array.

Then I validate the values in the array, using Illuminate\Support\Facades\Validator.

In my controller method, this looks like:

$dataArray = \json_decode($request->input('json'), true);
$validator = Validator::make($dataArray, [
    'user_id' => 'required|integer|gt:0',
    'customer_id' => 'required|integer|gt:0',
    'activity' => 'required|string',
    'date' => 'required|date'
]);

if($validator->fails()) {
    // ... error response.
}

// Input considered valid, go on... 
$this->_customerActivityService->createActivity($dataArray);

And I do it that way everywhere.

At the line $this->_customerActivityService->createActivity($dataArray); The $dataArray is still not really 'valid', because the user_id or customer_id could be incorrect (non existent for example).

I see this as a separate kind of validation, because this is not just validating raw data, but more in-dept logic based on other data. In my opinion, this should definitely be validated in the service. At least not in the controller.

The questions I'm asking myself:

  1. I have validation in several different places. I could just move the raw-data validation to my service, but then the service is tightly coupled to the request format (because the service would get a Request object or JSON string as its method parameters). My service must be re-usable for any request type. (So I can have different controllers for Web/API/..., but the same service).

  2. I wonder how best to pass the data to the service.

    • Just accept an array as input to my service: $this->_customerActivityService->createActivity($dataArray) This seems to have the disadvantage that the array must have correct keys and doesn't miss any required segments. You have to know the array format and probably read the documentation of the service method, or read/analyze the service code.

    • Have separate parameters for each 'property' of the data. $this->_customerActivityService->createActivity($userId, $customerId, $activity, $date) Advantage: method signature is descriptive. Disadvantage: the parameter list could be insanely long for bigger data structures, and you almost can't handle hierarchical data.

    • Accept a data object. $this->_customerActivityService->createActivity($activityInstance)

  3. Since the raw-data validation is done in the controller, and the service does the 'logic' validation, the service 'trusts' its input. The service could accidentially be called with wrong input data if the programmer that uses the service made a mistake. Like putting -12 as a $user_id in a service method call.

1 Answer 1

-1

Very detailed use case, there are couples of solution to this, however a way i would approach this following the SOLID principle, i will create a rule to handle the request validation and have all request logic in it. Would exploit the withValidation() method in the laravel request class binding my validation to the request class which has been resolved by the service container, then have an abstract class validate the request attributes. this should be a good use case to tightly coupling, the request class handles the request validation and service class handles its login.

Not the answer you're looking for? Browse other questions tagged or ask your own question.