0

I have been trying to learn about MVC pattern (without frameworks), however no matter material I read on the Internet, it just seems to be contradicting itself all the time.

My project right now consists of a form that can be submitted in order to add an element to the database. Another page just lists all the elements that are on the database.

So as I understand, my model should connect to the database (or just take the connection as a parameter, something else that was not very clear to me) and have functions like "saveItem" (which takes the $_POST variable as an input and parses it) and "listItems" (which just returns all entries to the page).

However, where does the controller come in? Now I parse my data in the model. But, if that should be rather done in the controller, what does the model actually do? I came across this page. Here, the model only has methods like "select" whose input is just a sql query. But this seems essentially just a PDO wrapper. (Contradicting information in this page about PDO already being a kind-of wrapper and there isn't really any need to do it.)

I guess it kind of makes sense, if the model was written as just a wrapper, it wouldn't actually have anything to do with the specifics of my website. (My understanding now is that each part of mvc is highly specific for each project.)

But then, it seems that either the model or the controller is just unnecessary. Either model parses the data leaving nothing for the controller to do or vice-versa.

I would be deeply grateful for any clarification.

kiloohm
  • 17
  • 4
  • 2
    The _domain_ part of your application has little to do with MVC. _Model_ refers to the data encapsulation presented to the _View_. _Controllers_ handle the requests – Phil May 30 '19 at 01:22
  • You might like to read a more generalised description of MVC. See https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller. Some frameworks like to tightly couple the model to your domain though that's not necessarily universal – Phil May 30 '19 at 01:26
  • 1
    The following resources will give you a better perspective on MVC: [this](http://confreaks.tv/videos/rubymidwest2011-keynote-architecture-the-lost-years) (see it as general guideline and keep viewing/reading the next links), [this](https://vimeo.com/101106002), [this](https://stackoverflow.com/questions/5863870/how-should-a-model-be-structured-in-mvc), [this](https://stackoverflow.com/a/55432977/9455607), maybe [this](https://stackoverflow.com/a/54203726/9455607). Don't hesitate to ask further, if you need to. – PajuranCodes May 30 '19 at 05:09

2 Answers2

1

I'd take this question rather as a genuine inquiry than a request to review some SEO spam article from Internet. So it goes:

What you need to understand in the first place is that the term "model" is ambiguous. It can represent either the whole application's business logic, or just what you meant - some piece of code that interacts with the database. To avoid this ambiguity, let's stick with the former. It will help you to settle with the Controller. Whereas we will call a "lesser model" a storage. A cover term for a code which actually interacts with the database.

I have a very concise writeup, MVC in simpler terms or the structure of a modern web-application. It will help you to wrap your head around MVC at whole.

Now closer to your question.

A database wrapper cannot be considered a model, in either meaning. A database wrapper is a service used by the storage class. So, you can have at least 3 layers in your application:

  • a controller. Just an interface to convey an HTTP client's request to the business model
  • a service or a helper. the code which is usually (and wrongly) written in the controller. For example, if you need to register a user, in the controller you are calling a method from a user service, providing the data came from the client.
  • a storage class. The actual code to interact with a database. For example it could be a User class that contain methods such as register and such. This class would use PDO (or some more advanced wrapper, or an ORM instance) as a class variable.

Where the latter two should actually encapsulate your whole application's business logic.

The most tricky part here is the instantiation of the Storage class. Given the connection must be done only once, there should be means to instantiate the UserStorage object providing it with the database connection. That is slightly different issue which is solved by means of the Dependency Injection Container

To illustrate the above with a bit of code

class UserController extends Controller
{
    public function create($request)
    {
        $userService = $this->serviceContainer->get('user_service');
        $userService->create(
            $request->email;
            $request->password;
        );
    }
}
class UserService
{
    public function create($username, $password)
    {
        // here, userStorage instance was already injected 
        // in the UserService in the controller by DI container
        $this->userStorage->create(
            $request->email;
            $request->password;
        );
    }
}
class UserStorage
{
    public function create($username, $password)
    {
        $sql = "INSERT INTO user VALUES (null, ?, ?)";
        // here, db instance was already injected 
        // in the UserStorage in the controller by DI container
        $this->db->prepare($sql)->execute([$username, $password]);
    }
}

It could be considered unnecessarily verbose, with all these seeming repetitions, but there are reasons for that:

  1. in the real code there are other parts in the each stage, For example,
    • Controller would validate the form submitted (like whether the form was actually submitted, whether passwords are equal, etc.) and call View to render the form.
    • UserService could perform additional validations, like whether such email already exists
  2. Different calling points
    • UserService could be called from many differnt places: from the above controller or a command line utility, or a REST controller.
    • UserStorage could be called from even more places. For example there is a TaskService that lists tasks belong to users, and it will naturally make a good use of the UserStorage class. And so on.

So it makes a perfect sense to separate your layers this way.

Of course it's just an oversimplified draft model, it doesn't implement an ORM which is usually here, and many other things. But the simpler the sketch is, the less details it have, the simpler to get the main idea.

Your Common Sense
  • 156,878
  • 40
  • 214
  • 345
  • I would suggest to use the [data mapper](https://martinfowler.com/eaaCatalog/dataMapper.html) term, instead of [repository](https://martinfowler.com/eaaCatalog/repository.html). The data mapper should be the one component accepting the db connection (PDO instance) and directly communicating with the db (through its API). – PajuranCodes May 30 '19 at 07:36
  • 1
    @dakis data mapper is too narrow and specific a term. it's just one of possible ORM variants, and ORM is not a good substitute either. However you are right, repository is misleading all the same. I will change it to a more appropriate term – Your Common Sense May 30 '19 at 08:01
  • I see. I didn't know about this specific ORM & data mapper situation. I appreciate your flexibility in choosing a more appropriate term. – PajuranCodes May 30 '19 at 09:49
0

I came across this page. Here, the model only has methods like "select" whose input is just a sql query. But this seems essentially just a PDO wrapper.

You're correct. In fact, this example is very poorly structured, and does not conform to any sensible conception of MVC design. I would recommend that you disregard it entirely and look for a better example.

  • The DB class (allegedly a "model") in this example is a database helper class. While this is a useful thing to have, it is not a MVC model in any sense, and this one is not particularly well written, either.

  • The Users class (allegedly a "controller") is not a controller. It is actually more akin to a model, as it attempts (awkwardly) to represent a business object as a class.

    (As an aside, extending a database helper class is a design "smell" which should be avoided -- it means that every object instantiated will create its own separate connection to the database.)

  • The list.php file (allegedly a "view") is not much of a view, either. While it provides some presentation functionality, it also takes on the role of a controller by operating on the model. In most MVC applications, views are implemented as pure template files -- often not even executable code -- which are passed data by a controller.

Now that we've properly torn apart this terrible tutorial:

A common architecture in MVC applications is the active record pattern, in which each table in your database (other than purely relational tables) is represented by a class, each row from those tables which has been loaded by your application is represented by an instance of that class, and each of those instances has methods which can be used to manipulate the contents of that row.

Implementing such an architecture usually requires some form of database mapper or ORM framework.