How Should a Model Be Structured in MVC

How should a model be structured in MVC?

Disclaimer: the following is a description of how I understand MVC-like patterns in the context of PHP-based web applications. All the external links that are used in the content are there to explain terms and concepts, and not to imply my own credibility on the subject.

The first thing that I must clear up is: the model is a layer.

Second: there is a difference between classical MVC and what we use in web development. Here's a bit of an older answer I wrote, which briefly describes how they are different.

What a model is NOT:

The model is not a class or any single object. It is a very common mistake to make (I did too, though the original answer was written when I began to learn otherwise), because most frameworks perpetuate this misconception.

Neither is it an Object-Relational Mapping technique (ORM) nor an abstraction of database tables. Anyone who tells you otherwise is most likely trying to 'sell' another brand-new ORM or a whole framework.

What a model is:

In proper MVC adaptation, the M contains all the domain business logic and the Model Layer is mostly made from three types of structures:

  • Domain Objects

    A domain object is a logical container of purely domain information; it usually represents a logical entity in the problem domain space. Commonly referred to as business logic.

    This would be where you define how to validate data before sending an invoice, or to compute the total cost of an order. At the same time, Domain Objects are completely unaware of storage - neither from where (SQL database, REST API, text file, etc.) nor even if they get saved or retrieved.

  • Data Mappers

    These objects are only responsible for the storage. If you store information in a database, this would be where the SQL lives. Or maybe you use an XML file to store data, and your Data Mappers are parsing from and to XML files.

  • Services

    You can think of them as "higher level Domain Objects", but instead of business logic, Services are responsible for interaction between Domain Objects and Mappers. These structures end up creating a "public" interface for interacting with the domain business logic. You can avoid them, but at the penalty of leaking some domain logic into Controllers.

    There is a related answer to this subject in the ACL implementation question - it might be useful.

The communication between the model layer and other parts of the MVC triad should happen only through Services. The clear separation has a few additional benefits:

  • it helps to enforce the single responsibility principle (SRP)
  • provides additional 'wiggle room' in case the logic changes
  • keeps the controller as simple as possible
  • gives a clear blueprint, if you ever need an external API

 

How to interact with a model?

Prerequisites: watch lectures "Global State and Singletons" and "Don't Look For Things!" from the Clean Code Talks.

Gaining access to service instances

For both the View and Controller instances (what you could call: "UI layer") to have access these services, there are two general approaches:

  1. You can inject the required services in the constructors of your views and controllers directly, preferably using a DI container.
  2. Using a factory for services as a mandatory dependency for all of your views and controllers.

As you might suspect, the DI container is a lot more elegant solution (while not being the easiest for a beginner). The two libraries, that I recommend considering for this functionality would be Syfmony's standalone DependencyInjection component or Auryn.

Both the solutions using a factory and a DI container would let you also share the instances of various servers to be shared between the selected controller and view for a given request-response cycle.

Alteration of model's state

Now that you can access to the model layer in the controllers, you need to start actually using them:

public function postLogin(Request $request)
{
$email = $request->get('email');
$identity = $this->identification->findIdentityByEmailAddress($email);
$this->identification->loginWithPassword(
$identity,
$request->get('password')
);
}

Your controllers have a very clear task: take the user input and, based on this input, change the current state of business logic. In this example the states that are changed between are "anonymous user" and "logged in user".

Controller is not responsible for validating user's input, because that is part of business rules and controller is definitely not calling SQL queries, like what you would see here or here (please don't hate on them, they are misguided, not evil).

Showing user the state-change.

Ok, user has logged in (or failed). Now what? Said user is still unaware of it. So you need to actually produce a response and that is the responsibility of a view.

public function postLogin()
{
$path = '/login';
if ($this->identification->isUserLoggedIn()) {
$path = '/dashboard';
}
return new RedirectResponse($path);
}

In this case, the view produced one of two possible responses, based on the current state of model layer. For a different use-case you would have the view picking different templates to render, based on something like "current selected of article" .

The presentation layer can actually get quite elaborate, as described here: Understanding MVC Views in PHP.

But I am just making a REST API!

Of course, there are situations, when this is a overkill.

MVC is just a concrete solution for Separation of Concerns principle. MVC separates user interface from the business logic, and it in the UI it separated handling of user input and the presentation. This is crucial. While often people describe it as a "triad", it's not actually made up from three independent parts. The structure is more like this:

MVC separation

It means, that, when your presentation layer's logic is close to none-existent, the pragmatic approach is to keep them as single layer. It also can substantially simplify some aspects of model layer.

Using this approach the login example (for an API) can be written as:

public function postLogin(Request $request)
{
$email = $request->get('email');
$data = [
'status' => 'ok',
];
try {
$identity = $this->identification->findIdentityByEmailAddress($email);
$token = $this->identification->loginWithPassword(
$identity,
$request->get('password')
);
} catch (FailedIdentification $exception) {
$data = [
'status' => 'error',
'message' => 'Login failed!',
]
}

return new JsonResponse($data);
}

While this is not sustainable, when you have complicate logic for rendering a response body, this simplification is very useful for more trivial scenarios. But be warned, this approach will become a nightmare, when attempting to use in large codebases with complex presentation logic.

 

How to build the model?

Since there is not a single "Model" class (as explained above), you really do not "build the model". Instead you start from making Services, which are able to perform certain methods. And then implement Domain Objects and Mappers.

An example of a service method:

In the both approaches above there was this login method for the identification service. What would it actually look like. I am using a slightly modified version of the same functionality from a library, that I wrote .. because I am lazy:

public function loginWithPassword(Identity $identity, string $password): string
{
if ($identity->matchPassword($password) === false) {
$this->logWrongPasswordNotice($identity, [
'email' => $identity->getEmailAddress(),
'key' => $password, // this is the wrong password
]);

throw new PasswordMismatch;
}

$identity->setPassword($password);
$this->updateIdentityOnUse($identity);
$cookie = $this->createCookieIdentity($identity);

$this->logger->info('login successful', [
'input' => [
'email' => $identity->getEmailAddress(),
],
'user' => [
'account' => $identity->getAccountId(),
'identity' => $identity->getId(),
],
]);

return $cookie->getToken();
}

As you can see, at this level of abstraction, there is no indication of where the data was fetched from. It might be a database, but it also might be just a mock object for testing purposes. Even the data mappers, that are actually used for it, are hidden away in the private methods of this service.

private function changeIdentityStatus(Entity\Identity $identity, int $status)
{
$identity->setStatus($status);
$identity->setLastUsed(time());
$mapper = $this->mapperFactory->create(Mapper\Identity::class);
$mapper->store($identity);
}

Ways of creating mappers

To implement an abstraction of persistence, on the most flexible approaches is to create custom data mappers.

Mapper diagram

From: PoEAA book

In practice they are implemented for interaction with specific classes or superclasses. Lets say you have Customer and Admin in your code (both inheriting from a User superclass). Both would probably end up having a separate matching mapper, since they contain different fields. But you will also end up with shared and commonly used operations. For example: updating the "last seen online" time. And instead of making the existing mappers more convoluted, the more pragmatic approach is to have a general "User Mapper", which only update that timestamp.

Some additional comments:

  1. Database tables and model

    While sometimes there is a direct 1:1:1 relationship between a database table, Domain Object, and Mapper, in larger projects it might be less common than you expect:

    • Information used by a single Domain Object might be mapped from different tables, while the object itself has no persistence in the database.

      Example: if you are generating a monthly report. This would collect information from different of tables, but there is no magical MonthlyReport table in the database.

    • A single Mapper can affect multiple tables.

      Example: when you are storing data from the User object, this Domain Object could contain collection of other domain objects - Group instances. If you alter them and store the User, the Data Mapper will have to update and/or insert entries in multiple tables.

    • Data from a single Domain Object is stored in more than one table.

      Example: in large systems (think: a medium-sized social network), it might be pragmatic to store user authentication data and often-accessed data separately from larger chunks of content, which is rarely required. In that case you might still have a single User class, but the information it contains would depend of whether full details were fetched.

    • For every Domain Object there can be more than one mapper

      Example: you have a news site with a shared codebased for both public-facing and the management software. But, while both interfaces use the same Article class, the management needs a lot more info populated in it. In this case you would have two separate mappers: "internal" and "external". Each performing different queries, or even use different databases (as in master or slave).

  2. A view is not a template

    View instances in MVC (if you are not using the MVP variation of the pattern) are responsible for the presentational logic. This means that each View will usually juggle at least a few templates. It acquires data from the Model Layer and then, based on the received information, chooses a template and sets values.

    One of the benefits you gain from this is re-usability. If you create a ListView class, then, with well-written code, you can have the same class handing the presentation of user-list and comments below an article. Because they both have the same presentation logic. You just switch templates.

    You can use either native PHP templates or use some third-party templating engine. There also might be some third-party libraries, which are able to fully replace View instances.

  3. What about the old version of the answer?

    The only major change is that, what is called Model in the old version, is actually a Service. The rest of the "library analogy" keeps up pretty well.

    The only flaw that I see is that this would be a really strange library, because it would return you information from the book, but not let you touch the book itself, because otherwise the abstraction would start to "leak". I might have to think of a more fitting analogy.

  4. What is the relationship between View and Controller instances?

    The MVC structure is composed of two layers: ui and model. The main structures in the UI layer are views and controller.

    When you are dealing with websites that use MVC design pattern, the best way is to have 1:1 relation between views and controllers. Each view represents a whole page in your website and it has a dedicated controller to handle all the incoming requests for that particular view.

    For example, to represent an opened article, you would have \Application\Controller\Document and \Application\View\Document. This would contain all the main functionality for UI layer, when it comes to dealing with articles (of course you might have some XHR components that are not directly related to articles).

Yes or no: Should models in MVC contain application logic?

Generally I try to keep controllers simple in terms of logic too. If business logic is required, it will go up to 'service layer' classes to handle it. This also saves repeating any code/logic too, which ultimately makes the whole project more maintainable if business logic was to change. I just keep models purely as entity objects.

I think the answer above sums it up nicely though, it is easy to over engineer a project based on design patterns: Go with whatever works for you and is most maintainable/efficient.

What is the role of model in MVC and how to make it work?

The Model is supposed to interact with the Database class since in an MVC model Model is responsible for fetching the data, process it and pass to the view. In your case the blog class (which derives from Controller) which does not follow MVC model. Instead it should instantiate an "article" class instance and pass the control to "article" class to fetch the data from database.

You article.php should look like

<?php
class Article extends Database {
public $id;
public $topic;
public $content;
public $database; //Dependency injection

//This method has been moved from the blog class
public function each(&$data, $blogid = '') {
// Query the database here
$result = $this->database->call('select * from articles where id='.$blogid);
while($rows = $result->fetch_assoc()) {
$data['id'] = $rows['id'];
$data['title'] = $rows['title'];
$data['content'] = $rows['content'];
}
}

public function inject() {
$query = 'insert into articles(title, content) values (\'test2\', \'test2\')';
$this->database->inject($query);
}
}
?>

and the blog.php should be

<?php
class Blog extends Controller {

protected $article;

public function __construct() {
/* Load data structure of Entry.php */
$this->article = $this->BuildData('Entry');
}

public function all($linkname='LINK BACK HOME') {
$this->loadtemplate('blog/blog', array('linkname'=>$linkname));
}

public function getData($blogid = '') {
$data = array();
$this->article->each($data, $blogid);
$this->loadtemplate('blog/each', $data);
$this->article->inject();
}
}
?>

Couple of things to notice:

  1. The model only interacts with data. In future if you change the datastore (move to cloud from the database) you need to change only the model.
  2. The controller has all the business logic to construct the view based on the data. When your application gets complicated the controller will change. This design principle is called "separation of concerns" where the controller and the model are responsible for completely separate functionalities now.

MVC - Model - View Model Structure

ViewModel, as the name suggests, its just an another representation of your model in other form. The concept is to provide your model with different views for rendering. Think it this way, if you have a category model and a picture model and you need to render them in view for new record creation. There are two ways you can handle this : one way is to pass one model as parameter and hold other in the ViewBag dictionary and the other (preferred way) is to make a view ViewModel like following merging both the entities in one.

public class CatPicView
{
public Category Category { get; set; }
public Picture Picture { get; set; }
}

MVC: should view talk with model directly?

The following is a representation of dependencies in classical MVC architecture. You will notice that there is no arrow pointing from controller to view, because it is newer addition:

enter image description here

Source: GUI architectures

And then there is dependency map that is closer to what you will usually see in "MVC frameworks":

Passive View

Source: Passive view

The "passive view" configuration is not part of MVC architecture. While it uses the same names, it actually is a variation on MVP pattern (you can find a longer and more detailed description in this publication)

Bottom line: yes, if you are implementing MVC or MVC-like architecture, then your views should be requesting information from the model layer.

Also, you should note that this is NOT what so-called "mvc frameworks" are pushing for. In the Rails-like frameworks there is no view. Instead (since the original structure was made for prototyping) the views are replaced with dumb templates and all the responsibilities of a view are pushed into something they call a "controller".

Basically, IMHO, the best way to name Rails-like patterns would be OLT: ORM-Logic-Template.

How should I structure my code when the MVC's model do not match the database model?

My question, where should I put this code?

The mapping between your domain models and view models should ideally be placed inside a separate and dedicated mapping layer. For example if you use AutoMapper, which I would recommend, you could place your mapping definitions inside separate files called profiles and inside the controller action simply call the Mapper.Map<TSource, TDest> method.

Another related question is where should I put the repository class?
Up until now I've put repository classes allong side the model class
in the same .cs file since every model had a corresponding repository.

The DAL represents the data access layer and is where the repositories should go. You could define a common contract (interface) that the repositories must obey (implement) and then have several implementations against the different data sources that you are working with.

how to structure MVC models and ORM models

The first thing you should understand is that the Model in MVC is not a class/object. It is a layer, made from a multitude of objects. I'm too lazy to do the same song'n'dance again , so just read this comment (skip to the "side notes" section).

The root of your confusion lies in the fact that you recognize two different responsibilities in the group of classes you call "models". You are actually having class instances responsible for business logic ( like your UserModel class ), and a separate thing called "ORM", which loads and stores content. And you have authentication, which does not fit in either of the groups.

I would go with a structure like this:

/application
/modules
/public
/controllers
/templates
/admin
/controllers
/templates
....
/views
/model
/logic
/persistence
/services
/framework

You might notice that there is a separate /views folder in /application and also each module has a separate /templates. That is because, in proper MVC the Views are instances of classes, responsible for presentation logic and usually juggle multiple templates. If well written, they too are a reusable structure.

And the final note: Do not try to use ORMs. Make a datamapper for each domain object which requires it. Some people consider ORMs to be antipatterns. Also, avoid static calls .. thats not OO code. You could benefit a lot from learning about dependency injection

.. my 2 cents



Related Topics



Leave a reply



Submit