How should a model be structured in MVC? [closed]












530















I am just getting a grasp on the MVC framework and I often wonder how much code should go in the model. I tend to have a data access class that has methods like this:



public function CheckUsername($connection, $username)
{
try
{
$data = array();
$data['Username'] = $username;

//// SQL
$sql = "SELECT Username FROM" . $this->usersTableName . " WHERE Username = :Username";

//// Execute statement
return $this->ExecuteObject($connection, $sql, $data);
}
catch(Exception $e)
{
throw $e;
}
}


My models tend to be an entity class that is mapped to the database table.



Should the model object have all the database mapped properties as well as the code above or is it OK to separate that code out that actually does the database work?



Will I end up having four layers?










share|improve this question















closed as primarily opinion-based by TylerH, Gert Arnold, sideshowbarker, Machavity, eyllanesc Nov 22 '18 at 0:32


Many good questions generate some degree of opinion based on expert experience, but answers to this question will tend to be almost entirely based on opinions, rather than facts, references, or specific expertise. If this question can be reworded to fit the rules in the help center, please edit the question.














  • 127





    Why are you catching exceptions just to throw them again?

    – Bailey Parker
    Jun 8 '12 at 5:46






  • 9





    @Elias Van Ootegem: you missed the point. it's pointless to catch them in this case.

    – Karoly Horvath
    Jul 18 '12 at 20:46






  • 4





    @Elias Van Ootegem: huh? if it works with rethrow, it means that an upper layer catches the exception. But if there is one, then it would have catched it without that pointless rethrow... (if you still don't get it, please mock up a small test code)

    – Karoly Horvath
    Jul 18 '12 at 21:11








  • 3





    @Elias Van Ootegem: I have no idea what you're talking about, not handling an exception on a specific layer doesn't mean it will halt the app. please construct (or more precisely: fail to construct) a code example where that rethrow is necessary. let's stop this offtopic conversation, please

    – Karoly Horvath
    Jul 18 '12 at 22:01






  • 6





    @drrcknlsn: that's a valid argument, but in that case at least catch the exception you expect to be thrown, the generic Exception doesn't have much documentation value. Personally if I went down on that road I would choose PHPDoc's @exception, or some similar mechanism, so it shows up in the generated documentation.

    – Karoly Horvath
    Aug 2 '12 at 22:27
















530















I am just getting a grasp on the MVC framework and I often wonder how much code should go in the model. I tend to have a data access class that has methods like this:



public function CheckUsername($connection, $username)
{
try
{
$data = array();
$data['Username'] = $username;

//// SQL
$sql = "SELECT Username FROM" . $this->usersTableName . " WHERE Username = :Username";

//// Execute statement
return $this->ExecuteObject($connection, $sql, $data);
}
catch(Exception $e)
{
throw $e;
}
}


My models tend to be an entity class that is mapped to the database table.



Should the model object have all the database mapped properties as well as the code above or is it OK to separate that code out that actually does the database work?



Will I end up having four layers?










share|improve this question















closed as primarily opinion-based by TylerH, Gert Arnold, sideshowbarker, Machavity, eyllanesc Nov 22 '18 at 0:32


Many good questions generate some degree of opinion based on expert experience, but answers to this question will tend to be almost entirely based on opinions, rather than facts, references, or specific expertise. If this question can be reworded to fit the rules in the help center, please edit the question.














  • 127





    Why are you catching exceptions just to throw them again?

    – Bailey Parker
    Jun 8 '12 at 5:46






  • 9





    @Elias Van Ootegem: you missed the point. it's pointless to catch them in this case.

    – Karoly Horvath
    Jul 18 '12 at 20:46






  • 4





    @Elias Van Ootegem: huh? if it works with rethrow, it means that an upper layer catches the exception. But if there is one, then it would have catched it without that pointless rethrow... (if you still don't get it, please mock up a small test code)

    – Karoly Horvath
    Jul 18 '12 at 21:11








  • 3





    @Elias Van Ootegem: I have no idea what you're talking about, not handling an exception on a specific layer doesn't mean it will halt the app. please construct (or more precisely: fail to construct) a code example where that rethrow is necessary. let's stop this offtopic conversation, please

    – Karoly Horvath
    Jul 18 '12 at 22:01






  • 6





    @drrcknlsn: that's a valid argument, but in that case at least catch the exception you expect to be thrown, the generic Exception doesn't have much documentation value. Personally if I went down on that road I would choose PHPDoc's @exception, or some similar mechanism, so it shows up in the generated documentation.

    – Karoly Horvath
    Aug 2 '12 at 22:27














530












530








530


598






I am just getting a grasp on the MVC framework and I often wonder how much code should go in the model. I tend to have a data access class that has methods like this:



public function CheckUsername($connection, $username)
{
try
{
$data = array();
$data['Username'] = $username;

//// SQL
$sql = "SELECT Username FROM" . $this->usersTableName . " WHERE Username = :Username";

//// Execute statement
return $this->ExecuteObject($connection, $sql, $data);
}
catch(Exception $e)
{
throw $e;
}
}


My models tend to be an entity class that is mapped to the database table.



Should the model object have all the database mapped properties as well as the code above or is it OK to separate that code out that actually does the database work?



Will I end up having four layers?










share|improve this question
















I am just getting a grasp on the MVC framework and I often wonder how much code should go in the model. I tend to have a data access class that has methods like this:



public function CheckUsername($connection, $username)
{
try
{
$data = array();
$data['Username'] = $username;

//// SQL
$sql = "SELECT Username FROM" . $this->usersTableName . " WHERE Username = :Username";

//// Execute statement
return $this->ExecuteObject($connection, $sql, $data);
}
catch(Exception $e)
{
throw $e;
}
}


My models tend to be an entity class that is mapped to the database table.



Should the model object have all the database mapped properties as well as the code above or is it OK to separate that code out that actually does the database work?



Will I end up having four layers?







php oop model-view-controller architecture model






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Aug 23 '14 at 18:08









i alarmed alien

8,14532035




8,14532035










asked May 3 '11 at 0:28









DietpixelDietpixel

4,72592331




4,72592331




closed as primarily opinion-based by TylerH, Gert Arnold, sideshowbarker, Machavity, eyllanesc Nov 22 '18 at 0:32


Many good questions generate some degree of opinion based on expert experience, but answers to this question will tend to be almost entirely based on opinions, rather than facts, references, or specific expertise. If this question can be reworded to fit the rules in the help center, please edit the question.









closed as primarily opinion-based by TylerH, Gert Arnold, sideshowbarker, Machavity, eyllanesc Nov 22 '18 at 0:32


Many good questions generate some degree of opinion based on expert experience, but answers to this question will tend to be almost entirely based on opinions, rather than facts, references, or specific expertise. If this question can be reworded to fit the rules in the help center, please edit the question.










  • 127





    Why are you catching exceptions just to throw them again?

    – Bailey Parker
    Jun 8 '12 at 5:46






  • 9





    @Elias Van Ootegem: you missed the point. it's pointless to catch them in this case.

    – Karoly Horvath
    Jul 18 '12 at 20:46






  • 4





    @Elias Van Ootegem: huh? if it works with rethrow, it means that an upper layer catches the exception. But if there is one, then it would have catched it without that pointless rethrow... (if you still don't get it, please mock up a small test code)

    – Karoly Horvath
    Jul 18 '12 at 21:11








  • 3





    @Elias Van Ootegem: I have no idea what you're talking about, not handling an exception on a specific layer doesn't mean it will halt the app. please construct (or more precisely: fail to construct) a code example where that rethrow is necessary. let's stop this offtopic conversation, please

    – Karoly Horvath
    Jul 18 '12 at 22:01






  • 6





    @drrcknlsn: that's a valid argument, but in that case at least catch the exception you expect to be thrown, the generic Exception doesn't have much documentation value. Personally if I went down on that road I would choose PHPDoc's @exception, or some similar mechanism, so it shows up in the generated documentation.

    – Karoly Horvath
    Aug 2 '12 at 22:27














  • 127





    Why are you catching exceptions just to throw them again?

    – Bailey Parker
    Jun 8 '12 at 5:46






  • 9





    @Elias Van Ootegem: you missed the point. it's pointless to catch them in this case.

    – Karoly Horvath
    Jul 18 '12 at 20:46






  • 4





    @Elias Van Ootegem: huh? if it works with rethrow, it means that an upper layer catches the exception. But if there is one, then it would have catched it without that pointless rethrow... (if you still don't get it, please mock up a small test code)

    – Karoly Horvath
    Jul 18 '12 at 21:11








  • 3





    @Elias Van Ootegem: I have no idea what you're talking about, not handling an exception on a specific layer doesn't mean it will halt the app. please construct (or more precisely: fail to construct) a code example where that rethrow is necessary. let's stop this offtopic conversation, please

    – Karoly Horvath
    Jul 18 '12 at 22:01






  • 6





    @drrcknlsn: that's a valid argument, but in that case at least catch the exception you expect to be thrown, the generic Exception doesn't have much documentation value. Personally if I went down on that road I would choose PHPDoc's @exception, or some similar mechanism, so it shows up in the generated documentation.

    – Karoly Horvath
    Aug 2 '12 at 22:27








127




127





Why are you catching exceptions just to throw them again?

– Bailey Parker
Jun 8 '12 at 5:46





Why are you catching exceptions just to throw them again?

– Bailey Parker
Jun 8 '12 at 5:46




9




9





@Elias Van Ootegem: you missed the point. it's pointless to catch them in this case.

– Karoly Horvath
Jul 18 '12 at 20:46





@Elias Van Ootegem: you missed the point. it's pointless to catch them in this case.

– Karoly Horvath
Jul 18 '12 at 20:46




4




4





@Elias Van Ootegem: huh? if it works with rethrow, it means that an upper layer catches the exception. But if there is one, then it would have catched it without that pointless rethrow... (if you still don't get it, please mock up a small test code)

– Karoly Horvath
Jul 18 '12 at 21:11







@Elias Van Ootegem: huh? if it works with rethrow, it means that an upper layer catches the exception. But if there is one, then it would have catched it without that pointless rethrow... (if you still don't get it, please mock up a small test code)

– Karoly Horvath
Jul 18 '12 at 21:11






3




3





@Elias Van Ootegem: I have no idea what you're talking about, not handling an exception on a specific layer doesn't mean it will halt the app. please construct (or more precisely: fail to construct) a code example where that rethrow is necessary. let's stop this offtopic conversation, please

– Karoly Horvath
Jul 18 '12 at 22:01





@Elias Van Ootegem: I have no idea what you're talking about, not handling an exception on a specific layer doesn't mean it will halt the app. please construct (or more precisely: fail to construct) a code example where that rethrow is necessary. let's stop this offtopic conversation, please

– Karoly Horvath
Jul 18 '12 at 22:01




6




6





@drrcknlsn: that's a valid argument, but in that case at least catch the exception you expect to be thrown, the generic Exception doesn't have much documentation value. Personally if I went down on that road I would choose PHPDoc's @exception, or some similar mechanism, so it shows up in the generated documentation.

– Karoly Horvath
Aug 2 '12 at 22:27





@drrcknlsn: that's a valid argument, but in that case at least catch the exception you expect to be thrown, the generic Exception doesn't have much documentation value. Personally if I went down on that road I would choose PHPDoc's @exception, or some similar mechanism, so it shows up in the generated documentation.

– Karoly Horvath
Aug 2 '12 at 22:27












5 Answers
5






active

oldest

votes


















855





+1700










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(EntityIdentity $identity, int $status)
{
$identity->setStatus($status);
$identity->setLastUsed(time());
$mapper = $this->mapperFactory->create(MapperIdentity::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 ApplicationControllerDocument and ApplicationViewDocument. 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).








share|improve this answer





















  • 4





    @Rinzler , you will notice, that nowhere in that link, anything said about Model (except in one comment). It's only "an object-oriented interface to database tables". If you try to mold this in a Model-like thing, you end up violating SRP and LSP.

    – tereško
    Jun 12 '12 at 10:11






  • 7





    @hafichuk only situations, when it is reasonable to employ ActiveRecord pattern is for prototyping. When you start to write the code that is mean for production, it becomes an anti-pattern, because it mixes storage and business logic. And since Model Layer is completely unaware of the other MVC parts. This does not change depending on variation on original pattern. Even when using MVVM. There are no "multiple models" and they are not mapped to anything. Model is a layer.

    – tereško
    Jun 15 '12 at 14:47








  • 3





    Short Version - Models are Data Structures.

    – Eddie B
    Nov 24 '12 at 10:21








  • 9





    Well seeing that he invented MVC the article may have some merit.

    – Eddie B
    Nov 24 '12 at 10:39






  • 3





    ... or even just a set of functions. MVC does not require to be implemented in an OOP style, although it is mostly implemented that way. The most important thing is to separate layers and establishing the right data and control flow

    – hek2mgl
    Aug 4 '13 at 11:36





















33














Everything that is business logic belongs in a model, whether it is a database query, calculations, a REST call, etc.



You can have the data access in the model itself, the MVC pattern doesn't restrict you from doing that. You can sugar coat it with services, mappers and what not, but the actual definition of a model is a layer that handles business logic, nothing more, nothing less. It can be a class, a function, or a complete module with a gazillion objects if that's what you want.



It's always easier to have a separate object that actually executes the database queries instead of having them being executed in the model directly: this will especially come in handy when unit testing (because of the easiness of injecting a mock database dependency in your model):



class Database {
protected $_conn;

public function __construct($connection) {
$this->_conn = $connection;
}

public function ExecuteObject($sql, $data) {
// stuff
}
}

abstract class Model {
protected $_db;

public function __construct(Database $db) {
$this->_db = $db;
}
}

class User extends Model {
public function CheckUsername($username) {
// ...
$sql = "SELECT Username FROM" . $this->usersTableName . " WHERE ...";
return $this->_db->ExecuteObject($sql, $data);
}
}

$db = new Database($conn);
$model = new User($db);
$model->CheckUsername('foo');


Also, in PHP, you rarely need to catch/rethrow exceptions because the backtrace is preserved, especially in a case like your example. Just let the exception be thrown and catch it in the controller instead.






share|improve this answer


























  • My structure is very similar, I think I just separate it out a bit more. The reason why I was passing around the connection was because I needed to have chunks run in transactions. I wanted to add a user and then add the user to a role, but role back if one failed. The only way I could sort that out was to pass the connection.

    – Dietpixel
    May 3 '11 at 0:50








  • 8





    -1: it also happens to be completely wrong. Model is not an abstraction for a table.

    – tereško
    Nov 16 '14 at 22:38






  • 1





    The User class basically extends the model, but itsn't an object. User should be an object and has properties like: id, name ... You're deploying User class is a helper.

    – TomSawyer
    Dec 2 '16 at 17:43








  • 1





    I think you understand MVC but don't understand what's OOP. In this scenario, like i said, User stands for an object, and it should have properties of an User, not methods like CheckUsername, what should you do if you want to create new User object? new User($db)

    – TomSawyer
    Dec 2 '16 at 18:10











  • @TomSawyer OOP doesn't mean objects are required to have properties. What you're describing is a design pattern, one which is irrelevant to the question or an answer to that question. OOP is a language model, not a design pattern.

    – netcoder
    Dec 2 '16 at 18:17



















19














In Web-"MVC" you can do whatever you please.



The original concept (1) described the model as the business logic. It should represent the application state and enforce some data consistency. That approach is often described as "fat model".



Most PHP frameworks follow a more shallow approach, where the model is just a database interface. But at the very least these models should still validate the incoming data and relations.



Either way, you're not very far off if you separate the SQL stuff or database calls into another layer. This way you only need to concern yourself with the real data/behaviour, not with the actual storage API. (It's however unreasonable to overdo it. You'll e.g. never be able to replace a database backend with a filestorage if that wasn't designed ahead.)






share|improve this answer





















  • 8





    link is invalid (404)

    – Kyslik
    Aug 6 '13 at 9:54








  • 1





    This works from WebArchive: web.archive.org/web/20101229204648/https://stackoverflow.com/…

    – Tudor
    Sep 19 '18 at 13:24



















5














More oftenly most of the applications will have data,display and processing part and we just put all those in the letters M,V and C.



Model(M)-->Has the attributes that holds state of application and it dont know any thing about V and C.



View(V)-->Has displaying format for the application and and only knows about how-to-digest model on it and does not bother about C.



Controller(C)---->Has processing part of application and acts as wiring between M and V and it depends on both M,V unlike M and V.



Altogether there is separation of concern between each.
In future any change or enhancements can be added very easily.






share|improve this answer

































    0














    In my case I have a database class that handle all the direct database interaction such as querying, fetching, and such. So if I had to change my database from MySQL to PostgreSQL there won't be any problem. So adding that extra layer can be useful.



    Each table can have its own class and have its specific methods, but to actually get the data, it lets the database class handle it:



    File Database.php



    class Database {
    private static $connection;
    private static $current_query;
    ...

    public static function query($sql) {
    if (!self::$connection){
    self::open_connection();
    }
    self::$current_query = $sql;
    $result = mysql_query($sql,self::$connection);

    if (!$result){
    self::close_connection();
    // throw custom error
    // The query failed for some reason. here is query :: self::$current_query
    $error = new Error(2,"There is an Error in the query.n<b>Query:</b>n{$sql}n");
    $error->handleError();
    }
    return $result;
    }
    ....

    public static function find_by_sql($sql){
    if (!is_string($sql))
    return false;

    $result_set = self::query($sql);
    $obj_arr = array();
    while ($row = self::fetch_array($result_set))
    {
    $obj_arr = self::instantiate($row);
    }
    return $obj_arr;
    }
    }


    Table object classL



    class DomainPeer extends Database {

    public static function getDomainInfoList() {
    $sql = 'SELECT ';
    $sql .='d.`id`,';
    $sql .='d.`name`,';
    $sql .='d.`shortName`,';
    $sql .='d.`created_at`,';
    $sql .='d.`updated_at`,';
    $sql .='count(q.id) as queries ';
    $sql .='FROM `domains` d ';
    $sql .='LEFT JOIN queries q on q.domainId = d.id ';
    $sql .='GROUP BY d.id';
    return self::find_by_sql($sql);
    }

    ....
    }


    I hope this example helps you create a good structure.






    share|improve this answer





















    • 12





      "So if I had to change my database from MySQL to PostgreSQL there won't be any problem." Uhhhmmm with above code you would have a huge problem changing anything imo.

      – PeeHaa
      Oct 4 '12 at 19:54











    • I see my answer makes less and less sense after edit, and as time goes by. But it should stay here

      – Ibu
      Dec 19 '12 at 17:48






    • 2





      Database in the example is not a class. It is just a wrapper for functions. Also, how can you have "table object class" without an object?

      – tereško
      Dec 19 '12 at 19:03






    • 1





      @tereško I have read many of your posts and they're great. But, I cannot find any complete framework anywhere to study. Do you know of one that "does it right"? Or at least one that does it like you and some others here on SO say to do? Thanks.

      – johnny
      Sep 1 '14 at 20:12













    • I may be way late, but i'd like to point out that PDO almost solves the issue of having to create a DB 'layer' in order to facilitate future changes.

      – Matthew Goulart
      Mar 3 '16 at 15:44


















    5 Answers
    5






    active

    oldest

    votes








    5 Answers
    5






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    855





    +1700










    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(EntityIdentity $identity, int $status)
    {
    $identity->setStatus($status);
    $identity->setLastUsed(time());
    $mapper = $this->mapperFactory->create(MapperIdentity::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 ApplicationControllerDocument and ApplicationViewDocument. 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).








    share|improve this answer





















    • 4





      @Rinzler , you will notice, that nowhere in that link, anything said about Model (except in one comment). It's only "an object-oriented interface to database tables". If you try to mold this in a Model-like thing, you end up violating SRP and LSP.

      – tereško
      Jun 12 '12 at 10:11






    • 7





      @hafichuk only situations, when it is reasonable to employ ActiveRecord pattern is for prototyping. When you start to write the code that is mean for production, it becomes an anti-pattern, because it mixes storage and business logic. And since Model Layer is completely unaware of the other MVC parts. This does not change depending on variation on original pattern. Even when using MVVM. There are no "multiple models" and they are not mapped to anything. Model is a layer.

      – tereško
      Jun 15 '12 at 14:47








    • 3





      Short Version - Models are Data Structures.

      – Eddie B
      Nov 24 '12 at 10:21








    • 9





      Well seeing that he invented MVC the article may have some merit.

      – Eddie B
      Nov 24 '12 at 10:39






    • 3





      ... or even just a set of functions. MVC does not require to be implemented in an OOP style, although it is mostly implemented that way. The most important thing is to separate layers and establishing the right data and control flow

      – hek2mgl
      Aug 4 '13 at 11:36


















    855





    +1700










    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(EntityIdentity $identity, int $status)
    {
    $identity->setStatus($status);
    $identity->setLastUsed(time());
    $mapper = $this->mapperFactory->create(MapperIdentity::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 ApplicationControllerDocument and ApplicationViewDocument. 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).








    share|improve this answer





















    • 4





      @Rinzler , you will notice, that nowhere in that link, anything said about Model (except in one comment). It's only "an object-oriented interface to database tables". If you try to mold this in a Model-like thing, you end up violating SRP and LSP.

      – tereško
      Jun 12 '12 at 10:11






    • 7





      @hafichuk only situations, when it is reasonable to employ ActiveRecord pattern is for prototyping. When you start to write the code that is mean for production, it becomes an anti-pattern, because it mixes storage and business logic. And since Model Layer is completely unaware of the other MVC parts. This does not change depending on variation on original pattern. Even when using MVVM. There are no "multiple models" and they are not mapped to anything. Model is a layer.

      – tereško
      Jun 15 '12 at 14:47








    • 3





      Short Version - Models are Data Structures.

      – Eddie B
      Nov 24 '12 at 10:21








    • 9





      Well seeing that he invented MVC the article may have some merit.

      – Eddie B
      Nov 24 '12 at 10:39






    • 3





      ... or even just a set of functions. MVC does not require to be implemented in an OOP style, although it is mostly implemented that way. The most important thing is to separate layers and establishing the right data and control flow

      – hek2mgl
      Aug 4 '13 at 11:36
















    855





    +1700







    855





    +1700



    855




    +1700






    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(EntityIdentity $identity, int $status)
    {
    $identity->setStatus($status);
    $identity->setLastUsed(time());
    $mapper = $this->mapperFactory->create(MapperIdentity::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 ApplicationControllerDocument and ApplicationViewDocument. 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).








    share|improve this answer
















    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(EntityIdentity $identity, int $status)
    {
    $identity->setStatus($status);
    $identity->setLastUsed(time());
    $mapper = $this->mapperFactory->create(MapperIdentity::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 ApplicationControllerDocument and ApplicationViewDocument. 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).









    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Oct 18 '17 at 7:54

























    answered May 3 '11 at 0:56









    tereškotereško

    52.6k2078136




    52.6k2078136








    • 4





      @Rinzler , you will notice, that nowhere in that link, anything said about Model (except in one comment). It's only "an object-oriented interface to database tables". If you try to mold this in a Model-like thing, you end up violating SRP and LSP.

      – tereško
      Jun 12 '12 at 10:11






    • 7





      @hafichuk only situations, when it is reasonable to employ ActiveRecord pattern is for prototyping. When you start to write the code that is mean for production, it becomes an anti-pattern, because it mixes storage and business logic. And since Model Layer is completely unaware of the other MVC parts. This does not change depending on variation on original pattern. Even when using MVVM. There are no "multiple models" and they are not mapped to anything. Model is a layer.

      – tereško
      Jun 15 '12 at 14:47








    • 3





      Short Version - Models are Data Structures.

      – Eddie B
      Nov 24 '12 at 10:21








    • 9





      Well seeing that he invented MVC the article may have some merit.

      – Eddie B
      Nov 24 '12 at 10:39






    • 3





      ... or even just a set of functions. MVC does not require to be implemented in an OOP style, although it is mostly implemented that way. The most important thing is to separate layers and establishing the right data and control flow

      – hek2mgl
      Aug 4 '13 at 11:36
















    • 4





      @Rinzler , you will notice, that nowhere in that link, anything said about Model (except in one comment). It's only "an object-oriented interface to database tables". If you try to mold this in a Model-like thing, you end up violating SRP and LSP.

      – tereško
      Jun 12 '12 at 10:11






    • 7





      @hafichuk only situations, when it is reasonable to employ ActiveRecord pattern is for prototyping. When you start to write the code that is mean for production, it becomes an anti-pattern, because it mixes storage and business logic. And since Model Layer is completely unaware of the other MVC parts. This does not change depending on variation on original pattern. Even when using MVVM. There are no "multiple models" and they are not mapped to anything. Model is a layer.

      – tereško
      Jun 15 '12 at 14:47








    • 3





      Short Version - Models are Data Structures.

      – Eddie B
      Nov 24 '12 at 10:21








    • 9





      Well seeing that he invented MVC the article may have some merit.

      – Eddie B
      Nov 24 '12 at 10:39






    • 3





      ... or even just a set of functions. MVC does not require to be implemented in an OOP style, although it is mostly implemented that way. The most important thing is to separate layers and establishing the right data and control flow

      – hek2mgl
      Aug 4 '13 at 11:36










    4




    4





    @Rinzler , you will notice, that nowhere in that link, anything said about Model (except in one comment). It's only "an object-oriented interface to database tables". If you try to mold this in a Model-like thing, you end up violating SRP and LSP.

    – tereško
    Jun 12 '12 at 10:11





    @Rinzler , you will notice, that nowhere in that link, anything said about Model (except in one comment). It's only "an object-oriented interface to database tables". If you try to mold this in a Model-like thing, you end up violating SRP and LSP.

    – tereško
    Jun 12 '12 at 10:11




    7




    7





    @hafichuk only situations, when it is reasonable to employ ActiveRecord pattern is for prototyping. When you start to write the code that is mean for production, it becomes an anti-pattern, because it mixes storage and business logic. And since Model Layer is completely unaware of the other MVC parts. This does not change depending on variation on original pattern. Even when using MVVM. There are no "multiple models" and they are not mapped to anything. Model is a layer.

    – tereško
    Jun 15 '12 at 14:47







    @hafichuk only situations, when it is reasonable to employ ActiveRecord pattern is for prototyping. When you start to write the code that is mean for production, it becomes an anti-pattern, because it mixes storage and business logic. And since Model Layer is completely unaware of the other MVC parts. This does not change depending on variation on original pattern. Even when using MVVM. There are no "multiple models" and they are not mapped to anything. Model is a layer.

    – tereško
    Jun 15 '12 at 14:47






    3




    3





    Short Version - Models are Data Structures.

    – Eddie B
    Nov 24 '12 at 10:21







    Short Version - Models are Data Structures.

    – Eddie B
    Nov 24 '12 at 10:21






    9




    9





    Well seeing that he invented MVC the article may have some merit.

    – Eddie B
    Nov 24 '12 at 10:39





    Well seeing that he invented MVC the article may have some merit.

    – Eddie B
    Nov 24 '12 at 10:39




    3




    3





    ... or even just a set of functions. MVC does not require to be implemented in an OOP style, although it is mostly implemented that way. The most important thing is to separate layers and establishing the right data and control flow

    – hek2mgl
    Aug 4 '13 at 11:36







    ... or even just a set of functions. MVC does not require to be implemented in an OOP style, although it is mostly implemented that way. The most important thing is to separate layers and establishing the right data and control flow

    – hek2mgl
    Aug 4 '13 at 11:36















    33














    Everything that is business logic belongs in a model, whether it is a database query, calculations, a REST call, etc.



    You can have the data access in the model itself, the MVC pattern doesn't restrict you from doing that. You can sugar coat it with services, mappers and what not, but the actual definition of a model is a layer that handles business logic, nothing more, nothing less. It can be a class, a function, or a complete module with a gazillion objects if that's what you want.



    It's always easier to have a separate object that actually executes the database queries instead of having them being executed in the model directly: this will especially come in handy when unit testing (because of the easiness of injecting a mock database dependency in your model):



    class Database {
    protected $_conn;

    public function __construct($connection) {
    $this->_conn = $connection;
    }

    public function ExecuteObject($sql, $data) {
    // stuff
    }
    }

    abstract class Model {
    protected $_db;

    public function __construct(Database $db) {
    $this->_db = $db;
    }
    }

    class User extends Model {
    public function CheckUsername($username) {
    // ...
    $sql = "SELECT Username FROM" . $this->usersTableName . " WHERE ...";
    return $this->_db->ExecuteObject($sql, $data);
    }
    }

    $db = new Database($conn);
    $model = new User($db);
    $model->CheckUsername('foo');


    Also, in PHP, you rarely need to catch/rethrow exceptions because the backtrace is preserved, especially in a case like your example. Just let the exception be thrown and catch it in the controller instead.






    share|improve this answer


























    • My structure is very similar, I think I just separate it out a bit more. The reason why I was passing around the connection was because I needed to have chunks run in transactions. I wanted to add a user and then add the user to a role, but role back if one failed. The only way I could sort that out was to pass the connection.

      – Dietpixel
      May 3 '11 at 0:50








    • 8





      -1: it also happens to be completely wrong. Model is not an abstraction for a table.

      – tereško
      Nov 16 '14 at 22:38






    • 1





      The User class basically extends the model, but itsn't an object. User should be an object and has properties like: id, name ... You're deploying User class is a helper.

      – TomSawyer
      Dec 2 '16 at 17:43








    • 1





      I think you understand MVC but don't understand what's OOP. In this scenario, like i said, User stands for an object, and it should have properties of an User, not methods like CheckUsername, what should you do if you want to create new User object? new User($db)

      – TomSawyer
      Dec 2 '16 at 18:10











    • @TomSawyer OOP doesn't mean objects are required to have properties. What you're describing is a design pattern, one which is irrelevant to the question or an answer to that question. OOP is a language model, not a design pattern.

      – netcoder
      Dec 2 '16 at 18:17
















    33














    Everything that is business logic belongs in a model, whether it is a database query, calculations, a REST call, etc.



    You can have the data access in the model itself, the MVC pattern doesn't restrict you from doing that. You can sugar coat it with services, mappers and what not, but the actual definition of a model is a layer that handles business logic, nothing more, nothing less. It can be a class, a function, or a complete module with a gazillion objects if that's what you want.



    It's always easier to have a separate object that actually executes the database queries instead of having them being executed in the model directly: this will especially come in handy when unit testing (because of the easiness of injecting a mock database dependency in your model):



    class Database {
    protected $_conn;

    public function __construct($connection) {
    $this->_conn = $connection;
    }

    public function ExecuteObject($sql, $data) {
    // stuff
    }
    }

    abstract class Model {
    protected $_db;

    public function __construct(Database $db) {
    $this->_db = $db;
    }
    }

    class User extends Model {
    public function CheckUsername($username) {
    // ...
    $sql = "SELECT Username FROM" . $this->usersTableName . " WHERE ...";
    return $this->_db->ExecuteObject($sql, $data);
    }
    }

    $db = new Database($conn);
    $model = new User($db);
    $model->CheckUsername('foo');


    Also, in PHP, you rarely need to catch/rethrow exceptions because the backtrace is preserved, especially in a case like your example. Just let the exception be thrown and catch it in the controller instead.






    share|improve this answer


























    • My structure is very similar, I think I just separate it out a bit more. The reason why I was passing around the connection was because I needed to have chunks run in transactions. I wanted to add a user and then add the user to a role, but role back if one failed. The only way I could sort that out was to pass the connection.

      – Dietpixel
      May 3 '11 at 0:50








    • 8





      -1: it also happens to be completely wrong. Model is not an abstraction for a table.

      – tereško
      Nov 16 '14 at 22:38






    • 1





      The User class basically extends the model, but itsn't an object. User should be an object and has properties like: id, name ... You're deploying User class is a helper.

      – TomSawyer
      Dec 2 '16 at 17:43








    • 1





      I think you understand MVC but don't understand what's OOP. In this scenario, like i said, User stands for an object, and it should have properties of an User, not methods like CheckUsername, what should you do if you want to create new User object? new User($db)

      – TomSawyer
      Dec 2 '16 at 18:10











    • @TomSawyer OOP doesn't mean objects are required to have properties. What you're describing is a design pattern, one which is irrelevant to the question or an answer to that question. OOP is a language model, not a design pattern.

      – netcoder
      Dec 2 '16 at 18:17














    33












    33








    33







    Everything that is business logic belongs in a model, whether it is a database query, calculations, a REST call, etc.



    You can have the data access in the model itself, the MVC pattern doesn't restrict you from doing that. You can sugar coat it with services, mappers and what not, but the actual definition of a model is a layer that handles business logic, nothing more, nothing less. It can be a class, a function, or a complete module with a gazillion objects if that's what you want.



    It's always easier to have a separate object that actually executes the database queries instead of having them being executed in the model directly: this will especially come in handy when unit testing (because of the easiness of injecting a mock database dependency in your model):



    class Database {
    protected $_conn;

    public function __construct($connection) {
    $this->_conn = $connection;
    }

    public function ExecuteObject($sql, $data) {
    // stuff
    }
    }

    abstract class Model {
    protected $_db;

    public function __construct(Database $db) {
    $this->_db = $db;
    }
    }

    class User extends Model {
    public function CheckUsername($username) {
    // ...
    $sql = "SELECT Username FROM" . $this->usersTableName . " WHERE ...";
    return $this->_db->ExecuteObject($sql, $data);
    }
    }

    $db = new Database($conn);
    $model = new User($db);
    $model->CheckUsername('foo');


    Also, in PHP, you rarely need to catch/rethrow exceptions because the backtrace is preserved, especially in a case like your example. Just let the exception be thrown and catch it in the controller instead.






    share|improve this answer















    Everything that is business logic belongs in a model, whether it is a database query, calculations, a REST call, etc.



    You can have the data access in the model itself, the MVC pattern doesn't restrict you from doing that. You can sugar coat it with services, mappers and what not, but the actual definition of a model is a layer that handles business logic, nothing more, nothing less. It can be a class, a function, or a complete module with a gazillion objects if that's what you want.



    It's always easier to have a separate object that actually executes the database queries instead of having them being executed in the model directly: this will especially come in handy when unit testing (because of the easiness of injecting a mock database dependency in your model):



    class Database {
    protected $_conn;

    public function __construct($connection) {
    $this->_conn = $connection;
    }

    public function ExecuteObject($sql, $data) {
    // stuff
    }
    }

    abstract class Model {
    protected $_db;

    public function __construct(Database $db) {
    $this->_db = $db;
    }
    }

    class User extends Model {
    public function CheckUsername($username) {
    // ...
    $sql = "SELECT Username FROM" . $this->usersTableName . " WHERE ...";
    return $this->_db->ExecuteObject($sql, $data);
    }
    }

    $db = new Database($conn);
    $model = new User($db);
    $model->CheckUsername('foo');


    Also, in PHP, you rarely need to catch/rethrow exceptions because the backtrace is preserved, especially in a case like your example. Just let the exception be thrown and catch it in the controller instead.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Jun 27 '15 at 19:38

























    answered May 3 '11 at 0:42









    netcodernetcoder

    53.9k14104132




    53.9k14104132













    • My structure is very similar, I think I just separate it out a bit more. The reason why I was passing around the connection was because I needed to have chunks run in transactions. I wanted to add a user and then add the user to a role, but role back if one failed. The only way I could sort that out was to pass the connection.

      – Dietpixel
      May 3 '11 at 0:50








    • 8





      -1: it also happens to be completely wrong. Model is not an abstraction for a table.

      – tereško
      Nov 16 '14 at 22:38






    • 1





      The User class basically extends the model, but itsn't an object. User should be an object and has properties like: id, name ... You're deploying User class is a helper.

      – TomSawyer
      Dec 2 '16 at 17:43








    • 1





      I think you understand MVC but don't understand what's OOP. In this scenario, like i said, User stands for an object, and it should have properties of an User, not methods like CheckUsername, what should you do if you want to create new User object? new User($db)

      – TomSawyer
      Dec 2 '16 at 18:10











    • @TomSawyer OOP doesn't mean objects are required to have properties. What you're describing is a design pattern, one which is irrelevant to the question or an answer to that question. OOP is a language model, not a design pattern.

      – netcoder
      Dec 2 '16 at 18:17



















    • My structure is very similar, I think I just separate it out a bit more. The reason why I was passing around the connection was because I needed to have chunks run in transactions. I wanted to add a user and then add the user to a role, but role back if one failed. The only way I could sort that out was to pass the connection.

      – Dietpixel
      May 3 '11 at 0:50








    • 8





      -1: it also happens to be completely wrong. Model is not an abstraction for a table.

      – tereško
      Nov 16 '14 at 22:38






    • 1





      The User class basically extends the model, but itsn't an object. User should be an object and has properties like: id, name ... You're deploying User class is a helper.

      – TomSawyer
      Dec 2 '16 at 17:43








    • 1





      I think you understand MVC but don't understand what's OOP. In this scenario, like i said, User stands for an object, and it should have properties of an User, not methods like CheckUsername, what should you do if you want to create new User object? new User($db)

      – TomSawyer
      Dec 2 '16 at 18:10











    • @TomSawyer OOP doesn't mean objects are required to have properties. What you're describing is a design pattern, one which is irrelevant to the question or an answer to that question. OOP is a language model, not a design pattern.

      – netcoder
      Dec 2 '16 at 18:17

















    My structure is very similar, I think I just separate it out a bit more. The reason why I was passing around the connection was because I needed to have chunks run in transactions. I wanted to add a user and then add the user to a role, but role back if one failed. The only way I could sort that out was to pass the connection.

    – Dietpixel
    May 3 '11 at 0:50







    My structure is very similar, I think I just separate it out a bit more. The reason why I was passing around the connection was because I needed to have chunks run in transactions. I wanted to add a user and then add the user to a role, but role back if one failed. The only way I could sort that out was to pass the connection.

    – Dietpixel
    May 3 '11 at 0:50






    8




    8





    -1: it also happens to be completely wrong. Model is not an abstraction for a table.

    – tereško
    Nov 16 '14 at 22:38





    -1: it also happens to be completely wrong. Model is not an abstraction for a table.

    – tereško
    Nov 16 '14 at 22:38




    1




    1





    The User class basically extends the model, but itsn't an object. User should be an object and has properties like: id, name ... You're deploying User class is a helper.

    – TomSawyer
    Dec 2 '16 at 17:43







    The User class basically extends the model, but itsn't an object. User should be an object and has properties like: id, name ... You're deploying User class is a helper.

    – TomSawyer
    Dec 2 '16 at 17:43






    1




    1





    I think you understand MVC but don't understand what's OOP. In this scenario, like i said, User stands for an object, and it should have properties of an User, not methods like CheckUsername, what should you do if you want to create new User object? new User($db)

    – TomSawyer
    Dec 2 '16 at 18:10





    I think you understand MVC but don't understand what's OOP. In this scenario, like i said, User stands for an object, and it should have properties of an User, not methods like CheckUsername, what should you do if you want to create new User object? new User($db)

    – TomSawyer
    Dec 2 '16 at 18:10













    @TomSawyer OOP doesn't mean objects are required to have properties. What you're describing is a design pattern, one which is irrelevant to the question or an answer to that question. OOP is a language model, not a design pattern.

    – netcoder
    Dec 2 '16 at 18:17





    @TomSawyer OOP doesn't mean objects are required to have properties. What you're describing is a design pattern, one which is irrelevant to the question or an answer to that question. OOP is a language model, not a design pattern.

    – netcoder
    Dec 2 '16 at 18:17











    19














    In Web-"MVC" you can do whatever you please.



    The original concept (1) described the model as the business logic. It should represent the application state and enforce some data consistency. That approach is often described as "fat model".



    Most PHP frameworks follow a more shallow approach, where the model is just a database interface. But at the very least these models should still validate the incoming data and relations.



    Either way, you're not very far off if you separate the SQL stuff or database calls into another layer. This way you only need to concern yourself with the real data/behaviour, not with the actual storage API. (It's however unreasonable to overdo it. You'll e.g. never be able to replace a database backend with a filestorage if that wasn't designed ahead.)






    share|improve this answer





















    • 8





      link is invalid (404)

      – Kyslik
      Aug 6 '13 at 9:54








    • 1





      This works from WebArchive: web.archive.org/web/20101229204648/https://stackoverflow.com/…

      – Tudor
      Sep 19 '18 at 13:24
















    19














    In Web-"MVC" you can do whatever you please.



    The original concept (1) described the model as the business logic. It should represent the application state and enforce some data consistency. That approach is often described as "fat model".



    Most PHP frameworks follow a more shallow approach, where the model is just a database interface. But at the very least these models should still validate the incoming data and relations.



    Either way, you're not very far off if you separate the SQL stuff or database calls into another layer. This way you only need to concern yourself with the real data/behaviour, not with the actual storage API. (It's however unreasonable to overdo it. You'll e.g. never be able to replace a database backend with a filestorage if that wasn't designed ahead.)






    share|improve this answer





















    • 8





      link is invalid (404)

      – Kyslik
      Aug 6 '13 at 9:54








    • 1





      This works from WebArchive: web.archive.org/web/20101229204648/https://stackoverflow.com/…

      – Tudor
      Sep 19 '18 at 13:24














    19












    19








    19







    In Web-"MVC" you can do whatever you please.



    The original concept (1) described the model as the business logic. It should represent the application state and enforce some data consistency. That approach is often described as "fat model".



    Most PHP frameworks follow a more shallow approach, where the model is just a database interface. But at the very least these models should still validate the incoming data and relations.



    Either way, you're not very far off if you separate the SQL stuff or database calls into another layer. This way you only need to concern yourself with the real data/behaviour, not with the actual storage API. (It's however unreasonable to overdo it. You'll e.g. never be able to replace a database backend with a filestorage if that wasn't designed ahead.)






    share|improve this answer















    In Web-"MVC" you can do whatever you please.



    The original concept (1) described the model as the business logic. It should represent the application state and enforce some data consistency. That approach is often described as "fat model".



    Most PHP frameworks follow a more shallow approach, where the model is just a database interface. But at the very least these models should still validate the incoming data and relations.



    Either way, you're not very far off if you separate the SQL stuff or database calls into another layer. This way you only need to concern yourself with the real data/behaviour, not with the actual storage API. (It's however unreasonable to overdo it. You'll e.g. never be able to replace a database backend with a filestorage if that wasn't designed ahead.)







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited May 23 '17 at 12:34









    Community

    11




    11










    answered May 3 '11 at 0:41









    mariomario

    126k17184256




    126k17184256








    • 8





      link is invalid (404)

      – Kyslik
      Aug 6 '13 at 9:54








    • 1





      This works from WebArchive: web.archive.org/web/20101229204648/https://stackoverflow.com/…

      – Tudor
      Sep 19 '18 at 13:24














    • 8





      link is invalid (404)

      – Kyslik
      Aug 6 '13 at 9:54








    • 1





      This works from WebArchive: web.archive.org/web/20101229204648/https://stackoverflow.com/…

      – Tudor
      Sep 19 '18 at 13:24








    8




    8





    link is invalid (404)

    – Kyslik
    Aug 6 '13 at 9:54







    link is invalid (404)

    – Kyslik
    Aug 6 '13 at 9:54






    1




    1





    This works from WebArchive: web.archive.org/web/20101229204648/https://stackoverflow.com/…

    – Tudor
    Sep 19 '18 at 13:24





    This works from WebArchive: web.archive.org/web/20101229204648/https://stackoverflow.com/…

    – Tudor
    Sep 19 '18 at 13:24











    5














    More oftenly most of the applications will have data,display and processing part and we just put all those in the letters M,V and C.



    Model(M)-->Has the attributes that holds state of application and it dont know any thing about V and C.



    View(V)-->Has displaying format for the application and and only knows about how-to-digest model on it and does not bother about C.



    Controller(C)---->Has processing part of application and acts as wiring between M and V and it depends on both M,V unlike M and V.



    Altogether there is separation of concern between each.
    In future any change or enhancements can be added very easily.






    share|improve this answer






























      5














      More oftenly most of the applications will have data,display and processing part and we just put all those in the letters M,V and C.



      Model(M)-->Has the attributes that holds state of application and it dont know any thing about V and C.



      View(V)-->Has displaying format for the application and and only knows about how-to-digest model on it and does not bother about C.



      Controller(C)---->Has processing part of application and acts as wiring between M and V and it depends on both M,V unlike M and V.



      Altogether there is separation of concern between each.
      In future any change or enhancements can be added very easily.






      share|improve this answer




























        5












        5








        5







        More oftenly most of the applications will have data,display and processing part and we just put all those in the letters M,V and C.



        Model(M)-->Has the attributes that holds state of application and it dont know any thing about V and C.



        View(V)-->Has displaying format for the application and and only knows about how-to-digest model on it and does not bother about C.



        Controller(C)---->Has processing part of application and acts as wiring between M and V and it depends on both M,V unlike M and V.



        Altogether there is separation of concern between each.
        In future any change or enhancements can be added very easily.






        share|improve this answer















        More oftenly most of the applications will have data,display and processing part and we just put all those in the letters M,V and C.



        Model(M)-->Has the attributes that holds state of application and it dont know any thing about V and C.



        View(V)-->Has displaying format for the application and and only knows about how-to-digest model on it and does not bother about C.



        Controller(C)---->Has processing part of application and acts as wiring between M and V and it depends on both M,V unlike M and V.



        Altogether there is separation of concern between each.
        In future any change or enhancements can be added very easily.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Aug 19 '14 at 14:44









        askmish

        5,5091638




        5,5091638










        answered Jun 30 '14 at 13:09









        feel good and programmingfeel good and programming

        6302924




        6302924























            0














            In my case I have a database class that handle all the direct database interaction such as querying, fetching, and such. So if I had to change my database from MySQL to PostgreSQL there won't be any problem. So adding that extra layer can be useful.



            Each table can have its own class and have its specific methods, but to actually get the data, it lets the database class handle it:



            File Database.php



            class Database {
            private static $connection;
            private static $current_query;
            ...

            public static function query($sql) {
            if (!self::$connection){
            self::open_connection();
            }
            self::$current_query = $sql;
            $result = mysql_query($sql,self::$connection);

            if (!$result){
            self::close_connection();
            // throw custom error
            // The query failed for some reason. here is query :: self::$current_query
            $error = new Error(2,"There is an Error in the query.n<b>Query:</b>n{$sql}n");
            $error->handleError();
            }
            return $result;
            }
            ....

            public static function find_by_sql($sql){
            if (!is_string($sql))
            return false;

            $result_set = self::query($sql);
            $obj_arr = array();
            while ($row = self::fetch_array($result_set))
            {
            $obj_arr = self::instantiate($row);
            }
            return $obj_arr;
            }
            }


            Table object classL



            class DomainPeer extends Database {

            public static function getDomainInfoList() {
            $sql = 'SELECT ';
            $sql .='d.`id`,';
            $sql .='d.`name`,';
            $sql .='d.`shortName`,';
            $sql .='d.`created_at`,';
            $sql .='d.`updated_at`,';
            $sql .='count(q.id) as queries ';
            $sql .='FROM `domains` d ';
            $sql .='LEFT JOIN queries q on q.domainId = d.id ';
            $sql .='GROUP BY d.id';
            return self::find_by_sql($sql);
            }

            ....
            }


            I hope this example helps you create a good structure.






            share|improve this answer





















            • 12





              "So if I had to change my database from MySQL to PostgreSQL there won't be any problem." Uhhhmmm with above code you would have a huge problem changing anything imo.

              – PeeHaa
              Oct 4 '12 at 19:54











            • I see my answer makes less and less sense after edit, and as time goes by. But it should stay here

              – Ibu
              Dec 19 '12 at 17:48






            • 2





              Database in the example is not a class. It is just a wrapper for functions. Also, how can you have "table object class" without an object?

              – tereško
              Dec 19 '12 at 19:03






            • 1





              @tereško I have read many of your posts and they're great. But, I cannot find any complete framework anywhere to study. Do you know of one that "does it right"? Or at least one that does it like you and some others here on SO say to do? Thanks.

              – johnny
              Sep 1 '14 at 20:12













            • I may be way late, but i'd like to point out that PDO almost solves the issue of having to create a DB 'layer' in order to facilitate future changes.

              – Matthew Goulart
              Mar 3 '16 at 15:44
















            0














            In my case I have a database class that handle all the direct database interaction such as querying, fetching, and such. So if I had to change my database from MySQL to PostgreSQL there won't be any problem. So adding that extra layer can be useful.



            Each table can have its own class and have its specific methods, but to actually get the data, it lets the database class handle it:



            File Database.php



            class Database {
            private static $connection;
            private static $current_query;
            ...

            public static function query($sql) {
            if (!self::$connection){
            self::open_connection();
            }
            self::$current_query = $sql;
            $result = mysql_query($sql,self::$connection);

            if (!$result){
            self::close_connection();
            // throw custom error
            // The query failed for some reason. here is query :: self::$current_query
            $error = new Error(2,"There is an Error in the query.n<b>Query:</b>n{$sql}n");
            $error->handleError();
            }
            return $result;
            }
            ....

            public static function find_by_sql($sql){
            if (!is_string($sql))
            return false;

            $result_set = self::query($sql);
            $obj_arr = array();
            while ($row = self::fetch_array($result_set))
            {
            $obj_arr = self::instantiate($row);
            }
            return $obj_arr;
            }
            }


            Table object classL



            class DomainPeer extends Database {

            public static function getDomainInfoList() {
            $sql = 'SELECT ';
            $sql .='d.`id`,';
            $sql .='d.`name`,';
            $sql .='d.`shortName`,';
            $sql .='d.`created_at`,';
            $sql .='d.`updated_at`,';
            $sql .='count(q.id) as queries ';
            $sql .='FROM `domains` d ';
            $sql .='LEFT JOIN queries q on q.domainId = d.id ';
            $sql .='GROUP BY d.id';
            return self::find_by_sql($sql);
            }

            ....
            }


            I hope this example helps you create a good structure.






            share|improve this answer





















            • 12





              "So if I had to change my database from MySQL to PostgreSQL there won't be any problem." Uhhhmmm with above code you would have a huge problem changing anything imo.

              – PeeHaa
              Oct 4 '12 at 19:54











            • I see my answer makes less and less sense after edit, and as time goes by. But it should stay here

              – Ibu
              Dec 19 '12 at 17:48






            • 2





              Database in the example is not a class. It is just a wrapper for functions. Also, how can you have "table object class" without an object?

              – tereško
              Dec 19 '12 at 19:03






            • 1





              @tereško I have read many of your posts and they're great. But, I cannot find any complete framework anywhere to study. Do you know of one that "does it right"? Or at least one that does it like you and some others here on SO say to do? Thanks.

              – johnny
              Sep 1 '14 at 20:12













            • I may be way late, but i'd like to point out that PDO almost solves the issue of having to create a DB 'layer' in order to facilitate future changes.

              – Matthew Goulart
              Mar 3 '16 at 15:44














            0












            0








            0







            In my case I have a database class that handle all the direct database interaction such as querying, fetching, and such. So if I had to change my database from MySQL to PostgreSQL there won't be any problem. So adding that extra layer can be useful.



            Each table can have its own class and have its specific methods, but to actually get the data, it lets the database class handle it:



            File Database.php



            class Database {
            private static $connection;
            private static $current_query;
            ...

            public static function query($sql) {
            if (!self::$connection){
            self::open_connection();
            }
            self::$current_query = $sql;
            $result = mysql_query($sql,self::$connection);

            if (!$result){
            self::close_connection();
            // throw custom error
            // The query failed for some reason. here is query :: self::$current_query
            $error = new Error(2,"There is an Error in the query.n<b>Query:</b>n{$sql}n");
            $error->handleError();
            }
            return $result;
            }
            ....

            public static function find_by_sql($sql){
            if (!is_string($sql))
            return false;

            $result_set = self::query($sql);
            $obj_arr = array();
            while ($row = self::fetch_array($result_set))
            {
            $obj_arr = self::instantiate($row);
            }
            return $obj_arr;
            }
            }


            Table object classL



            class DomainPeer extends Database {

            public static function getDomainInfoList() {
            $sql = 'SELECT ';
            $sql .='d.`id`,';
            $sql .='d.`name`,';
            $sql .='d.`shortName`,';
            $sql .='d.`created_at`,';
            $sql .='d.`updated_at`,';
            $sql .='count(q.id) as queries ';
            $sql .='FROM `domains` d ';
            $sql .='LEFT JOIN queries q on q.domainId = d.id ';
            $sql .='GROUP BY d.id';
            return self::find_by_sql($sql);
            }

            ....
            }


            I hope this example helps you create a good structure.






            share|improve this answer















            In my case I have a database class that handle all the direct database interaction such as querying, fetching, and such. So if I had to change my database from MySQL to PostgreSQL there won't be any problem. So adding that extra layer can be useful.



            Each table can have its own class and have its specific methods, but to actually get the data, it lets the database class handle it:



            File Database.php



            class Database {
            private static $connection;
            private static $current_query;
            ...

            public static function query($sql) {
            if (!self::$connection){
            self::open_connection();
            }
            self::$current_query = $sql;
            $result = mysql_query($sql,self::$connection);

            if (!$result){
            self::close_connection();
            // throw custom error
            // The query failed for some reason. here is query :: self::$current_query
            $error = new Error(2,"There is an Error in the query.n<b>Query:</b>n{$sql}n");
            $error->handleError();
            }
            return $result;
            }
            ....

            public static function find_by_sql($sql){
            if (!is_string($sql))
            return false;

            $result_set = self::query($sql);
            $obj_arr = array();
            while ($row = self::fetch_array($result_set))
            {
            $obj_arr = self::instantiate($row);
            }
            return $obj_arr;
            }
            }


            Table object classL



            class DomainPeer extends Database {

            public static function getDomainInfoList() {
            $sql = 'SELECT ';
            $sql .='d.`id`,';
            $sql .='d.`name`,';
            $sql .='d.`shortName`,';
            $sql .='d.`created_at`,';
            $sql .='d.`updated_at`,';
            $sql .='count(q.id) as queries ';
            $sql .='FROM `domains` d ';
            $sql .='LEFT JOIN queries q on q.domainId = d.id ';
            $sql .='GROUP BY d.id';
            return self::find_by_sql($sql);
            }

            ....
            }


            I hope this example helps you create a good structure.







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Jun 14 '12 at 20:24









            Peter Mortensen

            13.8k1987113




            13.8k1987113










            answered May 3 '11 at 0:47









            IbuIbu

            33.1k106188




            33.1k106188








            • 12





              "So if I had to change my database from MySQL to PostgreSQL there won't be any problem." Uhhhmmm with above code you would have a huge problem changing anything imo.

              – PeeHaa
              Oct 4 '12 at 19:54











            • I see my answer makes less and less sense after edit, and as time goes by. But it should stay here

              – Ibu
              Dec 19 '12 at 17:48






            • 2





              Database in the example is not a class. It is just a wrapper for functions. Also, how can you have "table object class" without an object?

              – tereško
              Dec 19 '12 at 19:03






            • 1





              @tereško I have read many of your posts and they're great. But, I cannot find any complete framework anywhere to study. Do you know of one that "does it right"? Or at least one that does it like you and some others here on SO say to do? Thanks.

              – johnny
              Sep 1 '14 at 20:12













            • I may be way late, but i'd like to point out that PDO almost solves the issue of having to create a DB 'layer' in order to facilitate future changes.

              – Matthew Goulart
              Mar 3 '16 at 15:44














            • 12





              "So if I had to change my database from MySQL to PostgreSQL there won't be any problem." Uhhhmmm with above code you would have a huge problem changing anything imo.

              – PeeHaa
              Oct 4 '12 at 19:54











            • I see my answer makes less and less sense after edit, and as time goes by. But it should stay here

              – Ibu
              Dec 19 '12 at 17:48






            • 2





              Database in the example is not a class. It is just a wrapper for functions. Also, how can you have "table object class" without an object?

              – tereško
              Dec 19 '12 at 19:03






            • 1





              @tereško I have read many of your posts and they're great. But, I cannot find any complete framework anywhere to study. Do you know of one that "does it right"? Or at least one that does it like you and some others here on SO say to do? Thanks.

              – johnny
              Sep 1 '14 at 20:12













            • I may be way late, but i'd like to point out that PDO almost solves the issue of having to create a DB 'layer' in order to facilitate future changes.

              – Matthew Goulart
              Mar 3 '16 at 15:44








            12




            12





            "So if I had to change my database from MySQL to PostgreSQL there won't be any problem." Uhhhmmm with above code you would have a huge problem changing anything imo.

            – PeeHaa
            Oct 4 '12 at 19:54





            "So if I had to change my database from MySQL to PostgreSQL there won't be any problem." Uhhhmmm with above code you would have a huge problem changing anything imo.

            – PeeHaa
            Oct 4 '12 at 19:54













            I see my answer makes less and less sense after edit, and as time goes by. But it should stay here

            – Ibu
            Dec 19 '12 at 17:48





            I see my answer makes less and less sense after edit, and as time goes by. But it should stay here

            – Ibu
            Dec 19 '12 at 17:48




            2




            2





            Database in the example is not a class. It is just a wrapper for functions. Also, how can you have "table object class" without an object?

            – tereško
            Dec 19 '12 at 19:03





            Database in the example is not a class. It is just a wrapper for functions. Also, how can you have "table object class" without an object?

            – tereško
            Dec 19 '12 at 19:03




            1




            1





            @tereško I have read many of your posts and they're great. But, I cannot find any complete framework anywhere to study. Do you know of one that "does it right"? Or at least one that does it like you and some others here on SO say to do? Thanks.

            – johnny
            Sep 1 '14 at 20:12







            @tereško I have read many of your posts and they're great. But, I cannot find any complete framework anywhere to study. Do you know of one that "does it right"? Or at least one that does it like you and some others here on SO say to do? Thanks.

            – johnny
            Sep 1 '14 at 20:12















            I may be way late, but i'd like to point out that PDO almost solves the issue of having to create a DB 'layer' in order to facilitate future changes.

            – Matthew Goulart
            Mar 3 '16 at 15:44





            I may be way late, but i'd like to point out that PDO almost solves the issue of having to create a DB 'layer' in order to facilitate future changes.

            – Matthew Goulart
            Mar 3 '16 at 15:44



            Popular posts from this blog

            Biblatex bibliography style without URLs when DOI exists (in Overleaf with Zotero bibliography)

            ComboBox Display Member on multiple fields

            Is it possible to collect Nectar points via Trainline?