CakePHP - passing constructor arguments to custom components - php

I am trying to use a custom class in cakephp. Initially I had created a vendor class which works fine but I can't use other cakephp components.
To use built in components like $this->Text, I can create a custom component but the constructor requires a argument which is a json object returned from an API and I need to keep initializing in a loop
//The constructor for the class
function __construct($objValue) {
$this->messageId = $objValue['id'];
Is using a component suitable for this purpose?

you don't need to create a component here if you don't need it in the controller scope.
also you don't need to make it a vendor class (which is third party stuff).
cake offers you a way out: Libs in APP/Lib
You can use them anywhere anytime.
App::uses('MyClassName', 'Lib');
$MyClass = new MyClassName();
You might even want to create a package in Lib itself - e.g. "Lib/Utility":
App::uses('MyClassName', 'Utility');
without knowing any more about what exactly this custom class does, it is difficult to be any more specific here.

Related

Using guzzle with CakePHP 2.x

I am trying to use guzzle 6.x on a CakePHP 2.x application.
What I need to do is to initialize Guzzle Client to some of my controllers but on the controllers that it will be loaded I need it to be loaded with the same configuration.
Basically what I don't know is which is the best approach to implement it. I was thinking about the following:
Shall I create a function in AppController that will create and return a Guzzle object and then save it to a protected property inside AppController? Maybe a function like setUpGuzzle() and call this function on the Controllers I need to load Guzzle Client.
Shall I create a component and then load Guzzle Client to a public property of this component. Then I could use it like this $this->HttpClient->client->post()
Shall I create a component and write one function for each of Guzzle public function? So I will have something like this $this->HttpClient->post().
Thing is I don't like any of the above and I was hopping maybe there could be another way to do this. For example create a components which loads the Guzzle Client in a controller or loads the Guzzle Client inside the component collection.
Do you really need Guzzle? I agree that the old Cake2 HTTP socket is old fashioned but is there something it can't do that requires you to add yet another lib?
Use a trait, as long as you're not stuck to an ancient php version this is a clean solution. Here is some pseudo-code that will give you the high level idea:
trait HttpSocket {
protected $_httpSocket = null;
protected $_httpSocketConfig = [
// Default config goes here
];
public function getHttpSocket() {
if (empty($this->_httpSocket)) {
// Not sure how the constructur works, so it's just an example
$this->_httpSocket = new Guzzle($this->_httpSocketConfig);
}
return $this->_httpSocket;
}
}
If you ever need to change the config or the whole socket implement ion you just have to change it in a single place without the overhead of a component. Also this can be use in any class, not just controllers. What you're looking for is more or less a simple factory like method, no need for a whole controller.
If you can't use a trait then you'll have to use a component or just put the above code not inside a trait nor a component but directly inside your AppController, but you won't be able to use it outside the scope of the controllers that inherit that controller then.

Slim framework shared code in routes

I have a route group with 6 routes inside it. I check the parameters on every route against the database.
What's the best way to achieve this? Build a class for it?
When working with a database, it really depends on how much you will be using it. Slim has no database integration, so you could access the database by either using basic php or using a ORM tool to assist you in talking with your database.
One orm that is quick and easy to use is idiorm http://idiorm.readthedocs.org/en/latest/index.html
There are other more robust things out there and it all depends on what you are trying to accomplish. Really, to give a "best" solution, we would need more information on the situation and also how you would quantify "best."
Try use Slim Middleware.
Add your check part as one middleware, and share a middleware for all routes. Then you will be happy.
Depending on your needs, you can also try using class instances as route callbacks.
Define a base class with all the database functionality and use "Class Controllers" available since version 2.4.0 (November 2013).
class Base {
// Define all your shared DB methods and properties here
}
Use child classes of your base class as controller class instances, as callbacks for your Slim app routes (and their parameters):
$app->get('/user/:id/', '\Base\User:find');
Getting an instance of $app in the callback class instance is easy enough:
class User extends \Base {
public function find($theUserId) {
// ...
// You can easily get access to $app here, too:
// $app = \Slim\Slim::getInstance();
}
}

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.

How to access libraries inside a controller?

I'm building a small framework that I can use for repeated mundane stuff on future small projects.
I'm stuck on the best way to access libraries from inside a controller. I originally implemented a system similar to CodeIgniter's whereby my main controller class is basically a super object and loads all the classes into class variables which are then accessed by extending the controller and doing like $this->class->method()
I find that a little ugly, though. So I thought of just loading each class individually on a per-use basis in each controller method.
What's the best (cleanest) way of doing this?
To only ever have one instance of each class, you could create a simple service container.
class ServiceContainer
{
protected $services;
public function get($className)
{
if (!array_key_exists($className, $this->services)) {
$this->services[$className] = new $className;
}
return $this->services[$className]
}
}
Then create one ServiceContainer instance per application. Inject the container into all of your controllers and use
public function someAction()
{
$this->container->get('Mailer')->send($email_data);
}
Simple example, and obviously needs a lot of work to make useable (for instance autoloading needed and handling of file paths for ease of use, or easier way to add services without getting them, etc).
I dont like the way CodeIgniter does it. Its never seemed right to me. I favor an auto loading class pushed onto the spl_autoload stack. And then just calling the class as normal like:
$class = new SomeClass();
PHP provides autoload functionality with SPL and spl_autoload (and related functions). You can register a custom autoloader for your library code.
For the shared functionality handled by your application, have you considered the Front Controller design pattern?

PHP workaround to extend classes of the same name?

I know extending a class with the same name is not possible, but I was curious if anyone knew of a way to load a class then rename it, so i can later extend it with the original name. Hopefully like something below:
<?php
//function to load and rename Class1 to Class2: does something like this exist?
load_and_rename_class('Class1', 'Class2');
//now i can extend the renamed class and use the original name:
class Class1 extends Class2{
}
?>
EDIT:
Well, I understand that this would be terrible practice in a basic OOP environment where there are large libraries of class files. But i'm using the CakePHP MVC framework and it would make great sense to be able to extend plugin classes in this way since the framework follows a well established naming convention (Model names, view names, controller names, url routes (http://site.com/users), etc).
As of now, to extend a CakePHP plugin (eg: Users plugin) you have to extend all the model, view, and controller classes each with different names by adding a prefix (like AppUsers) then do some more coding to rename the variable names, then you have to code the renamed url routes, etc. etc. to ultimately get back to a 'Users' name convention.
Since the MVC framework code is well organized it would easily make sense in the code if something like the above is able to be implemented.
I'm trying to work out why this would be necessary. I can only think of the following example:
In a context that you have no control over, an object is initialised:
// A class you can't change
class ImmutableClass {
private function __construct() {
$this->myObject = new AnotherImmutableClass();
}
}
$immutable = new ImmutableClass();
// And now you want to call a custom, currently non existing method on myObject
// Because for some reason you need the context that this instance provides
$immutable->myObject->yourCustomMethod();
And so now you want to add methods to AnotherImmutableClass without editing either Immutable class.
This is absolutely impossible.
All you can do from that context is to wrap that object in a decorator, or run a helper function, passing the object.
// Helper function
doSomethingToMyObject($immutable->myObject);
// Or decorator method
$myDecoratedObject = new objectDecorator($immutable->myObject);
$myDecoratedObject->doSomethingToMyObject();
Sorry if I got the wrong end of the stick.
For more information on decorators see this question:
how to implement a decorator in PHP?.
I happen to understand why you would want to do this, and have come up with a way to accomplish what the end goal is. For everyone else, this is an example of what the author may be dealing with...
Through out a CakePHP application you may have references to helper classes (as an example > $this->Form->input();)
Then at some point you may want to add something to that input() function, but still use the Form class name, because it is through out your application. At the same time though you don't want to rewrite the entire Form class, and instead just update small pieces of it. So given that requirement, the way to accomplish it is this...
You do have to copy the existing class out of the Cake core, but you do NOT make any changes to it, and then when ever you upgrade cake you simply make an exact copy to this new directory. (For example copy lib/Cake/View/Helper/FormHelper.php to app/View/Helper/CakeFormHelper.php)
You can then add a new file called app/View/Helper/FormHelper.php and have that FormHelper extend CakeFormHelper, ie.
App::uses('CakeFormHelper', 'View/Helper');
FormHelper extends CakeFormHelper {
// over write the individual pieces of the class here
}

Categories