I am currently refactoring my software according to the Domain Driven Design. The problem is my understanding in the DataMapper part, specifically if some data have m:n relationship via a connection table (in case of SQL).
In this case I have a Domain Object:
class UserGroup extends DomainObject {
public $title;
public $description;
}
Now in my understanding, I would get an Object this way:
$userGroup = UserGroupMapper::instance()->findById(42);
$userGroup->title = 'Foo';
$userGroup->description = 'Bar';
UserGroupMapper::instance()->save($userGroup);
Am I on the right way, right now?
So here comes the problem:
I have 3 Tables:
core_users
id | etc
core_usergroups
id | title | description
core_usergroups_dependencys
usergroup_id | user_id
Basicly, the goal is, to find all Users which are in a specific group (or the inverted way)
The first thing, which comes to my mind:
$userGroup = UserGroupMapper::instance()->findById(42);
$userCollection = UserGroupMapper::instance()->findUsersByGroup($userGroup);
The DataMapper knows 2 tables and 2 Domain Objects, but this doesn't feel right, does it?
I don't understand the Service Part of DDD. According to it (in my understanding) I would write
UserGroupService::instance()->findUsers($userGroup);
But in this case the service need an own Data Mapper. Why shouldn't I call
UserGroupDependencyMapper::instance()->findUsersByGroup($userGroup);
UserGroupDependencyMapper::instance()->findGroupsByUser($user);
I generaly dont understand the mapping for dependency. A DataMapper should everytime return an object instance or a collection of object instances of the same type. But here, the mapper could return either a user or a group.
So, what is the way I should go for such a common problem? Bonus: What should my service do in this Example?
Update to Clarify
My question is not about working with the data in Domain Driven Design. It is about how can i fetch a list of data in m:n relation without fetching all. How should the Interface look like?
Basicly i need this according to the DataMapper pattern:
select * from core_users
join core_usergroups_dependency on core_users.id = core_usergroups_dependency.user_id
where core_usergroups_dependency.usergruop_id = 42
But where would the Call findUsersByUserGroup($myGroup) Call be located? UserMapper?
If i have that Mapper or how ever we will call this, which part knows about it? The Domain Repository?
The method is part of the repository interface definition (defined in the Domain). The implementation is part of the persistence and does the actual query. The Domain services will know only about the abstraction.
// in the Domain
interface IUsersRepository // I think we need a better name
{
public function getUsersByGroup($myGroup);
}
class MyDomainService
{
private $repo;
public function __construct(IUsersRepository $repo)
{
$this->repo = $repo;
}
public function doSomething($group)
{
$groups = $this->repo->getUsersByGroup($group);
// process $groups
}
}
// in DAL
class MyRepo implements IUsersRepository
{
// implementation
}
What matters here is that the Domain doesn't know about how you get those groups. Only the implementation knows that, so you can do whatever query you want there. The Domain is decoupled from the query itself.
Related
Over the past two years, I have become fairly familiar with PHP MVC style architecture, and have developed all my projects using MVC structures since then.
One question that has continued to bother me is how to group functions and database calls. I run into needing to perform the same actions across models. I would prefer not to duplicate these operations and sql query inside each of the models, but would rather group all user operations into a separate class.
For example, say I have a website with a forum, a blog, and a profile page, each with a separate model, view, and controller. However, say each of these pages needs to perform the same operation to the user table.
My Model class is constructed with a database object automatically. If I need to call a function from the user class, is it ok to pass the db object to that new User class? ... to do something like the following? I am not sure if passing objects like I am doing is fine, or is there a much better way of setting things up? Am I wasting resources, or is this a clumsy way of doing things?
Profile Model
class Profile_Model extends Model{
public function __construct() {
parent::__construct();
}
public function someFunction(){
$this->db->insert( "SOME SQL" );
$user = new User( $this->db ); // OK TO PASS DB OBJECT LIKE THIS?
$user->setSomething();
}
public function anotherFunction(){
//do something else that does not need a user object
}
}
User Class
class User{
public function __construct($db){
$this->db = $db; // OK TO SET DB OBJECT AS CLASS VARIABLE AGAIN?
}
public function setSomething(){
$this->db->insert( "SOME SQL" );
}
}
I'm trying to give you a really basic example of how I'd implement this architecture; Since it's really basic and I'm just a passionate developer and nothing more it could be I'm breaking some architectural rules, so please take it as a proof of concept.
LET'S START quickly with the Controller part where you get some request. Now you need someone that takes care of doing the dirty work.
As you can see here I'm trying to pass all the "dependencies" via constructor. These way you should be able to easily replace it with Mocks when testing .
Dependency injection is one of the concepts here.
AND NOW the Model (please remember Model is a layer and not a single class)
I've used "Services (or cases)" that should help you to compose a group of behaviors with all the actors (Classes) involved in this behavior.
Idendifying common behaviours that Services (or Cases) should do, is one of the concepts here.
Keep in mind that you should have a big picture in mind (or somewhere else depending on the project) before starting, in order to respect principle like KISS, SOLID, DRY, etc..
And please pay attention to method naming, often a bad or long name (like mine for example) is a sign that the class has more than a single Responsability or there's smell of bad design.
//App/Controllers/BlogController.php
namespace App\Controllers;
use App\Services\AuthServiceInterface;
use App\Services\BlogService;
use App\Http\Request;
use App\Http\Response;
class BlogController
{
protected $blogService;
public function __construct(AuthServiceInterface $authService, BlogService $blogService, Request $request)
{
$this->authService = $authService;
$this->blogService = $blogService;
$this->request = $request;
}
public function indexAction()
{
$data = array();
if ($this->authService->isAuthenticatedUser($this->request->getSomethingRelatedToTheUser())) {
$someData = $this->blogService->getSomeData();
$someOtherData = $this->request->iDontKnowWhatToDo();
$data = compact('someData', 'someOtherData');
}
return new Response($this->template, array('data' => $data), $status);
}
}
Now we need to create this Service that we've used in the controller. As you can see we're not talking directly with the "storage or data layer" but instead we're calling an abstraction layer that will handle that for us.
Using a Repository Pattern to retrieve data from a data layer, is one of the concepts here.
this way we can switch to whatever repository (inMemory, other storage, etc) to retrieve our data without changing the interface that the Controller is using, same method call but get data from another place.
Design by interfaces and not by concrete classes is one of the concepts here.
//App/Services/BlogService.php
<?php
namespace App\Services;
use App\Model\Repositories\BlogRepository;
class BlogService
{
protected $blogRepository;
public function __construct(BlogRepositoryInterface $blogRepository)
{
$this->blogRepository = $blogRepository;
}
public function getSomeData()
{
// do something complex with your data, here's just simple ex
return $this->blogRepository->findOne();
}
}
At this point we define the Repository that contains the persistance handler and knows about our Entity.
Again decoupling storage Persister and knowledge of an entity (what "can" be coupled with a mysql table for example), is one of the concepts here.
//App/Model/Repositories/BlogRepository.php
<?php
namespace App\Models\Respositories;
use App\Models\Entities\BlogEntity;
use App\Models\Persistance\DbStorageInterface;
class DbBlogRepository extends EntityRepository implements BlogRepositoryInterface
{
protected $entity;
public function __construct(DbStorageInterface $dbStorage)
{
$this->dbStorage = $dbStorage;
$this->entity = new BlogEntity;
}
public function findOne()
{
$data = $this->dbStorage->select('*')->from($this->getEntityName());
// This should be part of a mapping logic outside of here
$this->entity->setPropA($data['some']);
return $this->entity;
}
public function getEntityName()
{
return str_replace('Entity', '', get_class($this->entity));
}
}
At the end a simple entity with Setters and Getters:
//App/Model/Entities/BlogEntity.php
<?php
namespace App\Models\Entities;
class BlogEntity
{
protected $propA;
public function setPropA($dataA)
{
$this->propA = $dataA;
}
public function getPropA()
{
return $this->propA;
}
}
AND NOW? how can you inject this classes passed as dependencies? Well, this is a long answer.
Indicatively you could use Dependency Injection as we've done here have a init/boot file where you define things like:
// Laravel Style
App::bind('BlogRepositoryInterface', 'App\Model\Repositories\DbBlogRepository');
App::bind('DbStorageInterface', 'App\Model\Persistence\PDOStorage');
or some config/service.yml file like:
// Not the same but close to Symfony Style
BlogService:
class: "Namespace\\ConcreteBlogServiceClass"
Or you may feel the need of a Container Class from where you can ask the service you need to use in your controller.
function indexAction ()
{
$blogService = $this->container->getService('BlogService');
....
Dulcis in fundo here are some useful links (You can find tons of docs about this):
Services in Domain-Driven Design
Wicked Domain Model
Dependency Injection Container
Inversion of Control and Dependency Injection
Managing common Dependencies with parent Services
Whenever you need to use an object from another class there is only one safe way to do it: Dependency Injection.
Example:
Instead of having:
public function myMethod(){
$anotherObject = new Object();
}
You should inject the object with the constructor:
function __construct($dependency) {
$this->anotherObject = $dependency;
}
Once you have this structure you can use type hint and an Inversion of Control container to build thing automatically, e.g. define:
function __construct(DependencyInterface $dependency) {
$this->anotherObject = $dependency;
}
And then set your IoC container to inject the right dependency when you need to use this object
Do you use any frameworks? If not, try having a look at some popular ones, like Zend Framework or Symfony. You'll find they solve your problem and probably many more and are a great way to expand your knowledge on how to structure your project.
That aside you are close. Although adding the database directly to your User-model is probably not want you want to do. If you can get Martin Fowler's Patterns of Enterprise Application Architecture (PEAA) you will find a whole chapter outlining how to connect your models to your database. I prefer a Gateway-class (search for the Gateway-pattern or look at Zend_Db) when building something on my own, as it is relatively easy to implement and build.
Basically you have a class which performs queries and then will pass the data to your model. Just look at Data Source Architectural Patterns in Martin Fowler's pattern catalog (http://martinfowler.com/eaaCatalog/) to get a quick glance how to structure it and definitely read the book to get a real understanding when and how to use the patterns.
I hope this helps.
Part of the answer is to use dependency injection, but there is more to it than that. Cognitively speaking, grouping starts in the mind and is teased out better by brainstorming and modeling: Entity Relationship Diagrams and UML Diagrams.
Grouping of methods into classes and delegating tasks to injected objects makes sense, but there is usually room for one level of inheritance (at minimum). The use of abstract super classes and a Strategy Pattern for child classes that inherit base functionality from the abstract parent can help reduce code duplication (DRY).
All that being said, this is one reason why dependency injection containers are popular. They allow you to obtain the objects, and hence functionality, you need anywhere, without coupling object instantiation to usage.
Do a search for Pimple in Google. It may give you some ideas.
I'm working on a small test application in PHP that represents the backend of a game. Consider the following:
// GameSession Model
class GameSession {
private $player;
...
}
// Player Model
class Player {
private $inventory;
...
}
// Inventory Model
class Inventory {
private $extensions;
...
}
class InventoryExtension {
...
}
class GameController {
public function newGame() {
// Create a new game session
$gameSession = new GameSession();
$gameSessionMySQL = new GameSessionMySQL();
...
// Save updated game session to DB
$gameSessionMySQL->update($gameSession);
}
}
I'm using a Data Mapper Object 'GameSessionMySQL' (class def not shown) to update/save the game session to the database. That mapper knows how to insert, update, retrieve and delete game session data.
What it does not do is update the Player that is inside the GameSession. The Player has its own PlayerMySQL mapper.
In addition, the Player model has an Inventory model, which also has its own InventoryMySQL mapper. The Inventory model has a InventoryExtension. So I have a tree-like structure of objects I guess.
I'm stuck because I don't know where I should be instantiating the appropriate mapper objects and using them? Should I place them all inside the GameController, get()ing the required models from GameSession? That doesn't seem good to me as I might end up writing something like:
$playerMySQL->update($game->Session->getPlayer());
$inventoryMySQL->update($gameSession->getPlayer()->getInventory());
$inventoryExpansionMySQL->update($gameSession->getPlayer()->getInventory()->getExpansion(1);
...
...etc until I end up with a bunch of lines that look suspiciously like procedural.
On the other hand, maybe each model should instantiate its required mapper in its constructor, then call the relevant CRUD methods on it from within its own (probably similarly named) CRUD methods? I doubt this as I'm fairly confident data-access stuff should be kept apart from the domain objects.
I'm implementing all this into a traditional MVC paradigm; that is, where the Controller does nothing at all to the view except accept input from it :P
I'd very much appreciate a clear answer with good reasoning. I'm still learning OO techniques so please go easy on the more arcane terms :)
Thanks very much
Consider a Database interaction module written in PHP that contains classes for interacting with the database. I have not started coding the class so I won't be able to give code snippets.
There will be one class per database table as explained below.
User - A class for interacting with the user table. The class contains functions such as createUser, updateUser, etc.
Locations - A class for interacting with the locations table. The class contains functions such as searchLocation, createLocation, updateLocation, etc.
In addition, I am thinking of creating another class as follows: -
DatabaseHelper : A class that will have a member that represents the connection to the database. This class will contain the lower level methods for executing SQL queries such as executeQuery(query,parameters), executeUpdate(query,parameters) and so on.
At this point, I have two options to use the DatabaseHelper class in other classes : -
The User and Locations class will extend the DatabaseHelper class so that they can use the inherited executeQuery and executeUpdate methods in DatabaseHelper. In this case, DatabaseHelper will ensure that there is only one instance of the connection to the database at any given time.
The DatabaseHelper class will be injected in the User and Locations class through a Container class that will make User and Location instances. In this case, the Container will make sure that there is only one instance of DatabaseHelper in the application at any given time.
These are the two approaches that quickly come to my mind. I want to know which approach to go with. It is possible that both these approaches are not good enough, in which case, I want to know any other approach that I can go with to implement the database interaction module.
Edit:
Note that the Container class will contain a static member of type DatabaseHelper. It will contain a private static getDatabaseHelper() function that will return an existing DatabaseHelper instance or create a new DatabaseHelper instance if one does not exists in which case, it will populate the connection object in DatabaseHelper. The Container will also contain static methods called makeUser and makeLocation that will inject the DatabaseHelper into User and Locations respectively.
After reading a few answers, I realize that the initial question has almost been answered. But there is still a doubt that needs to be clarified before I can accept the final answer which is as follows.
What to do when I have multiple databases to connect to rather than a single database. How does the DatabaseHelper class incorporate this and how does the container inject appropriate database dependencies in the User and Location objects?
Lets answer your questions from top to bottom, and see what I can add to what you say.
There will be one class per database table as explained below.
User - A class for interacting with the user table. The class contains functions such as createUser, updateUser, etc.
Locations - A class for interacting with the locations table. The class contains functions >such as searchLocation, createLocation, updateLocation, etc.
Essentially you have to choices here. The method you described is called the active record pattern. The object itself knows how and where it is stored. For simple objects that interact with a database to create / read / update / delete, this pattern is really usefull.
If the database operations become more extensive and less simple to understand, it is often a good choice to go with a data mapper (eg. this implementation). This is a second object that handles all the database interactions, while the object itself (eg. User or Location) only handles operations that are specific to that object (eg. login or goToLocation). If you ever want to chance the storage of your objects, you will only have to create a new data mapper. Your object won't even know that something changed in the implementation. This enforces encapsulation and seperation of concerns.
There are other options, but these two are the most used ways to implement database interactions.
In addition, I am thinking of creating another class as follows: -
DatabaseHelper : A class that will have a static member that represents the connection to the database. This class will contain the lower level methods for executing SQL queries such as executeQuery(query,parameters), executeUpdate(query,parameters) and so on.
What you are describing here sounds like a singleton. Normally this isn't really a good design choice. Are you really, really certain that there will never be a second database? Probably not, so you should not confine yourself to an implementation that only allowes for one database connection. Instead of making a DatabaseHelper with static members, you can better create a Database object with some methods that allow you to connect, disconnect, execute a query, etc. This way you can reuse it if you ever need a second connection.
At this point, I have two options to use the DatabaseHelper class in other classes : -
The User and Locations class will extend the DatabaseHelper class so that they can use the inherited executeQuery and executeUpdate methods in DatabaseHelper. In this case, DatabaseHelper will ensure that there is only one instance of the connection to the database at any given time.
The DatabaseHelper class will be injected in the User and Locations class through a Container class that will make User and Location instances. In this case, the Container will make sure that there is only one instance of DatabaseHelper in the application at any given time.
These are the two approaches that quickly come to my mind. I want to know which approach to go with. It is possible that both these approaches are not good enough, in which case, I want to know any other approach that I can go with to implement the database interaction module.
The first option isn't really viable. If you read the description of inheritance, you will see that inheritance is normally used to create a subtype of an existing object. An User is not a subtype of a DatabaseHelper, nor is a location. A MysqlDatabase would be a subtype of a Database, or a Admin would be a subtype of an User. I would advise against this option, as it isn't following the best practices of object oriented programming.
The second option is better. If you choose to use the active record method, you should indeed inject the Database into the User and Location objects. This should of course be done by some third object that handles all these kind of interactions. You will probably want to take a look at dependency injection and inversion of control.
Otherwise, if you choose the data mapper method, you should inject the Database into the data mapper. This way it is still possible to use several databases, while seperating all your concerns.
For more information about the active record pattern and the data mapper pattern, I would advise you to get the Patterns of Enterprise Application Architecture book of Martin Fowler. It is full of these kind of patterns and much, much more!
I hope this helps (and sorry if there are some really bad English sentences in there, I'm not a native speaker!).
== EDIT ==
Using the active record pattern of data mapper pattern also helps in testing your code (like Aurel said). If you seperate all peaces of code to do just one thing, it will be easier to check that it is really doing this one thing. By using PHPUnit (or some other testing framework) to check that your code is properly working, you can be pretty sure that no bugs will be present in each of your code units. If you mix up the concerns (like when you choose option 1 of your choices), this will be a whole lot harder. Things get pretty mixed up, and you will soon get a big bunch of spaghetti code.
== EDIT2 ==
An example of the active record pattern (that is pretty lazy, and not really active):
class Controller {
public function main() {
$database = new Database('host', 'username', 'password');
$database->selectDatabase('database');
$user = new User($database);
$user->name = 'Test';
$user->insert();
$otherUser = new User($database, 5);
$otherUser->delete();
}
}
class Database {
protected $connection = null;
public function __construct($host, $username, $password) {
// Connect to database and set $this->connection
}
public function selectDatabase($database) {
// Set the database on the current connection
}
public function execute($query) {
// Execute the given query
}
}
class User {
protected $database = null;
protected $id = 0;
protected $name = '';
// Add database on creation and get the user with the given id
public function __construct($database, $id = 0) {
$this->database = $database;
if ($id != 0) {
$this->load($id);
}
}
// Get the user with the given ID
public function load($id) {
$sql = 'SELECT * FROM users WHERE id = ' . $this->database->escape($id);
$result = $this->database->execute($sql);
$this->id = $result['id'];
$this->name = $result['name'];
}
// Insert this user into the database
public function insert() {
$sql = 'INSERT INTO users (name) VALUES ("' . $this->database->escape($this->name) . '")';
$this->database->execute($sql);
}
// Update this user
public function update() {
$sql = 'UPDATE users SET name = "' . $this->database->escape($this->name) . '" WHERE id = ' . $this->database->escape($this->id);
$this->database->execute($sql);
}
// Delete this user
public function delete() {
$sql = 'DELETE FROM users WHERE id = ' . $this->database->escape($this->id);
$this->database->execute($sql);
}
// Other method of this user
public function login() {}
public function logout() {}
}
And an example of the data mapper pattern:
class Controller {
public function main() {
$database = new Database('host', 'username', 'password');
$database->selectDatabase('database');
$userMapper = new UserMapper($database);
$user = $userMapper->get(0);
$user->name = 'Test';
$userMapper->insert($user);
$otherUser = UserMapper(5);
$userMapper->delete($otherUser);
}
}
class Database {
protected $connection = null;
public function __construct($host, $username, $password) {
// Connect to database and set $this->connection
}
public function selectDatabase($database) {
// Set the database on the current connection
}
public function execute($query) {
// Execute the given query
}
}
class UserMapper {
protected $database = null;
// Add database on creation
public function __construct($database) {
$this->database = $database;
}
// Get the user with the given ID
public function get($id) {
$user = new User();
if ($id != 0) {
$sql = 'SELECT * FROM users WHERE id = ' . $this->database->escape($id);
$result = $this->database->execute($sql);
$user->id = $result['id'];
$user->name = $result['name'];
}
return $user;
}
// Insert the given user
public function insert($user) {
$sql = 'INSERT INTO users (name) VALUES ("' . $this->database->escape($user->name) . '")';
$this->database->execute($sql);
}
// Update the given user
public function update($user) {
$sql = 'UPDATE users SET name = "' . $this->database->escape($user->name) . '" WHERE id = ' . $this->database->escape($user->id);
$this->database->execute($sql);
}
// Delete the given user
public function delete($user) {
$sql = 'DELETE FROM users WHERE id = ' . $this->database->escape($user->id);
$this->database->execute($sql);
}
}
class User {
public $id = 0;
public $name = '';
// Other method of this user
public function login() {}
public function logout() {}
}
== EDIT 3: after edit by bot ==
Note that the Container class will contain a static member of type DatabaseHelper. It will contain a private static getDatabaseHelper() function that will return an existing DatabaseHelper instance or create a new DatabaseHelper instance if one does not exists in which case, it will populate the connection object in DatabaseHelper. The Container will also contain static methods called makeUser and makeLocation that will inject the DatabaseHelper into User and Locations respectively.
After reading a few answers, I realize that the initial question has almost been answered. But there is still a doubt that needs to be clarified before I can accept the final answer which is as follows.
What to do when I have multiple databases to connect to rather than a single database. How does the DatabaseHelper class incorporate this and how does the container inject appropriate database dependencies in the User and Location objects?
I think there is no need for any static property, nor does the Container need those makeUser of makeLocation methods. Lets assume that you have some entry point of your application, in which you create a class that will control all flow in your application. You seem to call it a container, I prefer to call it a controller. After all, it controls what happens in your application.
$controller = new Controller();
The controller will have to know what database it has to load, and if there is one single database or multiple ones. For example, one database contains the user data, anonther database contains the location data. If the active record User from above and a similar Location class are given, then the controller might look as follows:
class Controller {
protected $databases = array();
public function __construct() {
$this->database['first_db'] = new Database('first_host', 'first_username', 'first_password');
$this->database['first_db']->selectDatabase('first_database');
$this->database['second_db'] = new Database('second_host', 'second_username', 'second_password');
$this->database['second_db']->selectDatabase('second_database');
}
public function showUserAndLocation() {
$user = new User($this->databases['first_database'], 3);
$location = $user->getLocation($this->databases['second_database']);
echo 'User ' . $user->name . ' is at location ' . $location->name;
}
public function showLocation() {
$location = new Location($this->database['second_database'], 5);
echo 'The location ' . $location->name . ' is ' . $location->description;
}
}
Probably it would be good to move all the echo's to a View class or something. If you have multiple controller classes, it might pay off to have a different entrypoint that creates all databases and pushes them in the controller. You could for example call this a front controller or an entry controller.
Does this answer you open questions?
I would go with the dependancy injection, for the following reason: if at some point you want to write tests for your applications, it will allow you to replace the DatabaseHelper instance by a stub class, implementing the same interface but that do not really access a database. This will make it really easier to test your model functionalities.
By the way, for this to be really useful, your other classes (User, Locations) should depend on a DatabaseHelperInterface rather than directly on DatabaseHelper. (This is required to be able to switch implementations)
The question of Dependency Injection vs. Inheritance, at least in your specific example comes down to the following: "is a" or "has a".
Is class foo a type of class bar? Is it a bar? If so, maybe inheritance is the way to go.
Does class foo use an object of class bar? You're now in dependency injection territory.
In your case, your data access objects (in my code approach these are UserDAO and LocationDAO) are NOT types of database helpers. You would not use a UserDAO, for instance, to provide database access to another DAO class. Instead, you USE the features of a database helper in your DAO classes. Now, this doesn't mean that technically you could not achieve what you want to do by extending the database helper classes. But I think it would be a bad design, and would cause trouble down the road as your design evolves.
Another way to think about it is, is ALL of your data going to come from the database? What if, somewhere down the road, you want to pull some location data from, say, an RSS feed. You have your LocationDAO essentially defining your interface -- your "contract", so to speak -- as to how the rest of your application obtains location data. But if you had extended DatabaseHelper to implement your LocationDAO, you'd now be stuck. There'd be no way to have your LocationDAO use a different data source. If, however, DatabaseHelper and your RSSHelper both had a common interface, you could plug the RSSHelper right into your DAO and LocationDAO doesn't even have to change at all. *
If you had made LocationDAO a type of DatabaseHandler, changing the data source would require changing the type of LocationDAO. This means that not only does LocationDAO have to change, but all your code that uses LocationDAO has to change. If you had injected a datasource into your DAO classes from the start, then the LocationDAO interface would remain the same, regardless of the datasource.
(* Just a theoretical example. There'd be a lot more work to get a DatabaseHelper and RSSHelper to have a similar interface.)
What you are describing with your User and Location classes is called a Table Data Gateway:
An object that acts as a Gateway to a database table. One instance handles all the rows in the table.
In general, you want to favor Composition over Inheritance and programm towards an interface. While it may seem like more effort to assemble your objects, doing it will benefit maintenance and the ability to change the program in the long run (and we all know change is the only ever constant in a project).
The most obvious benefit of using Dependency Injection here is when you want to unit test the Gateways. You cannot easily mock away the connection to the database when using inheritance. This means you will always have to have a database connection for these tests. Using Depedency Injection allows you to mock that connection and just test the Gateways interact correctly with the Database Helper.
Even though the other answers here are very good, I wanted to throw in some other thoughts from my experiences using CakePHP (an MVC framework). Basically, I will just show you a leaf or two out of their API; mainly because - to me - it seems well defined and thought out (probably because I use it daily).
class DATABASE_CONFIG { // define various database connection details here (default/test/externalapi/etc) }
// Data access layer
class DataSource extends Object { // base for all places where data comes from (DB/CSV/SOAP/etc) }
// - Database
class DboSource extends DataSource { // base for all DB-specific datasources (find/count/query/etc) }
class Mysql extends DboSource { // MySQL DB-specific datasource }
// - Web service
class SoapSource extends DataSource { // web services, etc don't extend DboSource }
class AcmeApi extends SoapSource { // some non-standard SOAP API to wrestle with, etc }
// Business logic layer
class Model extends Object { // inject a datasource (definitions are in DATABASE_CONFIG) }
// - Your models
class User extends Model { // createUser, updateUser (can influence datasource injected above) }
class Location extends Model { // searchLocation, createLocation, updateLocation (same as above) }
// Flow control layer
class Controller extends Object { // web browser controls: render view, redirect, error404, etc }
// - Your controllers
class UsersController extends Controller { // inject the User model here, implement CRUD, this is where your URLs map to (eg. /users/view/123) }
class LocationsController extends Controller { // more CRUD, eg. $this->Location->search() }
// Presentation layer
class View extends Object { // load php template, insert data, wrap in design }
// - Non-HTML output
class XmlView extends View { // expose data as XML }
class JsonView extends View { // expose data as JSON }
Dependency Injection is preferred if you have different types of services, and one service want to use other.
Your classes User and Locations sounds more like DAO (DataAccessObject) layer, that interact with database, So for your given case you should be using In Inheritance. Inheritance can be done by extending class or implementing Interfaces
public interface DatabaseHelperInterface {
public executeQuery(....);
}
public class DatabaseHelperImpl implemnets DatabaseHelperInterface {
public executeQuery(....) {
//some code
}
public Class UserDaoInterface extends DatabaseHelperInterface {
public createUser(....);
}
public Class UserDaoImpl extends DatabaseHelperImpl {
public createUser(....) {
executeQuery(create user query);
}
In this way your database design and code will be separate.
Extended Question: Why should I use data mapper / Db_Table_Row, where as DbTable is capable of handling most of the basic tasks for data manipulation.
I am currently learning ZF v1.11
For Database manipulation, I created DbTable for each tables. For example, "users" table is represented by Application_Model_DbTable_Users with no additional codes in there.
When manipulating data, I can use:
<?php
$uTable = new Application_Model_DbTable_Users();
$newUid = $uTable->insert(array('name'=>'Old Name', 'email'=>''));
$user = $uTable->find($newUid)->current();
// Then I can use $user which is instance of Table_Row
$user->name = "New Name";
$user->email = "email#addr.com";
$user->save();
My Question is, when would I need to define a row class (assuming Table_Row is referred as DataMapper in ZF-Tutorials)
// By, adding this to the DbTable class
protected $_rowClass = 'Application_Model_User';
What are the benefits of having a Row class for each entity? Can anyone point me to best practices for this.
You do not need to define your own Table_Row. However, it maybe useful in many cases, particularly if you want to define some specific methods or properties for a given user row. They can also improve readability of your code.
For example in your Users table case, you could define a method called getFullName() in a custom user row as:
public function getFullName() {
return $this->firstName . ' ' . $this->lastName;
}
Then when you obtain user row object, to get the full name of the user, you just do:
$user = $uTable->find($newUid)->current();
$fullName = $user->getFullName();
Second example is when you have some parent table to the Users table, such as Addresses. In this case you could define a method called getAddress in a user row:
public function getAddress() {
return $this->findParentRow('Application_Model_DbTable_Addresses');
}
In this scenario, you would get an Address row object for a current user as follows:
$user = $uTable->find($newUid)->current();
$addressRow = $user->getAddress();
Another example, would be when you want to create custom delete or instert methods. Lets assume that you want to make sure you do not want to delete an admin user using delete() method. Then you could overload delete method from Zend_Db_Table_Row as follows:
public function delete() {
if ('admin' === $this->userRole) {
return 0;
}
return parent::delete();
}
This way, you would not be able to delete an admin user just by calling delete() on a user row object:
$user = $uTable->find($newUid)->current();
$rowsDeleted = $user->delete(); // would be 0 if $user is admin
These are just three basic examples showing usefulness of defining your own row classes. But of course they are not necessary. However, from my own experience they are quite handy.
In a nutshell: it's about isolation.
Zend_Db_Table is an implementation of the Table Data Gateway. It channels CRUD access to a specific table view through one class. It is usually used with a Table Module, e.g. a class that contains the business logic for the records handled by a gateway.
Zend_Db_Table_Row is an implementation of the Row Data Gateway Pattern. Here, the returned objects look exactly like a database record and they contain the business logic to work with that data, but they don't contain the logic to CRUD with the table they are from (that would be an ActiveRecord) but aggregate them.
Row Data Gateways are fine as long as you don't have too much object relational impedance mismatch. How an object is persisted in a relational database and how it should look like in an object world are often quite different things. When using a Domain Model, your business objects are usually structured in a different way than they are stored in the database. Thus, you cannot easily CRUD them from the database. This is where DataMapper comes into play.
A DataMapper takes the responsibility of mapping Domain objects onto Recordsets and vice versa. This makes your application more maintainable because it decouples your Domain objects from the Database structure. It keeps them separated and gives you more flexibility in how to model both layers (persistence and domain).
I know that in OOP you want every object (from a class) to be a "thing", eg. user, validator etc.
I know the basics about MVC, how they different parts interact with each other.
However, i wonder if the models in MVC should be designed according to the traditional OOP design, that is to say, should every model be a database/table/row (solution 2)?
Or is the intention more like to collect methods that are affecting the same table or a bunch of related tables (solution 1).
example for an Address book module in CodeIgniter, where i want be able to "CRUD" a Contact and add/remove it to/from a CRUD-able Contact Group.
Models solution 1: bunching all related methods together (not real object, rather a "package")
class Contacts extends Model {
function create_contact() {)
function read_contact() {}
function update_contact() {}
function delete_contact() {}
function add_contact_to_group() {}
function delete_contact_from_group() {}
function create_group() {}
function read_group() {}
function update_group() {}
function delete_group() {}
}
Models solution 2: the OOP way (one class per file)
class Contact extends Model {
private $name = '';
private $id = '';
function create_contact() {)
function read_contact() {}
function update_contact() {}
function delete_contact() {}
}
class ContactGroup extends Model {
private $name = '';
private $id = '';
function add_contact_to_group() {}
function delete_contact_from_group() {}
function create_group() {}
function read_group() {}
function update_group() {}
function delete_group() {}
}
i dont know how to think when i want to create the models. and the above examples are my real tasks for creating an Address book. Should i just bunch all functions together in one class. then the class contains different logic (contact and group), so it can not hold properties that are specific for either one of them.
the solution 2 works according to the OOP. but i dont know why i should make such a dividing. what would the benefits be to have a Contact object for example. Its surely not a User object, so why should a Contact "live" with its own state (properties and methods). Cause i tend to think like this: If something needs a state, then i create a OOP class so that the methods could affect the state or other things based on the state.
so should models be "stateful" too? if they require no state, why should i create it according to the OOP pattern. then i could just bunch it all together like the "package" solution.
you experienced guys with OOP/MVC, please shed a light on how one should think here in this very concrete task (and in general when creating a model)
EDIT: come to think about Controllers in MVC. they are created according to the "package" solution. It makes me wonder...
should every model be a
database/table/row (solution 2)?
No. Don't tie the definition of a model to its method of persistence. Although for simple applications you might extend a model from a database row object, you should keep them at least mentally separated.
Models are simply representations of entities in your domain, so by necessity they have state. Where you talk about a Contact model, you are really talking about a mapper or gateway, i.e. the object retrieving your model from the data store. It's unfortunate that so many ad hoc implementations of Active Record have muddied the waters on this.
Mappers can be implemented as a collection of static functions or as an object - however, the collection is less flexible if you want to extend or alter the behaviour for any reason (such as mocking for unit testing).
The model itself should simply be a collection of data, either stored as public properties or preferably with appropriate setters and getters (please don't just define a get/set function pair for every variable or you might as well just leave them public), along with other methods that operate on the data. It should have no concept of, or dependency on, the data store. It is the responsibility of the mapper to instantiate and initialize the model through its interface. Doing this will afford flexibility in how you can create and save your models. You can do it from the database, an XML file, in-code, from a serialized stream sent in over the network, whatever floats your boat really, all by substituting a different mapper, and the model remains completely unaware.
I don't know if there's a best way, but i'll share the way i do it...
I have a table gateway e.g. ContactTableGateway that contains all the sql for dealing with contacts. I like all the sql being in one place.
class ContactTableGateway extends Model {
function saveContact( Contact $contact )
function getContact ( $contact_id )
function createContact ( Contact $contact )
}
Then i have a contact class that basically just has getters and setters ( or public properties ). Objects of this class are used as arguments for the table gateway to save/create
class Contact extends Model {
function getName()
function getAddress()
function getEmail()
....
}
Heres a simplified example
if ( isset( $_POST ) ) {
// some validation here
$contact = new Contact;
$contact->name = $_POST['name'];
$contact->email = $_POST['email']
$contactTableGateway = new ContactTableGateway;
if ( $contactTableGateway->createContact( $contact ) ) {
echo "YAY";
}
}
I think your Solution #2 is superior as it's more molecular/modular, therefore, more understandable, flexible and extensible (in the OOP domain). It's also more resource friendly as it could allow you to only have to load the Contact class when no contact group functionality is required and vice-versa. That is the benefit of division.
If models need no state, that does not mean OOP/MVC does not apply. Table models may have no state in one's design but that is why we have static methods/members, i.e., Contact::read($id).