Dennis
Dennis

Reputation: 8111

Does business logic live in the Model or in the Controller?

After reading https://softwareengineering.stackexchange.com/questions/165444/where-to-put-business-logic-in-mvc-design/165446#165446, I am still confused as to where I want to put my code for computing discounts. Computing a discounted price for a product or service I think is definitely part of business logic and is not part of application routing or database interaction. With that, I am struggling where to place my business logic.

Example

class Model
{
    public function saveService($options)
    {
        $serviceId = $options['service_id'];

        //Model reads "line Item" from database
        $service = $this->entityManager->find('Entity\ServiceLineItem', $serviceId);
        //uses the data to compute discount
        //but wait.. shouldn't model do CRUD only?
        //shouldn't this computation be in Controller?   
        $discount = ($service->getUnitPrice() * 0.25);

        // Add the line item
        $item = new SalesItem();
        $item->setDiscount($discount);
    }
}


class Controller
{
    function save()
    {
        $this->model->saveService($options);
    }
}

Question:

Above $discount computation, should it stay in Model, or does it go into Controller? If it goes into Controller, Controller has to call $service (via Model) first, then compute $discount inside Controller then send it the value back to the Model to be saved. Is that the way to do it?

Note

I may be confusing Model with "Storage". I probably need to have a Model where I do business logic and Database/Persistent Storage should be a separate layer.

Upvotes: 1

Views: 3063

Answers (5)

Kbdavis07
Kbdavis07

Reputation: 1090

The Below Image shows how I think where your "Business" logic should go :)

enter image description here

The above image has the "Service" layer as the Server Side "Controller".

It is the middle man between the "Client" side Controller and the "Logic" layer.

All of your tasks that requires some type of "Logic" like

"Computing a discounted price for a product or service"

Would go into a ProductLogic Class where it takes inputs From the Service if needed and uses that information to help calculate the discounted price.

The ProductLogic Class will also query a "Data" source if needed to get the current price of an item.

The ProductLogic Class will piece together the information it collected from the Service and Repository to make the calculation and if it needs to be return to the user then the ProductLogic class will send it to the Service layer.

If it just needs to be saved in the Repository than the Logic will pass off the information to the Repository to handle.

Hope this helps :)

Have a great day!

Upvotes: 0

AirLancer
AirLancer

Reputation: 1418

Business logic belongs in a Service, so you would need to add a service layer.

Business logic tends to span multiple models, which infers that it does not belong in any single model. Therefore, it is unclear in which model you should put the logic.

Enter the service class. I tend to make a service for each use-case the software is designed for. In your case there could be a CheckOutService which would calculate your total sum, including discounts. That way each service has a specific and intuitive purpose. Then, when a controller requires some business logic, it calls a service tailored for that very purpose.

A good description of what a service does in the MVC pattern can be found here: MVCS - Model View Controller Service

I'll quote the most essential part:

The service layer would then be responsible for:

  • Retreiving and creating your 'Model' from various data sources (or data access objects).
  • Updating values across various repositories/resources.
  • Performing application specific logic and manipulations, etc.

edit: I just saw kayess answer. I'd say his answer is more precise than mine, but I don't know how relatable it is, given the degree of uncertainty in your question. So I hope mine can help some people in the earlier stages of their programming career.

Upvotes: 6

kayess
kayess

Reputation: 3394

Answering a question like this is usually opinionated or one could say it really depends on your business use case.

First off, i sense some mixup in your Model and service wording here. A model should be your domain model, and service should either be a domain or an application service, in a different class or a different layer.

Architecturally thinking you could follow a rather simplified DDD-ish implementation.

Namely:

  1. You implement all behavioural concepts in your domain model, which are related to the models current state
  2. Use a factory that will query the line item from the repository
  3. Use a domain service for mostly everything that's not related to your model, in your case calculating discount (if you need that logic reusable, for example in more models or services). You don't want to pollute your domain model with non related mechanisms and dependencies
  4. For persistence you better use a different layer and by this you better separate most concerns you can, a reason for this is testability and another reason -amongst many others- for less code changes later

To achieve a cleaner architecture and less pain by maintaing your code in the longer run, don't forget to think about how design patterns and SOLID principles could help you implement your solution to the given business use case.

Upvotes: 3

KDN
KDN

Reputation: 1399

The question about how to separate business logic from data is not easily answered. However, Daniel Rocco has constructed a good discussion of the subject that you may find helpful, if not for this particular problem, then for structuring business applications in general.

Upvotes: 1

Daniel
Daniel

Reputation: 1282

I used a framework called "Yii Framework" using MVC, what it had was a function called beforeSave() in the controllers that was used to change the model values just before saving them.

Following this logic maybe the best practice would be to apply the discount to your price just before saving the model (in your Controller)

Upvotes: 0

Related Questions