How to handle domain object creation "inside" collections - php

I'm new to MVCish structure, so go easy on me, please. I'm coding my own small MVCish "framework" for understanding purposes. Bit by bit, I intend to understand how all fits together the right way.
Relying heavily on How should a model be structured in MVC? by tereško and the fact that Domain Object != Domain Object Collection, I'm trying to figure out a way to handle Domain Object creation in bulks and their respective insertion in the Collection.
Oh his example, he passes a single ServiceFactory instance to both the controller and the view. This instance has a MapperFactory and a DomainObjectFactory injected on its constructor. There is no Collection Factory.
$serviceFactory = new ServiceFactory(
new DataMapperFactory($dbhProvider),
new DomainObjectFactory
);
/*
* Initialization of View
*/
$class = '\\Application\\View\\' . $request->getResourceName();
$view = new $class($serviceFactory);
$view->setDefaultTemplateLocation(__DIR__ . '/templates');
/*
* Initialization of Controller
*/
$class = '\\Application\\Controller\\' . $request->getResourceName();
$controller = new $class($serviceFactory, $view);
ServiceFactory.php would be something like
class ServiceFactory
{
private $domObjFactory;
private $mapperFactory;
private $services = array();
public function __construct(MapperFactory $mapperFactory, DomObjFactory $domObjFactory)
{
$this->mapperFactory = $mapperFactory;
$this->domObjFactory = $domObjFactory;
}
public function create($name)
{
if ( array_key_exists($name, $this->services) === false )
{
$serviceName = '\Vendor\\'.$name.'Service';
$this->services[$name] = new $serviceName($this->mapperFactory, $this->domObjFactory);
}
return $this->services[$name];
}
}
As an example, let's say I have a Domain Object called Contract and I want my view to show them all in a list. It should probably tell the "model" something like $ContractService->fetchAll(), which would instantiate a collection and tell the mapper to populate it with all the contracts. Right?
Considering the collection should contain Domain Objects and a method like $ContractMapper->fetchAll($collection) should probably create a bunch of them, how to handle their creation!?
Should I have a dedicated Collection Factory also?
Should I create single Domain Objects with a method inside the Collection Object?
Should I create single Domain Objects with a method inside the Collection Mapper?
If so, should I inject the Domain Object Factory inside one of them? (This would probable require a ServiceFactory with a bunch more Factory dependencies being injected, which is bad, right?)
I believe this could be easily achieved in a poorly coded way, but I'm trying to find the most elegant and clean solution.

Related

What does a domain object factory look like?

I have a DataMapperFactory and I think I am doing it correctly and it makes sense to have one but I have a DomainObjectFactory too but it just seems pointless. This is it:
namespace libs\factories;
use models as Models;
class DomainObjectFactory {
public function build($name) {
$className = 'Models\\' . $name;
return new className();
}
}
The only advantage I can see of this is that I am keeping the new operator from being present all over my code.
There has to be more to a DomainObjectFactory than this right?
Any help would be great thanks.
There are there major reasons to use factories:
1. Abstract the creation of object
This is one of the most useful structures in your architecture when it comes to unit testing. Having a factory be responsible for the creation of instance makes easier to introduce mocks when testing.
Also, as added benefit, your is not anymore tightly coupled to the name of the classes that you utilize.
2. Simplify instantiation
Here you have two aspect that you have to consider. First - the ability to instantiate different objects based on some condition - was already quite well described in helmbert's answer (+1 for him).
The other case is when you are instantiating domain objects, which more complex.
Something like this:
$employees = new EmployeeCollection;
$address = new Location;
$class = $type . `Company`;
$company = new $class( $employee, $address );
There is quite a lot to do before you can create an instance of HoldingCompany. But this whole process can be done withing the factory. Especially if your domain object factory makes a good use of correctly implemented DIC (which is quite rare, btw).
3. Prepare objects before they are released in the application
You should never do any computation in the constructor. It make impossible to test that code. Constructors should only contains simple variable assignments.
But this introduces an issue: sometimes you need to do few logical operations, before you can let other code structures to deal with your instantiated object. As beginners we usually do that in the constructor. But where to put it now?
This is where factories come to the rescue.
public function create( $name )
{
$instance = new $name;
if ( is_callable($instance, false, 'prepare') )
{
$instance->prepare();
}
return $instance;
}
Now, when you use $factory->create('foobar'), your object is fully primed to be used.
In general, you can use the factory to abstract from specific implementations. If you use the new <classname> operator, you instantiate a specific class every time. If you want to interchange this class with another implementation at a later time, you will have to manually change every new statement.
The factory pattern allows you to abstract from specific classes. A valid minimal use case might be something like this:
interface UserInterface {
public function getName();
}
class UserImplementationA implements UserInterface {
private $name;
public function getName() { return $this->name; }
}
class UserImplementationB implements UserInterface {
public function getName() { return "Fritz"; }
}
class UserFactory {
public function createUser() {
if (/* some condition */) return new UserImplementationA();
else return new UserImplementationB();
}
}
$f = new UserFactory();
$u = $f->createUser(); // At this point, you don't really have to care
// whether $u is an UserImplementationA or
// UserImplementationB, you can just treat it as
// an instance of UserInterface.
One use case (of many) when this becomes extremely useful is when working with unit tests. In Test-Driven Development, you often replace dependencies of classes with mock objects (objects that implement a certain interface, but don't really do anything). Using the factory pattern, it is quite easy to transparently substitute specific classes with mock classes.
public function build($name) {
$className = 'Models\\' . $name;
return new $className();
}
That would work for you.
Defining object factories is a good practice, when you would like to set some default properties to objects, and also, you will not have to worry in what namespace or directory some class exists.
Example:
public function createButton($name){
require("home/lib/display/Button.php") ;
$button = new Button($name, "some default param") ;
$button->visible = true ;
return $button ;
}
You just make default objects so quickly via such factories, besides keeping word new away.

return objects as a class property from function php

I am making an MVC application. I made this function in my loader class:
public function load_models($model)
{
if ($model) {
set_include_path($this->modelDirectoryPath);
spl_autoload_extensions('.php');
spl_autoload($model);
}
}
I'm using this function from my controller like this:
$this->load->load_models('news');
I want to access this model class like this:
$this->load->news->get_article();
But I can't unless I do this:
$this->load->news = new news();
$this->load->news->get_article();
I want to access it without typing $this->load->news = new news();. I also want it to be automatically instantiated. Can anyone help?
Make get_article() a static method and access it like this:
$this->load->news::get_article();
You cannot access non-static methods without instantiating at least one instance of the class. Even with reflection, you can't actually call and regular method.
You could implement a magic method in the load class that when you access any property such as
$this->load->news->get_article();
it checks to see if the 'news' property's name is also loaded a classname and if it is but it's not set to an instance of the class, create one and assign it to it.
This is the magic method:
public function __get(){ ... } ;
Basically, this magic method always gets called every time you access an object's ...every time you access an object's inaccesible properties (ones not declared or created)
You seem to be "channeling" something of CodeIgniter, which is severely outdated (if you want to know details, go to PHP chat room). That would not be the framework to emulate, if you want high quality code.
Oh, and the pattern you are implementing is actually MVP, not MVC .. there is a difference.
At first you should so is make autoloader, which actually works. Read about spl_autoload_register() .. how it is used, what it actually does. If you need some examples, beside the ones provided in comments, you can look up implementations of PSR-0. It should give you some idea, how to use it in practice.
This all would basically get rid of your $this->load->load_models('news'); line in controller.
in MVC the Model is a layer not an object/class. I don't intend to repeat whole song and dance, i wrote an answer on this some time ago .. it's long =/
you should not use new inside the controller, but not for same reason that you think. You should avoid new, because it causes tight coupling to the name of class. Instead you should provide your Controller instance with a Factory in constructor.
$factory = new DomainFactory( new PDO(...), $cache );
$controller = new Foobar( $factory );
$controller->$command($request);
This you could use in the controllers method like this:
public function __construct( $domain_factory )
{
$this->factory = $domain_factory
}
public function do_stuff( $request )
{
$id = $request->getQuery('id');
$articles = $this->factory->build('news')->get_article($id);
// thought i would split this line into two parts
}
Oh .. and what factory would do, would be this:
public function __construct( $pdo, $cache )
{
$this->pdo = $pdo;
$this->cache = $cache;
}
public function build( $name )
{
$instance = new $name;
$instance->assign_connection( $this->pdo );
$instance->assign_cache( $this->cache );
return $instance;
}
This should give you some ideas ..
Here are few links which you might find helpful, if you want to learn how to do good object oriented code, which follows best practices:
GUI Architectures <= start with this
Inheritance, Polymorphism, & Testing
Advanced OO Patterns (slides)
Unit Testing
The Principles of Agile Design
Global State and Singletons
Don't Look For Things!
Beyond Frameworks (slide)
Agility and Quality (slides)

Is this a good use of Registry?

Main goal is to make core classes (instantiated with params) available from any place in application - in controllers, mappers, models, helpers etc.
For example, we have mapper which depends on Database object:
class Foo_Mapper
{
private $database;
public function __construct(Database $database)
{
$this->database = $database;
}
public function getFoo(array $criteria)
{
// ...
}
}
Variant 1: Basic dependency injection. The problem is that every time when I need to create mapper, I also need to instantiate a database object (with params).
$database = new Database($params);
$foo_mapper = new Foo_Mapper($database);
Variant 2: Registry. Core objects are instantiated and put into registry so every other object can easily access them.
// Somewhere in bootstrap...
$registry = Registry::getInstance();
$registry->database = new Database($params));
// Usage
$registry = Registry::getInstance();
$foo_mapper = new Foo_Mapper($registry->database);
Is there a better way to do what I want? Any drawbacks?
Variant 1: Basic dependency injection. The problem is that every time when I need to
create mapper, I also need to instantiate a database object (with params).
or passing it along. If you use a Dependency Injection Container, you would even have to do that manually: you simply add that you need to retrieve a Database, and a Database will be created (or reused) for you. Ask the Container to create a controller, and make sure you list your dependencies in the constructor. There are a few decent Dependency Injection containers for PHP, to wit:
Bucket https://github.com/troelskn/bucket
Symfony Dependency Injection http://components.symfony-project.org/dependency-injection/
Phemto http://phemto.sourceforge.net/
Sphoof\Container http://code.google.com/p/sphoof/source/browse/lib/container.php?repo=v2
For full disclosure: I wrote the last one.
Variant 2: Registry. Core objects are instantiated and put into registry so every other
object can easily access them.
You could make the registry non-static, but if you're going to rely on a Registry object in your application, you might as well leave it static. This is a perfectly viable solution, with one obvious drawback: you don't know what objects are used by what objects by looking at the API. You'll have to dig into the code.
You could make this a Singleton. Like this:
class Database
{
private static $instance = null;
public static getInstance()
{
if (self::$instance == null) self::$instance = new Database();
return self::$instance;
}
// ... METHODS ... //
// ... METHODS ... //
// ..... //
}
Then you can use
new Foo_Mapper(Database::getInstance());
It looks like you did this with your registry. Then you don't really need your registry anymore. Though if your classes are coded by someone else you would still have to use something like a registry or make a helper class/function for every of those classes that do not use the singleton pattern.
I think the way you illustrated it seems ok to me. It would be bad if you call your registry from within Foo_Mapper, because that class should probably not know about the existence of the registry, but this way looks ok.

Refactoring of model for testing purpose

I want to refactor my model so I can properly write a unit test for it. But I have some dependencies. Can anybody point me in the right direction how I can remove these dependencies?
class Customer
{
public function save(array $data, $id = NULL)
{
// create or update
if (empty($id)) {
$customer = new \Entities\Customer();
} else {
$customer = $this->findById((int) $id);
}
$birthday = new DateTime();
list($day, $month, $year) = explode("/", $data['birthday']);
$birthday->setDate($year, $month, $day);
$customer->setFirstName($data['firstName']);
$customer->setLastName($data['lastName']);
$customer->setCompany($data['company']);
$languageModel = new Application_Model_Language();
$customer->setLanguage($languageModel->findById($data['language']));
$resellerShopModel = new Application_Model_ResellerShop();
$customer->setResellerShop($resellerShopModel->findById($data['resellerShop']));
$customer->setEmail($data['email']);
$customer->setPhone($data['phone']);
$customer->setGender($data['gender']);
$customer->setBirthday($birthday);
$customer->setType($data['type']);
$customerSectorModel = new Application_Model_CustomerSector();
$customer->setSector($customerSectorModel->findById($data['sector']));
$customerReferenceModel = new Application_Model_CustomerReference();
$customer->setReference($customerReferenceModel->findById($data['reference']));
if (isset($data['password'])) {
$customer->setPassword($this->_hashPassword($data['password']));
}
return $customer;
}
}
I guess your dependencies are the constructor calls in the function body. Out of my mind there are 3 ways to replace them in the unit test:
Create a mock library where all the different classes are implemented, and to run the test include the mock library instead of the real modules.
Add a set of default parameters for the external classes to your function declaration. In the end your new function declaration would look like public function save(array $data, $id = NULL, $newCustomer=\Entities\Customer(), $newLangModel = Application_Model_Language, ...). Also in the function body you use the variables to create the actual objects, like $customer = new $newCustomer(). In the test code you can override every depended class by a mock class.
You do not add a parameter for every class, but create two factories: one which creates the current objects, and one which creates mock objects. Inside of the function you request new objects only from the factory.
This approach is useful if there are many different places where the construction should be intercepted. If there is only one function which should be changed, a factory is over-engineering.
After looking back over your code, it appears this class is acting as both a Factory and Repository to the \Entities\Customer class (this was not obvious, so you could consider renaming to be more explicit your intentions). I also disagree with that function being named save since it is only returning an object that then needs to be persisted, but that is more semantics.
With the code as you have it now, I see two different tests that are needed.
1) Test your \Entities\Customer class.
Verify that each of your getters and setters are working correctly, or at least any one that has business logic behind it. For instance make sure that if you set the ResellerShop, then if you get a correct/valid ResellerShow object.
More or less, you need to test your business logic. Get/Set of basic fields (ex. Name) don't really necessitate their own tests (unless 100% code coverage is a goal, I don't think it is).
2) Test the (Factory\Repository) class.
Ensure the class you showed correctly creates (or fails) depending on the data passed into the array. For instance it should fail if required fields are not passed in, and it should not return a customer entity object.
The idea is for separation of concerns. Your Entity class should contain your business logic and should be tested separately from your object instantiation code.

How to Properly Enforce Correct Usage of a Class Method?

Our current ORM solution uses Data Mappers to represent tables / views in the database which then return a Collection object that can be used to iterate through the retrieved records as Model objects. Between the Data Mapper and Model layers is a Repository layer that handles domain requests to the data mappers and returns the corresponding collections or domain objects.
We are currently looking at refactoring the responsibilities of the Repository and Data Mapper layers so that all application requests to the Data Mapper layer are routed through the Repository and the Data Mapper returns the retrieved data rows to the Repository which then returns the necessary collection to the requesting object.
What I'm wondering is whether it is valid / good practice to pass the entire Repository object into the corresponding Data Mapper so that we can enforce access to the Data Mappers only through the Repository layer.
As an example this is basically how it works now:
class DataMapper {
public function findAll(Criteria $criteria)
{
$select = $criteria->getSelect();
// Build specific select statement
$rows = $this->_fetchAll($select);
return new Collection(array('data' => $rows, 'mapper' => get_class($this)));
}
}
I thinking of doing something like this:
class Repository {
public function findAllByName(Model $model)
{
$this->_criteria->addCondition('name LIKE ?', $model->name);
$rows = $this->_mapper->findAll($this);
return new Collection(array('data' => $rows, 'repository' => get_class($this)));
}
}
class DataMapper {
public function findAll(Repository $repository)
{
$select = $repository->getCriteria()->getSelect();
// Build specific select statement
$rows = $this->_fetchAll($select);
return $rows;
}
}
And then in this version, the Collection object would issue a call to the Repository which could first search through its cached objects and then only issue a call to the database to load the record if its needed.
Chris has a valid suggestion.
It partially depends on the context of the code, but dependency injecting the repository into the DataMapper instances you create, i.e:
$repo = new Repository();
$mapper = new DataMapper($repo);
Will spare you from subsequently having to pass that $repo around whenever you want to use findAll(). IE:
$mapper->findAll();
$mapper->findAllByName();
I find when parameters become a ubiquitous part of every function call I'm making, it makes sense to consider turning them into instance variables (especially when they're identical every time).
If your repository varies from between context/instances then the injection makes more sense. If you find that you're always creating one repo instance and would like to recycle it, a singleton might be appropriate.
The nice thing about Dependency Injection is it does clarify this dependency idea (ironic!). If you want to enforce it, you can do something like throw an exception if the $repo object is null, or not a Repository instance, in your __construct() method.
I would perhaps do this a little bit differently. I would add a setRepository(Repository $repos) method as well as a getRepository() method. Then, in your findAll method, call getRepository(). If setRepository() has not been called yet, then getRepository can return a default repository instance.
I would also perhaps create an interface for the Repository class so that different implementations of Repository can be used within the DataMapper class.
So the get method could look something like
public function getRepository()
{
if (!$this->_repository) {
$this->_repository = new Repository();
}
return $this->_repository;
}
and the set method could look something like
public function setRepository(RepositoryInterface $repos)
{
$this->_repository = $repos;
}

Categories