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.
How to interact with a model?
Prerequisites: watch lectures "Global State and Singletons" and "Don‘t Look For Things!" from the Clean Code Talks.
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
The easiest way to make sure that both View and Controller instances (for that incoming request) have access to the same version of the Model Layer would be to provide them both with the same ServiceFactory
instance. I would do it like this:
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:
How to interact with a model?
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:
The easiest way to make sure that both View and Controller instances (for that incoming request) have access to the same version of the Model Layer would be to provide them both with the same
This would let you initialize a not-too-complicated MVC application (notice that there is no caching nor authentication/authorization included). As you can see, the Also, you might notice that the anonymous With this given code, the Controller instance would change the state of the Model Layer, and the View instance (as per Model2 MVC) would request data from the Model Layer. 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:This might be a simplified authentication method in a recognition service (something that ascertains a user‘s identity). But you should not think of this example as directly related to the one above, because as part of the authentication process, it should happen right after the
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. P.S. This would also be the part where caching is introduced. For example, as an additional Mapper. Some additional comments:
|