PHP Decorator Debugging - php

Reading this article and worked through the Decorator example. The code is returning <strong></strong> instead of the expected <strong>Logout</strong>.
class HtmlLinks {
//some methods which is available to all html links
}
class LogoutLink extends HtmlLinks
{
protected $_html;
public function __construct() {
$this->_html = "Logout";
}
public function setHtml($html) {
$this->_html = $html;
}
public function render() {
echo $this->_html;
}
}
class LogoutLinkStrongDecorator extends HtmlLinks {
protected $_logout_link;
public function __construct( $logout_link ) {
$this->_logout_link = $logout_link;
$this->setHtml("<strong>" . $this->_html . "</strong>");
}
public function __call( $name, $args ) {
$this->_logout_link->$name($args[0]);
}
}
$logout_link = new LogoutLink();
$logout_link = new LogoutLinkStrongDecorator($logout_link);
$logout_link->render();
Tried to debug all afternoon but I haven't made any headway. Any insight would be appreciated.

Looks like you forgot to pull the _html from the inner object. You need to add it to each constructor method of each decorator. Basically add this $this->_html=$_linked_obj->_html.

Decorator pattern:
The Decorator and the Decorated Object implement the same interface.
The Decorator takes an object implementing the shared interface in its constructor.
You don't necessarily want your decorator to inherit from the class it decorates. You just care that it implements the method you need in the context you're using it (in this case, "render()"), which you can enforce by using Interfaces. The benefit of using inheritance is that all other methods are guaranteed to still be callable, and you'll also get back an instance of the class you passed in.
The code:
interface Renderable
{
public function render();
}
class HtmlLink implements Renderable
{
public function render()
{
return ''.$this->anchorText.'';
}
// other link methods...
}
class StrongRenderableDecorator implements Renderable
{
protected $renderable;
public function __construct(Renderable $renderable)
{
$this->renderable = $renderable;
}
public function render()
{
return '<strong>'.$this->renderable->render().'</strong>';
}
}
$logout_link = new StrongRenderableDecorator(new LogoutLink());
$logout_link->render();

Related

Confusion about adapter pattern and inheritance (PHP)

I'm having some confusion with the adapter pattern and am wondering if it is the right tool for what I'm trying to accomplish.
Basically, I'm trying to get a class written by another developer to conform to an interface that I've written while also retaining the other methods from that class.
So I've written the following interface for a container object:
interface MyContainerInterface
{
public function has($key);
public function get($key);
public function add($key, $value);
public function remove($key);
}
I've also written an adapter that implements that interface:
class OtherContainerAdapter implements MyContainerInterface
{
protected $container;
public function __construct(ContainerInteface $container) {
$this->container = $container;
}
public function has($key) {
$this->container->isRegistered($key);
}
...
}
And am using it in my class as follows:
class MyClass implements \ArrayAccess
{
protected $container;
public function __construct(MyContainerInterface $container) {
$this->setContainer($container);
}
public function offsetExists($key) {
$this->container->has($key);
}
...
}
Then my application uses the class as so:
$myClass = new MyClass(new OtherContainerAdapter(new OtherContainer));
The issue I'm having is that in order to use the methods from the adapter I have to write the following:
$myClass->getContainer()->getContainer()->has('some_key');
When ideally it would just be:
$myClass->getContainer()->has('some_key');
$myClass->getContainer()
should return an instance of MyContainerInterface and that has a has() function. It shouldn't have a getContainer() function.
I don't think you need the Adapter Pattern for this. It looks to me like you're after a polymorphic solution, which can be accomplished by simply using an abstract class. No adapter needed.
The interface
interface MyContainerInterface
{
public function has($key);
public function get($key);
public function add($key, $value);
public function remove($key);
}
Then the abstract base class:
class MyContainerBaseClass implements MyContainerInterface, \ArrayAccess
{
public function offsetExists($key) {
$this->has($key);
}
...
}
Then, the sub-class from the other developer:
class ClassByOtherDeveloper extends MyContainerBaseClass
{
public function has($key) {
$this->isRegistered($key);
}
//you also need to implement get(), add(), and remove() since they are still abstract.
...
}
You can use it in your application like this:
$object = new ClassByOtherDeveloper();
$x = $object->has('some_key');
I'm assuming the isRegistered method lives in the implementation from the other developer.
To make it truly polymorphic you wouldn't hard-code the class name, but you'd use a variable that could come from a config file, database, or a Factory.
For example:
$className = "ClassByOtherDeveloper"; //this could be read from a database or some other dynamic source
$object = new $className();
$x = $object->has('some_key');

Can I reuse decorators?

Can I reuse decorators?
I have a ClientDecorator to decorate an entity that has a reference of a client, this decorator gets the client on database on call getClient (before it gets decorated, this method returns the clientId, after being decorated, it returns an instance of Client).
Okay, but, I've some other entities that can be decorated with the same decorator, for example, I have another table named questions, this table has a reference pointing to a client that has asked a question, and I have another table named schedules, that has a reference of a client.
By the way, I can decorate question and schedule with ClientDecorator.
But, I have an QuestionDecorator too; this guy decorates an Answer, etc.
How I can do this abstraction, so I can reuse decorators whenever I want?
I've tried to create ClientDecorable, QuestionDecorable interfaces, but have made no progress.
You can always instance the decorator class passing parameters to the constructor that will tell it how it should behave or what class it should impersonate. You don't really have to declare your decorator as an extension of another class.
PHP classes support magic methods that make it possible to forward calls to the class your object is impersonating, just as if it was extending it with extends.
For instance:
class Client
{
public function getId() { return 123; }
}
class Decorator
{
private $instance = null;
public function __construct($class)
{
$this->instance = new $class();
}
public function __call($method, $params) // magic method
{
return call_user_func_array(array($this->instance, $method), $params);
}
}
$object = Decorator('Client');
echo $object->getId(); // 123
The magic method __call() will be invoked when you try to access a method that doesn't belong to the class Decorator. The same can be done with properties by using the magic methods __get() and __set().
That's a really tricky problem. I could find a solution, but it is kind of McGiver style... Works for PHP 5.4+ (yes, traits).
<?php
interface Decorable
{
public function getTarget();
}
interface ClientDecorable extends Decorable
{
public function getClient();
}
interface LogDecorable extends Decorable
{
public function getLog();
}
abstract class AbstractDecorator implements Decorable
{
private $target;
public function __construct(ClientDecorable $target)
{
$this->target = $target;
}
public function getTarget()
{
// I'll be able to access the leaf node of my decorator single way 'tree'
return $this->target->getTarget();
}
public function __call($method, $args) {
$reflected = new ReflectionClass($this->target);
if ($reflected->hasMethod($method)) {
return call_user_func_array([$this->target, $method], $args);
}
}
}
class ClientDecorator extends AbstractDecorator implements ClientDecorable
{
public function __construct(Decorable $target) {
if (! $target->getTarget() instanceof ClientDecorable) {
throw new Exception('Must be an instance de ClientDecorable');
}
parent::__construct($target);
}
public function getClient()
{
return new Client($this->getTarget()->getClient());
}
}
class LogDecorator extends AbstractDecorator implements LogDecorable
{
public function __construct(Decorable $target) {
if (! $target->getTarget() instanceof LogDecorable) {
throw new Exception('Must be an instance de LogDecorable');
}
parent::__construct($target);
}
public function getLog()
{
return new Log($this->getTarget()->getLog());
}
}
abstract class AbstractTarget implements Decorable
{
// this does the trick
public function getTarget() { return $this; }
}
trait ClientDecorableTrait {
public function getClient()
{
return $this->client;
}
}
trait LogDecorableTrait {
public function getLog()
{
return $this->log;
}
}
class Payment extends AbstractTarget implements ClientDecorable, LogDecorable
{
use ClientDecorableTrait;
use LogDecorableTrait;
private $client = 1;
private $log = 101;
}
class Sale extends AbstractTarget implements ClientDecorable
{
use ClientDecorableTrait;
private $client = 2;
}
class Client
{
// ...
}
class Log
{
// ...
}
$sale = new Sale();
var_dump($sale->getClient());
$saleDec = new ClientDecorator($sale);
var_dump($saleDec->getClient());
$payment = new Payment();
var_dump($payment->getClient());
$paymentDec = new ClientDecorator($payment);
var_dump($paymentDec->getClient());
var_dump($paymentDec->getLog());
$paymentDecTwice = new LogDecorator($paymentDec);
var_dump($paymentDecTwice->getLog());
$saleDecTwice = new LogDecorator($saleDec); // will throw an exception
This is just a skeleton, a real world implementation must be tricky. I think you'd better keep your decorators separated...

Changing the Privacy Scope of PHP Class Functions

I have an abstract class that extends classes to provide a basic orm function. All the functions it provides are protected to the class so it can decide what fields are made publicly available to outside objects. But recently, I have started working with some smaller data classes that do not require such complexity, and would benefit from having the orm editing functions publicly available and no special functions.
As the naming convention for the functions is sufficient and compact, is there a way to change the existing functions to public (without needing the same class, or an interim extends), or would I have to use the new traits feature of php to add an existing class, which contains public versions of the functions that act as an abstraction layer for the internal protected functions?
EDIT:
For the traits method, I was thinking that it would help like this:
abstract class ORMClass {
public function __construct($pk) {}
protected function __get($k) {}
protected function __set($k,$v) {}
protected function save() {}
}
trait publicORM {
public function __get($k) { return parent::__get($k); }
public function __set($k,$v) { return parent::__set($k,$v); }
public function save() { return parent::save(); }
}
class myOrm extends ORMClass {
use publicORM;
protected static $table = 'myTable';
}
so then I could use myOrm like:
$myOrm = new myOrm(1);
$myOrm->foo = 'alice'
echo $myOrm->bar;
$myOrm->save();
without needing the:
public function __get($k) { return parent::__get($k); }
public function __set($k,$v) { return parent::__set($k,$v); }
public function save() { return parent::save(); }
to be listed in the class myOrm
Since this was never answered properly, I'm adding Charles answer.
This can be done using PHP's Reflection library, built in to PHP since version 5. This particular method is fairly hacky:
<?php
abstract class BaseClass {
protected function testMe() {
echo 'I WORK!';
}
}
class ConcreteClass extends BaseClass {
// Class Code
}
$method = new ReflectionMethod('BaseClass', 'testMe');
$method->setAccessible(true);
$method->invoke(new ConcreteClass()); // Prints 'I WORK!'
And here is the better method using an interim abstract class that extends the base class but uses public methods:
<?php
abstract class BaseClass {
protected function testMe() {
echo 'I WORK!';
}
}
abstract class PublicBaseClass extends BaseClass {
public function testMe() {
parent::testMe();
}
}
class ConcreteClass extends PublicBaseClass {
// Class Code
}
$obj = new ConcreteClass();
$obj->testMe();

When to put factory() method into factoried object and when put factory() method to separated class?

Is it ok to put factory() method to the factoried object's class?
class User {
public static function factory($id) {
return new User($id);
}
private function __construct($id) {
}
}
And when consider placing factory() method into separated class?
class User {
public function __construct($id) {
}
}
class UserFactory {
public static function factory($id) {
return new User($id)
}
}
I can't see any benefits of using additional class for factory, but I consider that there are some benefits I don't know about. :)
When to put factory() method into factoried object and when put factory() method to separated class?
The advantage with putting the factory method inside the class itself is protecting the class from being instantiated without using the factory method:
class User {
public static function factory($id) {
return new User($id);
}
private function __construct($id) {
// Now, only the factory method within this class can call this method.
// (Additionally, this method was static, which it shouldn't.)
}
}
I let other add to this with advantages of the opposite solution.
If you have a static creator method there is not much use in putting in into a factory.
It's only really useful to put factory method in it's own class if it isn't static and you want to inject it somewhere.
class User {
public static function __construct($id) {
}
}
class UserFactory {
public function factory($id) {
return new User($id)
}
}
class SomethingUserReleated {
public function __construct(UserFactory $factory) {
$this->userFactory = $factory;
}
public function iNeedToCreateAnUserForSomething() {
$userOne = $this->userFactory->factory(1233);
$userTwo = $this->userFactory->factory(123533);
}
}
Since you can't to the above with static methods.
Moving the factory methods into separate class allows you to separate object-methods and factory-specific methods (that are only needed while creating a new object).
class User {
public static function __construct($id, $name){
// call this directly or via Factory
}
}
class UserFactory {
private static function randomName(){
// return some random name
}
public static function factory($id){
return new User($id, UserFactory::randomName());
}
}

PHP Classes: get access to the calling instance from the called method

sorry for that weird subject but I don't know how to express it in an other way.
I'm trying to access a method from a calling class. Like in this example:
class normalClass {
public function someMethod() {
[...]
//this method shall access the doSomething method from superClass
}
}
class superClass {
public function __construct() {
$inst = new normalClass;
$inst->someMethod();
}
public function doSomething() {
//this method shall be be accessed by domeMethod form normalClass
}
}
Both classes are not related by inheritance and I don't want to set the function to static.
Is there any way to achieve that?
Thanks for your help!
You can pass a reference to the first object like this:
class normalClass {
protected $superObject;
public function __construct(superClass $obj) {
$this->superObject = $obj;
}
public function someMethod() {
//this method shall access the doSomething method from superClass
$this->superObject->doSomething();
}
}
class superClass {
public function __construct() {
//provide normalClass with a reference to ourself
$inst = new normalClass($this);
$inst->someMethod();
}
public function doSomething() {
//this method shall be be accessed by domeMethod form normalClass
}
}
You could use debug_backtrace() for this. It is a bit iffy but for debugging purposes it is usefull.
class normalClass {
public function someMethod() {
$trace = debug_backtrace();
$trace[1]['object']->doSomething();
}
}
You have a few options. You can use aggregation like so
class normalClass
{
protected $superClass;
public function __construct( superClass $superClass )
{
$this->superClass = $superClass;
}
public function someMethod()
{
$this->superClass->doSomething();
}
}
class superClass
{
public function __construct()
{
$inst = new normalClass( $this );
$inst->someMethod();
}
public function doSomething()
{ //this method shall be be accessed by domeMethod form normalClass
}
}
Or just a straight-up setter
class normalClass
{
protected $superClass;
public function setSuperClass( superClass $superClass )
{
$this->superClass = $superClass;
}
public function someMethod()
{
if ( !isset( $this->superClass ) )
{
throw new Exception( 'you must set a superclass' );
}
$this->superClass->doSomething();
}
}
class superClass
{
public function __construct()
{
$inst = new normalClass();
$inst->setSuperClass( $this );
$inst->someMethod();
}
public function doSomething()
{ //this method shall be be accessed by domeMethod form normalClass
}
}
Depending on your use case, you might want to pass the instance to the function only:
class normalClass {
public function someMethod($object) {
$object->doSomething();
}
}
If normalClass::someMethod() can be called by multiple, distinct $objects, this might be the better choice (instead of providing the $object to the whole normalClass instance).
But regardless of that you might consider creating an Interface to use for type hinting:
interface ISomethingDoer {
public function doSomething();
}
class normalClass {
public function someMethod(ISomethingDoer $object) {
# Now PHP will generate an error if an $object is passed
# to this function which does not implement the above interface.
// ...
class superClass implements ISomethingDoer {
// ...
woah I had the same problem than you but instead of going with the so simple pass the reference to the object, I went with an event manager, Basically, when something would happen in the normal class, it would trigger an event which was listened by a class and that said class(the listener) would call the super class to execute that functionality and if necessary pass it new arguments.
Anyways, whether you pass it as a parameter to your object or you go with an event based approach, both solutions work. Choose the one you prefers.
For more information on events, sympony explains it quite good.
http://symfony.com/doc/current/components/event_dispatcher/introduction.html

Categories