Properly Calling the Database from Model in an MVC Application

Properly calling the database from Model in an MVC application?

Warning:
The information in this posts is extremely outdated. It represents my understanding of MVC pattern as it was more then 2 years ago. It will be updated when I get round to it. Probably this month (2013.09).




Damn it! (2017.11).

Model itself should not contain any SQL. Ever. It is meant to only contain domain business logic.

The approach i would recommend is to separate the responsibilities, which are not strictly "business logic" into two other other sets of constructs : Domain Objects and Data Mappers.

For example, if you are making a blog, then the Model will not be Post. Instead most likely the model will be Blog , and this model will deal with multiple Domain Objects: multiple instances of Post, Comment, User and maybe other objects.

In your model, the domain objects should not know how to store themselves in database. Or even be aware of the existence of any form of storage. That is a responsibility of Data Mappers. All you should do in the Model is to call $mapper->store( $comment );. And the data mapper should know how to store one specific type of domain objects, and win which table to put the information ( usually the storage of of single domain object actually affects multiple tables ).


Some code

(only relevant fragments from files):

  • I assume that you know how to write a good constructor .. if you have doubts, read this article
  • nothing is namespaced in example, but it should be
  • anything that begins with _ in example is protected

from /application/bootstrap.php

/* --- snip --- */

$connection = new PDO( 'sqlite::memory:' );
$model_factory = new ModelFactory( $connection );

$controller = new SomeController( $request , $model_factory );

/* --- snip --- */

$controller->{$action}();

/* --- snip --- */
  • controller does not need to be aware of database connection.
  • if you want to change DB connection for whole application, you need to change single line
  • to change the way how Model's are made, you create different class which implements same interface as ModelFactory

from /framework/classes/ModelFactory.php

/* --- snip --- */

class ModelFactory implements ModelBuilderInterface
{
/* --- snip --- */

protected function _prepare()
{
if ( $this->_object_factory === null )
{
$this->_object_factory = new DomainObjectFactory;
}
if ( $this->_mapper_factory === null )
{
$this->_mapper_factory = new DataMapperFactory( $this->_connection );
}
}

public function build( $name )
{
$this->_prepare();
return new {$name}( $this->_object_mapper , $this->_data_mapper );
}

/* --- snip --- */

}
  • only data mappers will use database , only mapper factory need connection
  • all the dependencies of Model are injected in constructor
  • every DataMapper instance in the application uses same DB connection, no Global State (video) required.

file /application/controllers/SomeController.php

/* --- snip --- */

public function get_foobar()
{
$factory = $this->_model_factory;
$view = $this->_view;

$foo = $factory->build( 'FooModel' );
$bar = $factory->build( 'BarModel' );

$bar->set_language( $this->_request->get('lang') );

$view->bind( 'ergo' , $foo );

/* --- snip --- */

}

/* --- snip --- */
  • controller is unaware of model creation details
  • controller is only responsible for wiring and changing the state of elements

file /application/models/FooModel.php

/* --- snip --- */

public function find_something( $param , $filter )
{
$something = $this->_object_factory('FooBar');
$mapper = $this->_mapper_factory('FooMapper');

$something->set_type( $param );
$mapper->use_filter( $filter )->fetch( $something );

return $something;
}

/* --- snip --- */
  • domain object is responsible for validating the given parameters
  • view receives and decides how to present it
  • mapper takes the object and puts in it all the required information from storage ( it doesn't have to be DB .. it could be taken from some file, or an external REST API )

I hope this will help you understand the separation between DB logic and business logic ( and actually , presentation logic too )


Few notes

Model should never extend Database or ORM, because Model is not a subset of them. By extending a class, you are declaring that has all the characteristics of the superclass, but with minor exceptions.

class Duck extends Bird{}
class ForestDuck extends Duck{}
// this is ok

class Table extends Database{}
class Person extends Table{}
// this is kinda stupid and a bit insulting

Besides the obvious logic-issues, if your Model is tightly coupled with underlaying Database, it makes the code extremely hard to test (talking about Unit Testing (video)).


I personally think, that ORMs are useless and in large project - even harmful. Problem stems from the fact that ORMs are trying to bridge two completely different ways of approaching problems : OOP and SQL.

If you start project with ORM then, after short learning curve, you are able to write simple queries very fast. But by the time you start hitting the ORM's limitations and problems, you are already completely invested in the use of ORM ( maybe even new people were hired , who were really good at your chosen , but sucked at plain SQL ). You end up in situation where every new DB related issue take more and more time to solve. And if you have been using ORM based on ActiveRecord pattern, then the problems directly influence your Models.

Uncle Bob calls this "technical debt".


Few books

loosely related to subject

  • Patterns of Enterprise Application Architecture
  • Agile Software Development, Principles, Patterns, and Practices
  • SQL Antipatterns: Avoiding the Pitfalls of Database Programming
  • PHP Object-Oriented Solutions
  • PHP in Action

How to call model methods in controller in asp.net mvc

In general practice you should now follow this methodology.
Although this is the default MVC behavior of accepting entire model as an argument you should have a middle layer called as DTO(Data Transfer Object) or ViewModel which represents UI.
And after accepting and validating View model you can transform it to your main business entity.
Offcouse it depends how you have written code in your update method but the main hack is this case is that.... any body can pass any known property value to this method and can hack your system. for example suppose you have following values in your Employeemodel
{
Id,
Name,
SecurityCode,
...
}

and your edit screen just have Name input to update it. Any body can add extra html for SecurityCode and can add bad value to it :)
I hope i didn't confused you.
For start try to implement Repository pattern MVC... Google it and you'll find the basic usage of it. :)

Cheers

In a MVC application, should the controller or the model handle data access?

All business logic should be in the MODEL.

Remember, the responsibilities of each layer are thus:

  • Controller - bridge between the model and view. Decides where to go next.
  • View - displays the data, gathers user input
  • Model - business logic, interface to data store.

One of the biggest gains is in maintenance and (later) expansion. In general:

  • If you need to change business logic, you should not need to modify your controller or view.
  • If you change your visual display, you should not need to modify your model or controller.
  • If you change your workflow, you should not need to modify your view or model.

To do the above, each layer should have no knowledge of the others in order to work properly. For example, the view should receive its data and not need to know anything about where it comes from in order to display it properly. The controller should not need to know anything about the underlying structure of the model in order to interact with it. The model should have no knowledge of how the data is to be displayed (e.g., formatting) or the workflow.

"He also believes that any call that returns a Json object should happen in the model, not in the controller. The model would return an array to the controller, which would then return this as a Json object."

NO. The Model should never format data. It also should not read formatted data. That is polluting the model and moving into the level of hell where business logic = display logic.

JSON (coming in or going out) is just another view. So going out:

Data Store -> Model -> Controller -> View

Coming in:

View -> Controller -> Model -> Data Store

Correct way to call a database into a view

FYI: view is not a template. In properly implemented MVC, views are instances (as in - objects made from classes) that are responsible for all of the UI logic. To achieve it, they often juggle multiple templates.

The confusing part about DB connection (and interaction with any other form of storage) is that it is required only at very low-level structures - data mappers book chapter.

The connection itself should be provided to each data mapper (that requires it, because not all mapper would work with SQL database) instance through factory. Code example here - the relevant part is the StructureFactory class definition.

The factory for creating data mappers would injected in an instance, which need to use the mappers. Otherwise would be violating LoD.

The view should not have any idea about the origin of data. It would only request some information from model layer.

P.S.: this ancient answer is quite outdated. It contains my understanding of MVC more then 18 month ago. I soon will get an update. You will find this answer to be much more up-to-date.

model management in MVC

If you have just one server and just one process, you could cache your model (static variables or similiar) and you will just have one model in memory that mirrors the database. But this would scale bad (or better won't scale at all). So depending on how much latency you could tolerate, you could have several servers and processes which have their own caches, updating from database in regular intervals. This could of course mean data corruption. Another way will be that if one server changes an entity it informs all other servers via sockets to invalidate that entity in their caches. A midway would be that all servers cache in memory, but every time an object is requested, only the timestamp (or version) is pulled from the database to decide wether the cache is up to date.

Does a Model in MVC Need To Be a Class Or is That Just a Common Pattern?

In general "Model" refers to your Business Object Model (BOM). If you subscribe to Domain Driven Design (DDD) then your Models in a Model View Controller (MVC) architecture will be representative of your BOMs as classes or interfaces. Those BOMs may also be your classes in an Object Relational Map architecture. Since it is better for an interface to be a description of what something can do and a class as a description of what something is, you would tend to see your Models represented as classes rather than interfaces. In terms of what "logic" is allowed inside of those model classes it is really up to you and your team. For example, while it is typical to put data validation in Models you may want to abstract those rules to a separate data validation class that your model uses. There is typically not a black and white rule about where business logic goes but it is generally considered best practice for each class to have a single responsibility based on the Single Responsibility Principle as part of the SOLID model. From my experience when I have called "Model" classes things that were not the Business Object Models, like a "RepositoryModel", it can be confusing about where the code representation of the data model was. Instead I recommend using the word "Model" to be reserved for things which end users are familiar with and avoid the word "Model" for things they cannot.

In MVC, should the Model or the Controller be processing and parsing data?

The internet is full of discussion about what is true MVC. This answer is from the perspective of the CodeIgniter (CI) implementation of MVC. Read the official line here.

As it says on the linked page "CodeIgniter has a fairly loose approach to MVC...". Which, IMO, means there aren't any truly wrong ways to do things. That said, the MVC pattern is a pretty good way to achieve Separation of Concerns (SoC) (defined here). CI will allow you to follow the MVC pattern while, as the linked documentation page says, "...enabling you to work in a way that makes the most sense to you."

Models need not be restricted to database functions. (Though if that makes sense to you, then by all means, do it.) Many CI developers put all kinds of "business logic" in Models. Often this logic could just as easily reside in a custom library. I've often had cases where that "business logic" is so trivial it makes perfect sense to have it in a Controller. So, strictly speaking - there really isn't any strictly speaking.

In your case, and as one of the comments suggests, it might make sense to put the CSV functionality into a library (a.k.a. service). That makes it easy to use in multiple places - either Controller or Model.

Ultimately you want to keep any given block of code relevant to, and only to, the task at hand. Hopefully this can be done in a way that keeps the code DRY (Don't Repeat Yourself). It's up to you to determine how to achieve the desired end result.

You get to decide what the terms Model, View, and Controller mean.

Have I implemented a n-tier application with MVC correctly?

I'm not sure if I can call this n-tier MVC when the models are lists/VO's returned from business objects in the logic tier

Those are perfectly good models. I also consider the ActionForms in Struts to be models. ActionForms are what Struts uses to represent/model HTML forms.

in MVC the view is supposed to observe the model and update on change, but this isn't possible in a web-application

Yep, and that is a matter of debate as to whether you can have true MVC with web-applications.

Should one always have a business layer?

It depends on the type of application. Some applications are database-driven, and are essentially a UI for the database. In that case, there's very little business logic required.

Data Tier:

The stored procedures aren't really part of the data tier code. You should be creating data access objects (DAOs) which are called by the business objects. The DAOs call the stored procedures. Further, the DAO interfaces should give no hint to the business objects as to where the data is stored, whether that be a database or file system or from some web service.



Related Topics



Leave a reply



Submit