I have been researching so many times, asking experts on stackoverflow for the best practice, but I still could not find the solution, I might have got told the correct answer, but I didn't get it.
I always wanted to create a 'proper' MVC pattern to work on my projects, I have been researching for example this http://www.phpro.org/tutorials/Model-View-Controller-MVC.html but I got told that this is awful design, and I should not use the registery pattern anymore.
So I looked at teresko's answer, even though it's very old, can be seen here How should a model be structured in MVC? and I got the idea there, to use a global factory, which will create other factories
The idea I got from there, is to have a big factory, called ServiceFactory
which will create instances of other factories like ModelFactory which will create instances of classes that are serving the model layer, and a ViewFactory, which will serve the view (Pretty useless at the moment I think).
But got something like this:
namespace library\application;
use library\application\exceptions\ClassNotFoundException;
use library\application\exceptions\PackageNotFoundException;
class ServiceFactory {
private $mapper;
private $package;
private $services = array();
public function __construct(DataMapper $mapper) {
$this->mapper = $mapper;
}
/**
* Setting a default package
* @param $package string Package path
* @throws exceptions\PackageNotFoundException
*/
public function setDefaultPackage($package) {
if (is_dir('library' . $package)) {
$this->package = 'library' . $package;
return;
}
throw new PackageNotFoundException("The package: " . $package . " was not found.");
}
/**
* @param $name string Class name
* @param null $constructor IF the class needs constructor parameters, use it.
* @return Factory
* @throws exceptions\ClassNotFoundException
*/
public function create($name, $constructor = null) {
$path = $this->package . "\\" . $name;
if (file_exists($path)) {
if ($constructor) {
return new $path($constructor);
}
return new $path;
}
throw new ClassNotFoundException("The requested class was not found: " . $path);
}
/**
* @param $name string Class name
* @param $object object Object to register
*/
public function register($name, $object) {
$this->services[$name] = $object;
}
/**
* @param $name string Class name
* @return Factory
*/
public function get($name) {
if (isset($this->services[$name])) {
return $this->services[$name];
}
return null;
}
}
This is awesome actually, but in my opinion, OO-wise, it's totally wrong, because it's not object-oriented friendly, since the returning object of S ServiceFactory::create()
is anonymous, well fine, It's no longer anonymous, because the purpose of the class is to create instances of factories, sure, just added the interface of the factories in return.
But now the next problem, when I want to use the factories to create objects, that should not have the same interface, will cause problems to my IDE, since it doesn't know what is the object I am going to return, it can be Foo, can be Car and one day it can be HelloWorld.
So I always will have to declare a variable with the object when using it in the controller:
/**
* @var $items Items
* @var $categories CategoryModel
*/
$items = parent::getModelFactory()->create('Items');
$items->setDb(parent::getDatabase());
$categories = parent::getModelFactory()->create('Categories');
$categories->setDb(parent::getDatabase());
Now in one of Teresko
's answer(s), it says the following rule: A controller can not create instances of the Model layer
So I assume he means like $foo = new Foo(); $foo->method($db);
in the controller, but why not? how should a controller actually communicate the model layer?
The main purpose of me creating that god factory class, is to prevent doing new Object()
in the controller class, but since it's calling the factory, which creates the instance, it's still considered as I am creating an instance of a model layer in a controller (I think).
I also could cache objects, using ServiceFactory::register()
method, but that doesn't change the situation.
So is the ServiceFactory
and factories idea fine ? What is the correct way communcating between the controller and the model layer?