Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should I fully separate Models and ORM in MVC?

I am working on an MVC application in PHP that is not using any frameworks. I am using RedBean for my ORM, which implements the datamapper pattern and works quite similiar to doctrine.

As per this question, I understand that the model is NOT the ORM object. In my project I have the following scenarios:

  • "Complicated" Models which need to talk with a lot of tables in the database:

    • One of these models can be something like the RBAC permissions system. A controller should be able to call something like $permission->isAllowed($controller, $action, $resource) to determine if the user is allowed to perform the requested action. In addition, he might call $permission->getPermissions() to get a list of permissions the user has.
  • "Simple" models where the model can generally be represented by 1 table in the database:

    • One such model would be the User model. For example $user->changeRank(), $user->addPoints() and so on.

The problem I am facing now is that looking at most documentation for various frameworks, I can see that in the examples, the controller talks with the ORM directly. For example, here's an example controller from symfony2:

public function createAction()
{
    $product = new Product();
    $product->setName('A Foo Bar');
    $product->setPrice('19.99');
    $product->setDescription('Lorem ipsum dolor');

    $em = $this->getDoctrine()->getEntityManager();
    $em->persist($product);
    $em->flush();

    return new Response('Created product id '.$product->getId());
}

If an ORM is NOT the model, why is the controller allowed to interact directly with it? Shouldn't it interact with a Model that looks like this?

class ProductModel{
   public function newProduct($name, $price, $description){
        $product = new Product();
        $product->setName('A Foo Bar');
        $product->setPrice('19.99');
        $product->setDescription('Lorem ipsum dolor');

        $em = $this->getDoctrine()->getEntityManager();
        $em->persist($product);
        $em->flush();
   }
}

Finally, I outlined the permissions model earlier. Is this considered to be a model in the context of MVC? This class will be used across the whole application, as most abctions will need to check for access permissions.

like image 451
F21 Avatar asked Nov 19 '11 06:11

F21


1 Answers

An ORM (Object Relational Mapper) is used to generate model files. Model files are used to communicate between the application and database (model). It seems you are versed in the ORM processes, but a quick re-cap (using doctrine as an example), for those who may not be, and I might get lucky and answer your question.

You use the ORM to introspect your database schema, which generates a schema file. Now with this schema file you can alter it to suit your application needs. For example, you can add actAs: { Timestampable ~}, or actAs: NestedSet: hasManyRoots: true. Also, you will want to use this schema file to setup how you want relations between objects to behave (i.e. 1:M, M:M using a refClass, etc.)

Once your schema file is ready to go, you issue the command to generate the model files. The model files are classes which you can use within your application to gain access to the database. So the controller is actually communicating with the model (your database) through the files generated by the ORM.

The example you gave is a good one, in that you can offload much of the business logic out of your action (page controller) and into your model. This way the same logic can be accessed from other code-points without having to deal with any controller level logic. What doctrine does (and propel does too), is allow you to create 'Table' (or 'Peer') classes. These classes act as containers for dealing with multiple objects. It's within these classes you should add your business logic as you demonstrated in your second example.

The ultimate goal is to keep your actions as lightweight as possible, just dealing with request params and form handling, then push the values to your model via 'Table' or custom classes you design. Following this paradigm you can have a feature rich application with trim actions and centralized business logic.

Edit ---

Sorry I missed your last question regarding your permission API. From what you posted, it does appear to follow the MVC paradigm in that you have a permission object and are using as a API between the controller and database.

like image 136
Mike Purcell Avatar answered Oct 21 '22 16:10

Mike Purcell