Models, Repositories, Service classes & Jobs (commands)

498 Views Asked by At

I need some help in understanding what part each play in a large application. I'll start first with a scenario:

  • as usual there will be User
  • an user must have a MembershipType (free, basic, business).
  • an user can have (not required) a Business (User has one or zero Business)
  • an user can have a Subscription (User has one or zero Subscription).
  • a subscription requires a SubscriptionPlan which is related to the MembershipType. So a membership type of 'basic' would have in Stripe a 'basic2015' plan; a 'business' would have a 'business2015' plan.
  • an user has Address (User many to many Address)
  • a basic user must have a 'personal' address on file while a business user must have a 'business' address on file
  • there are other requirements but this will be sufficient to get the better picture

So far I have these Models: User, MembershipType, Business, Subscription, SubscriptionPlan and Address.

Some of the business logic requires me to have at least the following methods: - user isBusiness() - user hasAddress(type) where type is (personal or business) - membership type getPlanForCurrentYear()
- other things required but I'll stop here

Now, an example: John registers and is required to provide basic information (email, password, name). He signs up as a business. After this basic registration process he get's Logged In and notified that he is required to complete their profile before getting access. He is required then to provide a business information (name, website, email, phone). Also I need the business address. He then has to subscribe to the current year plan 'business2015'.

All of this I have managed to do it, but I done it in my controllers. As some suggested in other posts, first make it work and then decide if you need to extract it to repositories. Well, I have got to the point where I am sure I need to use repositories because it get's more and more complicated and I have to constantly modify my controllers. So after lot of research I am still empty on how to make my DB to UI work both ways without a mess.

My research led me to the fact that I need to use Repositories, maybe Service Classes and Jobs. Can someone share some thoughts on what I will need to have a good architecture?

  1. Will I need a Repository for each Model? Have an interface and abstract repository with general methods (all, getId, create, update, delete, etc). If so how would I relate repositories between themselves?

  2. Do I need service classes (like RegisterUser, CompleteProfile) that orchestrate all the repositories involved at certain time?

  3. How should I use Jobs in this scenario? Dispatch them from the controller and inject a Repository or a Service class?

  4. Is there an example somewhere of large applications in Laravel (open source) that I can look at a understand some of the principles involved?

Thank you.

1

There are 1 best solutions below

3
Gravy On

1 & 2. At the moment, you are querying your database via models in the controller. Start by Writing a middle layer outside of your controller. This can be called a service layer. So lets assume a user wants to register, and POSTs to the store method of your controller.

Create a UserService and add a method register. Let your service talk to the model. and your controller talk to the service.

UserController extends BaseController {

    // Dependency injected the UserService
    public function __construct(UserService $userService) {
        $this->userService = $userService;
    }
    public function store(){
        // validate input

        // register the user
        if (!$this->userService->register($input)) {
            // return error
        }
        // return success
    }
}

class UserService {
    protected $user;

    // Dependency injected the User model.
    public function __construct(User $user) {
         $this->user = $user;
    }

    public function register($input) {
         return $this->user->create($input);
    }
}

Once you have the hang of this, then you can think about interfaces and abstracting a further layer.

Forget interfaces for the time being - you probably won't need them quite yet. Interfaces are really good when you might swap out an implementation further down the line. e.g. Now you are using Stripe Billing, but one day you may wish to use Paypal, so you program your payments system to an interface, which is basically a contract stipulating exactly the public methods which need to be exposed.

  1. You dont need jobs yet.

  2. As per my previous comment, www.laracasts.com is a really good resource.

Once you have got the hang of abstracting out the details from your controller, the rest should come naturally and in time.