Correct implementation of Factory pattern in PHP - php

I have a question about correct way of implementing factory pattern in PHP used for instantiating complex objects with their dependencies. Let's assume the factory class has a 'build' method, so that for example class User is created in following way:
$factory->build('User');
The class User needs to retrieve the user data from the repository (database), so it depends on Repository object - the constructor looks like:
public function __construct(Repository $repository);
This means that 'build' method of the factory needs to call something like this
$user = new User(new Repository());
Now let's assume I also need to instantiate HomeController object which displays content on the home page. It is retrieving a list of latest articles - to display them on the home page, so it needs repository object as well. So build method will call something like this:
$home = new HomeController(new Repository());
So it is clear now that we have two instances of Repository object, while in fact one instance would be probably enough in this case. So I was wondering if it is a good practise for factory pattern to actually register instantiated Repository object (store it in $registeredObjects array of Factory object) and return it from the table if it was instantiated before. So the object creation in build method would look then like so:
$user = new User($this->build('Repository')); // Here Repository is created first time.
$home = new HomeController($this->build('Repository')); //Here it is retrieved from list of already registered objects
Repository object act in fact as a singleton in this case. I am wondering whether this approach is correct or it is better to instantiate two independent Repository objects.

Related

Pass class by config using ::class and retrieve in Laravel

I have a config file with such array:
'ppr' => [
'validate' => TestRequest::class
];
Now, I want to retrive this class in other part of the system and use it to validate form (outside of the controller).
While using config('main.ppr.validate') all I receive is namespaced name of the class instead of the class object.
As I already accepted that it won't be that easy to just use reuqests as in controllers, I still do wonder how to pass a class by config.
While passing eloquent models it works like a charm (or i.e. config arrays with middlewares etc.), so I suppose there is some magic binding to the IoC to achive that, is it true?
My question is, how to use class passed as in example above without initializing it like:
$obj = new $className;
Laravel (and many other applications) use Dependency Injection to achieve this magic -- your words, not mine! :D
It seems that the Service Container is what handles this in Laravel and should be of help to you.
Directly from the Laravel docs (linked above):
Within a service provider, you always have access to the container via the $this->app property. We can register a binding using the bind method, passing the class or interface name that we wish to register along with a Closure that returns an instance of the class:
$this->app->bind('HelpSpot\API', function ($app) {
return new HelpSpot\API($app->make('HttpClient'));
});
Also:
You may use the make method to resolve a class instance out of the container. The make method accepts the name of the class or interface you wish to resolve:
$api = $this->app->make('HelpSpot\API');
And:
If some of your class' dependencies are not resolvable via the container, you may inject them by passing them as an associative array into the makeWith method:
$api = $this->app->makeWith('HelpSpot\API', ['id' => 1]);
IMHO, I would look up where/how this is implemented in the native Laravel code (usually the Illuminate vendor) and see how it is used / meant to be implemented.
Furthermore, ClassName::class will return the namespace + class of that class. This is why you only see the class name and are not actually receiving an object/instance of that class.
I'm not sure what/where/why/how you're implementing your class and why you need this functionality somewhere that it doesn't already exist. Laravel is pretty good about already having things set up where you need them, so think twice before breaking out of the box and make sure there isn't a default solution for your situation!

Mocking a method on dynamically allocated instance?

Background: I'm working on an MVC framework for some practice, and want to make sure everything is 100% unit tested.
The setup currently is to have an instance of the application class (Ex_App). The main script asks a Dispatcher/Router for a controller name. This controller name is the name of a class implementing Ex_Controller. The result is returned as an instance of Ex_Dispatch_Result. This result is passed to the Ex_App instance using an invokeController($dispatchResult) function.
And this is where magic happens. The listing below is an excerpt:
$controllerName = $dispatchResult->getControllerName();
... checks for validaty of class name ...
$controller = new $controllerName();
$controller->prepare($this);
I'm using PHPUnit to do my unit testing, and am able to mock the dispatch result, correctly check that validating the class name of the controller works. The problem is how to check if prepare is called.
I'd like to do something similar to:
$mockController = $this->getMockBuilder('Ex_Controller')
->setMockClassName('Invoke_Correct_Controller')
->getMock();
$mockController->expects($this->once())->method('prepare');
However since a new instance of Invoke_Correct_Controller is created upon calling invokeController, it will not be this mock and thus the expects() call is completely irrelevant.
I could make the Ex_Dispatch_Result class responsible for returning a controller and testing that, but before returning an instance I will need to verify the correctness of the class name and in my opinion that responsibility should be with the Ex_App class and not the "dumb shell" Ex_Dispatch_Result class.
Is there something I am missing in the PHPUnit framework that I could use to test the code here, or some useful pattern that could work in my instance? I feel passing around controller names scales way better than passing around instances of controllers from the start, requiring the initialization of every possible controller. So, I kinda want to stick to passing around names and using the Ex_App as a factory for the controller instance.
Maybe I'm just over-thinking part of this problem, but that happens sometimes. It's why a fresh look by a third party often works :-)
There are couple of things you could do:
Extract controller creation logic to separate class e.g. ControllerFactory, and then mock controller factory instance, so that it returns your $mockController.
Extract controller creation logic to separate method and use partial mocking.
Return $mockController from $dispatchResult->getControllerName(), which probably requires mocking of $dispatchResult or even something else.
If you want more detailed answer, please provide more code samples of your classes and methods.

php fetch_object inheritance

I have class:
class item{
public id='';
public name='';
}
inside this class i want to have a function that fills up class with values from mysql query
like this:
$result_item = $this->mysqli->query("SELECT *
FROM items
WHERE item_id=".$item_id."
LIMIT 1");
$res = $result_item->fetch_object(SalesOrderItem);
$this = $res;
this code doesnt work, but is there a way to do this?
You need to look at the documentation around the mysqli::fetch_object.
Your class name needs to be specified as a string like so:
$result_item->fetch_object('SalesOrderItem'); // or 'item' your question is inconsistent here
You also may need to pass some values to the constructor to help you along. I would strongly recommend reading through the user notes on the documentation page - http://us3.php.net/manual/en/mysqli-result.fetch-object.php for some better examples of usage than given in the main documentation itself.
The fatal error you mention in your comments is because you can't change $this. That is an internal reference to the current object instance. Trying to change it make no sense.
If you intent is you have an object class that is, in essence, its own object relational mapper (ORM). To where it makes a call to the database, populates properties from records and somehow mutates itself into another class, this is not really possible. What you probably need to look to do is utilize a factory pattern of sorts to have a class that does nothing but instantiate classes of given type using the ORM approach.
So maybe usage would be like this:
// The class with MySQLi logic could be called something like MysqlObjectfactory
// It could take input like an instantiated mysqli object, DB table name,
// the class name you are trying to map to, and the id for the specific item in the class you are looking for
// it would use the logic noted above to generate an object with the specifications given
// and return it to the caller
$object = MysqliObjectFactory::getObject($mysqli, $db_table, $class_name, $id);
The other thought that jump to my mind is: why reinvent the wheel? It sounds like what you are looking for is an object relational mapper. There are several of these for PHP that are really widely used: Doctrine, Propel, PHP Active Record, etc. You might check these out as they will give you a lot more functionalitu/flexibility than trying to do this with mysqli::fetch_object() where the mapping depends on the database field (or provided alias in SQL) exactly matching the class property names (that is without having to do mapping in class constructor).

CakePHP Model instances confusion

After debugging quite a bit, I noticed a really strange behaviour inside of CakePHP's (2.x) Model usage:
When I changed the Model ID and used read(), on a completly different object instance with a relation to the same Model, it overwrites the old Model data.
// set the user, by using the 'User' model
$this->User->id = 1;
$this->User->read();
print_r($this->User->data); // works correctly
$instance = new Notification(); // this has a relation to the 'User' model
print_r($instance->User->data); // == $this->User->data! why?!
$instance->User->id = 2;
$instance->User->read();
print_r($this->User->data); // == $instance->User->data!
Why are those Models connected with each other? Shouldnt they be completly separated, since it's a new instance? I mean, I'm setting the 'User' model for the Notification, not for $this
And if that's default behaviour - how can I read() data into different instances, whitout changing other models? Do I really need to manually create a new 'User' instance and store it somewhere in $instance to avoid this behaviour? That sounds rather ugly to me.
Model instances are singletons
The following two objects in the question are identical:
$this->User
$instance->User
Because they are literally the same object, the path used to access an object doesn't modify the behavior of the (User) object itself.
That's simply how ClassRegistry::init works - it stores a reference to model instances - and will return the same object when queried for the same alias (className) again.
Don't create models using new
Doing that is not normal - and will likely cause problems or at least confusion in the future. To get a reference to the Notification model, use $uses, loadModel or ClassRegistry::init as appropriate.
Don't use Model::read
Do I really need to manually create a new 'User' instance
Absolutely not, that's not how models are intended to work with CakePHP. A model class is effectively the interface to the database, it's not a representation of a single row (except when calling save).
The simplest way to avoid a significant number of problems is to not use Model::read at all, and instead use any appropriate find call; A more complete code example would permit a more specific answer.

Predefining requirements before starting a controller object. Is it called DI container?

I've been using registry pattern for a very long time. Basically, I load all the classes using a main object (even if they're not required by the controller itself) and controllers can reach them.
It loads like 20 classes currently and I want to change my approach.
I want to define dependencies for my controllers. For example, my register controller only depends on database class, recaptcha class and filter class.
So, I want to create a solution like this:
//dependencies
$registerDependencies = array(new Database(), new Recatpcha(), new Filter());
//load register controller
$this->loadController->('register', $this->loadDependencies($registerDependencies));
Is it called DI/DI Container?
Is this a better approach than my current system?
I would probably use this approach:
$this->loadController->register('database.main', 'Database')
->register('database.user', 'Database')
->register('recaptcha', 'Racatpcha');
And the register function would look like this
public function register($serviceName, $serviceClass)
{
// you can inject options to your class via a config array or a conf file
$this->registry[$serviceName] = new $serviceClass();
}
If you give an alias to your service, you could have multiple services that share the same class but with different parameters.
The service 'database.main' could connect to a DB and 'database.user' to another DB.
Symfony2 uses dependency injection and you can find documentation about the component on their website.

Categories