The question is more about MVC principles, but I will describe a specific issue just to make it clear.
I am working on an app for a training center. I have students that get enrolled into classes (M:N relationship), and each student must have an online user account. My job is to create a form for bulk user account creation, so that the instructor of that class can enter all student accounts info for the class on one page (don't ask why, its not relevant; I just have to do this). The thing is, I'm stuck trying to figure out where to put the complexity of the operation or how to break it down into smaller pieces.
All student data for the class is already in another table; I just have to pull it out and generate the form that displays account data. The instructor adjusts data if necessary and then hits "create all accounts"; accounts are created and users are notified by email.
The following approach is wrong and I want to correct it but it's not very clear what's the best way to do it:
- I have created a POST route that processes form data that points to ClassController@createAllUserAccounts()
- the form generates a nice multi-dimensional array with all user account data indexed by user
- in the createAllUserAccounts() method:
- I have to validate incoming data. In order to move some of the complexity out of the controller I used a trait for creating self-validating models, and I moved student validation to the Student model. So I only validate the array in the controller
- I loop through the request data and I create user accounts one by one; all of this is done on a transaction, so that if one account creation fails the whole process is cancelled
- I have to notify users after their account gets created, but only after the whole process has ended (which means that I have to loop through them again at the end...?)
Those are a lot of operations, and clearly I'm on the wrong path. But what can I do with that complexity - because those operations have to be done eventually, I can't just eliminate them; which means that a part of the "action" has to move somewhere else. I have read about "skinny controllers and fat models", but creating a fat model means that it no longer does one thing (so it breaks the SRP). So if it's not in the controller and not in the model (and clearly not in the view), where does it go? Should I create a separate class (some kind of service object) that enrolls users into a class?
I have also read about Registries, but in my mind they are a way of decoupling my app from the storage solution below, it's not clear to me if they are the right place to move the complexity. And I suspect that I'm asking the wrong thing: that complexity doesn't only have to be moved out of the controller, but also distributed somehow. I guess having a 100-lines method is a code smell anyway...
As you can see, the question is not related to a certain scenario: in general, how do I keep my controllers thin without fattening the models?