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
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 writing a fairly simple "fact database" in PHP (with Codeigniter .. but I am trying to get away from the framework internals for learning purposes), and trying to better my MVC/OOP practices.
Previously I would have done this: a fact model, a user model, a source model .. and inside each of those models I would place the CRUD logic for each. So it would look like this..
$this->fact_model->save($fact);
$this->user_model->deactivate($uid);
$this->source_model->get_id($sid);
But after reading more, it seems to make sense to have a separate persistence model (ie 'database_model'). But then it seems it would have to contain a full range of CRUD for each type of object, which seems wasteful to me. I guess I'm looking for how to go to this...
$this->db_m->save(Fact $fact);
$this->db_m->update(User $user);
// .. etc .. but also ..
$this->db_m->get_user_id($uid);
// .. and ..
$htis->db_m->get_all_facts();
Is this heading in the right direction? Do I just end up testing for type inside the database model and switching when I need to? Or do I extend the database model for each type of object?
$this->fact_db_m->save(Fact $fact);
$this->fact_db_m->get_all();
$this->source_db_m->get_id($sid);
Or something like this, which I guess is the closest to CIs AR implementation.
$this->db_m->save('facts', Fact $fact);
$this->db_m->get('user', array('id'=>$uid));
I guess this is a case of "active record vs repository". I understand that repository is easier to test, and the CRUD logic is separate from the object data, and that separation makes sense to me. But still.. it means you have to write a separate repository model for each entity. Is this right?
BTW - I know Codeigniter has a Database class and uses active record, and in a way I am just kind of re-creating it with some of those approaches. I'm just trying to understand things without relying on the framework internals. Any comments? Is it just a matter of choice?
Trying to do a little research on my own, thanks to your question, I came across this article: http://msdn.microsoft.com/en-us/magazine/dd569757.aspx , which explains the differences between different data access patterns.
I hope i understood the question correctly, but here goes.
My approach would be to use the separation of models, however the one twist i usually do. i will try to be clear.
Lets say my application is going to require 3 unique features. One for users, facts, sources, All of these models might need to use some common functions like SAVE or LOAD, or UPDATE, or DELETE. Instead of duplicating the common functions into each model, i would simply make a base class with all the common functions, a nd have the base class extend the CI_Model, then all my new model files ( users,facts,sources ) i would have extend my common class.
To better illustrate this, i will throw some basic code up
db_common_model Common Class (db_common_model.php)
class db_common_model extends CI_Model
{
public function __construct()
{
parent::__construct();
}
/**
* All Common Functions Here */
public function save()
{
// Do stuff
}
public function update()
{
// Do stuff
}
public function etc()
{
// Do stuff
}
}
users_model Class (db_common_model.php)
class users_model extends db_common_model
{
public function __construct()
{
parent::__construct();
}
/**
* user specific functions */
public function get_one()
{
// Do stuff
}
public function get_all()
{
// Do stuff
}
public function get_latest()
{
// Do stuff
}
public function etc()
{
// Do stuff
}
}
/**
* When using it in CI Controller
*/
$this->user_model->get_one(); // loads user specific function
$this->user_model->save(); // Calls all inherited methods from parent db_common_model
// Etc
This way of setting up your models allows you expand common features in the db_common_model, that are automatically available to all children classes.
This allows for clean organization, and allows you to not have to re-invent your common functions in every model.
Hope this helps.
I am developing a PHP framework, based on dependency injection. My data objects are injectable components, like any others.
I have an abstract DAO class, that each model should extend, that has:
basic crud methods
a reference to DI container, to instantiate objects
Things are, in short, like this
abstract class AbstractDao {
protected $fields;
protected $container; // This is the (injected) DI container, used to create instances.
protected $driver; // The injected database driver (i.e. PDO)
public function insert() {
// Insert implementation
// Insert current instance.
}
public function fetch($id) {
// Fetch implementation
// Fetches a row and sets fields on current instance
}
public function fetchAll() {
// Performs a select * query on database driver
// Iterates through results, and creates an instance
// for each result using $container, like this:
foreach ($results as $row) {
// I can't just make $instances[] = new Something(), or all the
// dependency injection thing would mess up.
$instances[] = $this->container->get('someDao');
}
return $instances;
}
// Other methods.
}
class Book extends AbstractDao {
protected $fields = array('field', 'definition', 'goes', 'here',);
// No special behaviour is needed, so we can keep default
// abstract implementation without overriding.
}
My question: every data object implementation (a book, a person, an user, etc.) must extend my AbstractDao object, therefore it will carry the weight of $driver and $container. Furthermore, since $fields property is defined at instance level, each data object would have its own, adding more overhead.
I fear that when handling big data sets this solution may result in a much expensive one, in terms of performance. I know objects would be just referenced, not cloned, but the overhead could be sadly high.
Couple of solutions i have in mind are
using static method implementations, that may reduce overhead in
subclasses
do not make my Daos extends the above mentioned AbstractDao, that should become a sort of DaoProvider. In this case, for each method, i should pass in the instance (thing that i don't really like)
None of those solutions i like that much... first i don't like using static things, as they conflicts a little with the entire idea of injection. Second, i dont like the idea of removing the dao subclassing pattern.
Any good idea would be really appreciated, thank you.
=== EDIT ===
One more thing that came to my mind. What i don't like in the 2nd approach ("dao provider") is that the provider has to perform operations on Dao fields (set values, set status, set isDirty, etc.), therefore fields have to be made accessible from outside. With the subclassing approach one can keep those protected or private.
=== /EDIT ===
I suggest you create a DAO Interface that declares behavior that a DAO implementation will have to define. Now in each concrete DAO implementation you can define your $driver, $container and $fieldsinstance fields.
After that you might want to create a AbstractModelclass that each concrete model should extend so that both your AbstractModeland concrete models be will 'data access agnostic'. The AbstractModel class will end up looking like this:
/*
* an AbstractModel
*/
abstract class AbstractModel {
protected $daoImpl;
function __construct(DAOInterface $daoImpl) {
$this->daoImpl = $daoImpl;
}
//some other functions that are common to concrete models
}
/*
* a concrete model
*/
class Model extends AbstractModel {
function findAll($params) {
//You can use the $daoImpl of AbstractModel to perform a CRUD operation
$this->daoImpl->findAll($params);
}
}
Now whenever you instantiate a concrete model you will inject a DAO implementation into the model class.
//inject a DAOInterface implementation into Model
$model = new Model(new DAOImpl());
$model->findAll($params);
The advantage here is that you can stub different DAO implementations during testing and perhaps this is where the DI container comes in handy. There's a similar code sample I have created when I was creating my DI container a few days ago.
BTW I don't see the need of putting a $containerobject inside your AbstractDAO why don't you pass in an object that is returned when you invoke a property of the container. That way you can use type hinting to force the object parameters to be of a certain type and encourage a fail-fast mechanism if a wrong object is passed in and you might also find it beneficial to create a Config class to handle your $driver details so that users are free to configure the driver they want to use for the db.
I'm new to OOP and thought I'd give Silex a try on a small app I'm attempting. I'm looking for some advice as to whether my design falls in line with good object oriented principles.
I have a User object which is basically just a bunch of properties, getters and setters. I then have a UserService object which will contain the logic for authenticating users, getting a user from the database, setting or updating user information, etc. I also have a UserServiceProvder class which is there to provide an instance of the UserService class to the app (which seems to be the best way to create a reusable chunk of code in Silex).
The question I have now is this: I am using the Doctrine DBAL that ships with Silex and when I instantiate the UserService class, I'm tempted to pass in a reference to the Doctrine object and then hard code calls to that object into methods of the UserService class.
For instance, to return a User from the database by id, I might create a method called getUserById($id) and then hardcode a Doctrine prepared statement into that method to select that user from the database and then return a User object.
Would it be better for me to create a whole other service that is just a further abstraction of the Doctrine DBAL and pass that to UserService when I instantiate it? That way, I could hard code the Doctrine prepared statements into that class, leaving my UserService class more encapsulated and reusable in case I decide to move away from Doctrine in the future.
I guess what I'm having a hard time with is realizing if there is a such a thing as overkill in OOP. It seems to me like the second method is much more reusable, but is it necessary or wise?
Moving the Database access to a separate class will bring you a couple of advantages. First of all, if you keep the database access apart from the rest of your logic you can replace the implementation of your database access more easy. If for a reason you want to drop the Doctrine DBAL you'll be happy that all the code is just referencing some interface to a repository instead of directly querying a database.
A second great advantage is that you can test your application logic in separation of your database access logic. If you inject a Repository for users inside your UserService you can Mock this in your tests and be sure they only fail if something is wrong with the actual application logic.
A small example of what you could do
The interface is convenient for reference throughout your codebase. No code references the implementation, only the interface. That way you can easily replace the implementation of the interface without touching all the places it is used:
interface IUserRepository
{
/**
* #return User
*/
public function getUserById($userId);
}
Of course you do need an implementation of said interface. This is what you inject into your UserService. This is what you one day might replace with another implementation of the interface:
class DoctrineDBALUserRepository implements IUserRepository
{
/**
* #return User
*/
public function getUserById($userId)
{
//implementation specific for Doctrine DBAL
}
}
The UserService only knows about the interface and can use it freely. To avoid having to inject the UserRepository in a lot of places in your code you could create a convenience build method. Notice the constructor that references the interface and the build method that injects an implementation of that interface:
class UserService
{
private $UserRepository;
public static build()
{
return new UserService(new DoctrineDBALUserRepository());
}
public function __construct(IUserRepository $UserRepository)
{
$this->UserRepository = $UserRepository;
}
public function getUserById($userId)
{
if ($User = $this->UserRepository->getUserById($userId) {
return $User;
}
throw new RuntimeException('O noes, we messed up');
}
With this in place you can write tests for the business logic (e.g. throw an exception if saving fails):
public function UserServiceTest extends PHPUnit_Framework_TestCase
{
public function testGetUserById_whenRetrievingFails_shouldThrowAnException()
{
$RepositoryStub = $this->getMock('IUserRepository');
$RepositoryStub->expects($this->any())->method('getUserById')->will($this->returnValue(false);
$UserService = new UserService($RepositoryStub);
$this->setExpectedException('RuntimeException');
$UserService->getUserById(1);
}
}
I can imagine you're not familiar with the last bit of code if you're not into unit-testing yet. I hope you are and if not urge you to read up on that as well :D I figured it was good for the completeness of the answer to include it no matter what.
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).