Good question.
The immediate thought process I would think of when going through this question is - is there a class I am already using that can handle the functionality without breaking the Single Responsibility Principle? If there is, then yes - you've over-complicated/over-engineered it. If you haven't, then you're on the right track.
In respect to your form objects - I actually have setup a more generalised solution - services. Services handle particular use-cases, and will talk to validation and persist data to storage via the repositories. The only issue I take with the term "Form", is that it stipulates that that data will only ever come from a form. And this is probably true for 90% of cases - but what about the times when you have to run a cron-job, or you're seeding data.etc?
I think you're on the right track, but there appears to be a lot of redundant code in your example, in that - it looks like code that would show up in many different controller actions. My thought there is what can you do to simplify it? Exceptions are a good way to do this, which I talk about in my Validations presentation at Laracon. That way you can write your code with the assumption that everything has worked fine - and have response handlers deal with those exceptions when they arise, thereby cutting down your controller code substantially.
Hope that helps :)
Thanks Kirk,
That is definitely food for thought.
I'm scratch my head with regards to your idea of using Custom Exceptions and I can see how this would cut a load boiler plate out.
You also mention "services". I am using Services in my app. Admittedly as a self taught OOP dev - its my notion/heavily influenced by the internet of what that entails.
This is my project structure.
In regards to Single responsibility - I am not certain how to achieve this.
My test project is basically creating a Contact book.
Party = Person or Org with relations X number of telephone X number of Emails X number of Addresses
To Save a New contact, I am using a Repository. Injecting via Service Providers the relevant models and doing the logic in the STORE method.
If I lose my Form Object that is currently handling Validation - Do I put it in the Repo?
The light bulb has gone on in respect of handling failed validation - Custom Exception and event Listener.
But the actual code that exists to loop my JSON payload, then test against the relevant models Repo Injected Validator has to sit some where. If I put this in the REPO does this break single responsibility.
I feel this simple scenario is holding me back from being able to fly the project.
I feel I need someone qualified (more qualified than me) to say - YUP thats the way you do it. ! OR No this is a better way.!
Based on what you write above and taking what experience I have from learning Solo - my best guess on moving forward would be:
Im still not sure.
You write:
In respect to your form objects - I actually have setup a more generalized solution - services. Services handle particular use-cases, and will talk to validation and persist data to storage via the repositories.
I would love to hear more on this. Anything specific or maybe an example.
Once again - THANK YOU - for taking the time to help.
Okay - so firstly, I will admit that your follow up questions I'm finding a little hard to read, so I apologise if the below answer does not address your needs.
Secondly, repositories should ONLY be for creating and managing database objects. What do I mean by this? I mean that any call you make to a repository, should only ever be persisting data, deleting data, or retrieving data. If it's doing anything else for a particular model, then it's doing too much and breaking single responsibility principle.
For validation - put the validation call in the service, but have a separate validation class PER USE CASE. This will allow validation to do only that. I'm working on an article that will highlight this a little more clearly, as well as an article of how to use repositories reponsibly. Let's say for example, you have a user registration use case, the code path should look like this:
POST to /users/register/ (or something)
User controller that handles registration should have a dependency on the UserRegistration service.
UserRegistration service class calls validation, something like:
(new UserRegistrationValidation($input)->validate());
If validation fails, it'll throw an exception which you can handle
Next line should be dealing with the users repository:
$user = $this->usersRepository->registerWith($input);
Make a call to the repository, create the user. You then have a user object you can do whatever you want with.
return $user;
This should be your last line in your service's register method.
Now, back in your controller, you simply handle the $user however you want:
$this->session->logIn($user); // or something of that nature
return Redirect::to('some action');
This obviously isn't the only way to deal with it, there are many different approaches. The problem with using lots of services, or commands if you'er going the DDD route, is how to handle all those layers. What used to be a 3-layer approach (MVC), is now fast becoming 5 or 6 layers. You don't want to be passing back information all the time, because an error that occurs 6 layers down will be very hard to manage (which is why you want to start using exceptions more).
In regards to your structure - I'd break it down by domain/module. For example, have a Users folder that has all the validation, services, models and repositories specific to users.
Whenever you create or delete or save a user - fire an event, then let other modules deal with related data/content.
Hope that helps!
Sign in to participate in this thread!
The Laravel portal for problem solving, knowledge sharing and community building.
The community