2

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.

Cristian
  • 2,390
  • 6
  • 27
  • 40
  • Voted to close. Your question is basically asking how to architect an entire application. It is far to broad. Laracasts.com has good tutorials on what to use Services, Controllers, Commands, Repositories for etc. – Gravy Oct 06 '15 at 19:03
  • @Gravy I tried to explain the best I could. Is it too broad? Well, depends how you think about it. I don't need to get the entire architecture out of this but a start. Nothing by a start. I want something from people more experienced than me. A simple answer could help me redirect my attention and focus on what is needed. – Cristian Oct 06 '15 at 19:06

1 Answers1

1

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.

Gravy
  • 12,264
  • 26
  • 124
  • 193
  • Thanks! You talk here about User Service as a buffer between Controller and Model? Is this the same as a Repository? I found on github, Laravel.io's source code and from first look they do something like this: Controller talks to a Service which talks to the Repository which talks to the Model which talks to the DB. Like this: UserController inputs data, sends it to UserCreatorService, which gets the UserRepository which in turn gets the UserModel. Am I on the right path? – Cristian Oct 06 '15 at 19:41
  • Btw, I am on Laracasts and watched lots of videos on Repositories, etc but I just can't seem to get the bigger picture! – Cristian Oct 06 '15 at 19:42
  • The Service layer should contain business logic. So, when you want to register a user, you might need to: email the user and other actions after storing in the db. So you would put this logic in the service layer. – Gravy Oct 06 '15 at 19:44