<?php
/**
* My codebase is littered with the same conditionals over and over
* again. I'm trying to refactor using inheritance and the Factory
* pattern and I've had some success but I'm now stuck.
*
* I'm stuck because I want to derive a new class from the one
* returned by the Factory. But I can't do that, so I'm obviously
* doing something wrong somewhere else.
*/
/**
* The old implementation was as follows. There's if statements
* everywhere throughout both LayoutView and ItemIndexView and
* SomeOtherView.
*/
class LayoutView { }
class IndexView extends LayoutView { }
class SomeOtherView extends LayoutView { }
/**
* Below is the new implementation. So far I've managed to tidy
* up LayoutView (I think I have anyway). But now I'm stuck because
* the way I've tidied it up has left me not knowing how to extend
* it.
*
* For example's sake, let's say the conditions were relating to a
* type of fish: salmon or tuna.
*/
abstract class LayoutView {
protected function prepareHeader() { echo __METHOD__, "\n"; }
protected function prepareLeftHandSide() { echo __METHOD__, "\n"; }
protected function prepareFooter() { echo __METHOD__, "\n"; }
public function prepare() {
$this->prepareHeader();
$this->prepareLeftHandSide();
$this->prepareFooter();
}
}
class SalmonLayoutView extends LayoutView
{
protected function prepareLeftHandSide() { echo __METHOD__, "\n"; }
}
class TunaLayoutView extends LayoutView
{
protected function prepareLeftHandSide() { echo __METHOD__, "\n"; }
protected function prepareFooter() { echo __METHOD__, "\n"; }
}
class ViewFactory {
public static function getLayoutView($fishType) {
switch($this->$fishType) {
case 'salmon':
return new SalmonLayoutView();
break;
case 'tuna':
return new TunaLayoutView();
break;
}
}
}
/**
* Now LayoutView has been cleaned up and the condition that was once
* scattered through every LayoutView method is now in one place.
*/
$view = ViewFactory::getLayoutView( Config::getOption('fishtype') );
$view->prepare();
/**
* Now here's where I'm stuck. I want to effectively extend whatever
* class $view is an instance of.
*
* The reason being, I wish to derive a view to show an index of
* articles within the appropriate *LayoutView. The IndexView code is
* the same for Salmon and Tuna.
*
* I can do something like this:
*/
class SalmonIndexView extends SalmonLayoutView { }
class TunaIndexView extends TunaLayoutView { }
/**
* But then I'll be writing the same IndexView code twice. What I'd
* like to do is something like this:
*/
$view = ViewFactory::getLayoutView( Config::getOption('fishtype') );
class IndexView extends get_class($view) { }
/**
* But I'm pretty certain that's not possible, and even if it was
* it seems very wrong.
*
* Can someone more experienced in refactoring and OO please let
* me know where I've gone wrong and suggest a clean way to solve
* this?
*/
If the IndexView code really is the same then you don't need inheritance, but composition. Add, in your base LayoutView class, an instance of IndexView that then you'll be able to call from each *LayoutView.
Inheritance is due only when the relationship between objects is is-a. I deduce that an IndexView is not a LayoutView, but rather the LayoutView has an IndexView.
Check this out, I don't agree with everything it says, but still:
http://phpimpact.wordpress.com/2008/09/04/favour-object-composition-over-class-inheritance/
Just pass the template as a parameter to the subviews you'll compose. I don't think that'd be evil in this case. Although if it's a standard framework you might be better asking in their forums, because they might have a functionality we are unaware of for this case (it usually happens)
You could have something like
class LayoutView {
protected View $subview; //Potentially an array of views
public function prepare() {
// empty, to be filled out by derived classes
}
public function setSubView($view) { $this->subview = $view; }
public function display() {
$this->prepare();
$this->subview->prepare($this->template);
$this->template->render();
}
}
class IndexView {
protected View $subview; //Potentially an array of views
public function prepare() {
// empty, to be filled out by derived classes
}
public function prepare($template) {
//operate on it, maybe even assigning it to $this->template
}
public function setSubView($view) { $this->subview = $view; }
public function display() {
$this->prepare();
$this->subview->prepare($this->template);
$this->template->render();
}
}
Related
I have a set of objects (MainObject) which are uniquely defined by two objects (SubObject1, SubObject2) and a string (theString). I with to retrieve a MainObject from the set by returning an existing object based on the two subobjects and string should it exist, else creating a new one, adding it to the set, and returning that object.
The following pseudo code demonstrates this in the make believe world where a standard array can use objects as keys.
class SubObject1{}
class SubObject2{}
class MainObject{
private $subObject1, $subObject2, $theString;
public function __construct(SubObject1 $subObject1, SubObject2 $subObject2, string $theString):MainObject {
$this->subObject1=$subObject1;
$this->subObject2=$subObject2;
$this->theString=$theString;
}
}
class ObjectCollection
{
private $map=[];
public function getObject(SubObject1 $subObject1, SubObject2 $subObject2, string $theString):MainObject {
if(isset($this->map[$subObject1][$subObject2][$theString])) {
$mainObject=$this->map[$subObject1][$subObject2][$theString];
}
else {
$mainObject=new MainObject($subObject1, $subObject2, $theString);
$this->map[$subObject1][$subObject2][$theString]=$mainObject;
}
return $mainObject;
}
}
$objectCollection=new ObjectCollection();
$subObject1_1=new SubObject1();
$subObject1_2=new SubObject1();
$subObject2_1=new SubObject2();
$subObject2_1=new SubObject2();
$o=$objectCollection->getObject($subObject1_1, $subObject2_1, 'hello'); //returns a new object
$o=$objectCollection->getObject($subObject1_2, $subObject2_1, 'hello'); //returns a new object
$o=$objectCollection->getObject($subObject1_1, $subObject2_1, 'goodby'); //returns a new object
$o=$objectCollection->getObject($subObject1_1, $subObject2_1, 'hello'); //returns existing object
How should this be best implemented?
One possibility is something like the following untested code, however, it is a little verbose and am interested if there is a cleaner solution.
public function getObject(SubObject1 $subObject1, SubObject2 $subObject2, string $theString):MainObject {
if(isset($this->map[$theString])) {
if($this->map[$theString]->contains($subObject1)) {
$subObject1Storage=$this->map[$theString][$subObject1];
if($subObject1Storage->contains($subObject2)) {
$mainObject=$subObject1Storage[$subObject2];
}
else {
$mainObject=new MainObject($subObject1, $subObject2, $theString);
$subObject1Storage[$subObject2]=$mainObject;
}
}
else {
$subObject1Storage = new \SplObjectStorage();
$this->map[$theString][$subObject1]=$subObject1Storage;
$mainObject=new MainObject($subObject1, $subObject2, $theString);
$subObject1Storage[$subObject2]=$mainObject;
}
}
else {
$this->map[$theString] = new \SplObjectStorage();
$subObject1Storage = new \SplObjectStorage();
$this->map[$theString][$subObject1]=$subObject1Storage;
$mainObject=new MainObject($subObject1, $subObject2, $theString);
$subObject1Storage[$subObject2]=$mainObject;
}
return $mainObject;
}
The logic I had in mind was as follows:
A factory(or abstract factory in case of too many objects) will take care of creating the object itself.
A container will map unique identifiers with objects created by the factory.
And can retrieve objects based on those identifiers.
That's the easy part, the custom part should be even easier, you can add your own methods to do whatever magic you need with aliases and such.
namespace Example;
/**
* Class ObjectFactory
*
* #package Example
*/
class ObjectFactory {
/**
* This is obviosuly not ideal but it can work
* with a limited amount of objects. Otherwise use an
* abstract factory and let each instance take care of a few
* related objects
*
* #param string $objectAlias
*
* #throws \Exception
*/
public function make(string $objectAlias) {
switch($objectAlias) {
case 'object_unique_id_1':
try{
$instance = new $objectAlias;
}catch (\Exception $exception) {
// log or whatever and rethrow
throw new \Exception("Invalid class? maybe, I dunno");
}
// return $instance
// etc
}
}
}
You can also use Reflection here to recursively get the arguments for the object and dump new instances of the object in the current object based on the arguments in the construct esentially make your own little DI container.
But if you want to keep your sanity use something like Pimple.
Container:
<?php
namespace Example;
/**
* Class Container
*
* #package Example
*/
class Container {
/**
* #var array
*/
private $map = [];
/**
* #param $objectAlias
* #param $objectInstance
*
* #throws \Exception
*/
public function set($objectAlias, $objectInstance) {
// You can use a try catch here, I chose not to
if(isset($this->map[$objectAlias])) {
throw new \Exception("Already exists");
}
$this->map[$objectAlias] = $objectInstance;
}
/**
* #param $objectAlias
*
* #return bool|mixed
*/
public function get($objectAlias) {
if(isset($this->map[$objectAlias])) {
return $this->map[$objectAlias];
}
return false;
}
}
Specific container which will hold your own methods
<?php
namespace Example;
/**
* Class ContainerHashMapThingy
*
* #package Example
*/
class ContainerHashMapThingy extends Container {
// Your methods go here
}
And an example object:
<?php
namespace Example;
/**
* Class ExampleObject1
*
* #package Example
*/
class ExampleObject1 {
/**
* #return string
*/
public function alias() {
// This is just for example sake
// You can just as well have a config, another class to map them or not map them at all
return 'example_object_1';
}
}
And an actual example
<?php
$factory = new \Example\ObjectFactory();
$container = new \Example\Container();
$objectOne = $factory->make('example_object_1');
$container->set('first_object', $objectOne);
The idea here is to give you a clean slate for a container + factory.
If you extend the container you can implement your own methods, remove stuff from the map array, even rewrite the set method to suit your own needs.
While this is not a complete answer it's very hard to give one since, as I said, your needs may vary.
I do hope this gets you on the right track.
In our application, we use repositories for models that are fetched from the database. So, we have an abstract repository that knows about the database, has a loadById method to load a database record and an abstract getEntity method that creates an object for that specific repository. Example code:
abstract class EntityRepository {
/**
* #param int $id
* #return AbstractEntity
*/
public function loadById($id) {
$record = $this->db->loadById($id);
$entity = $this->getEntity();
return $this->inflate($record, $entity);
}
/**
* #return AbstractEntity
*/
protected abstract function getEntity();
}
class PeopleRepository extends EntityRepository {
protected function getEntity() {
return new PeopleEntity();
}
}
abstract class AbstractEntity {
private $id;
/**
* #return int
*/
public function getId() {
return $this->id;
}
/**
* #param int $id;
*/
public function setId($id) {
$this->id = $id;
}
}
class PeopleEntity extends AbstractEntity {
private $name;
/**
* #return string
*/
public function getName() {
return $this->name;
}
/**
* #param string $name;
*/
public function setName($name) {
$this->name= $name;
}
}
When using an instance of PeopleRepository and fetching a model through loadById, PhpStorm is not able to resolve the returned model to a concrete type, but provides only code completion for the functions of AbstractEntity. Is there any simple way to make it work?
In https://confluence.jetbrains.com/display/PhpStorm/PhpStorm+Advanced+Metadata, I've only found ways to make it work for concrete classes and their functions. So, enumerating all repository classes and all their ways of creating an entity might work. But I'd love to see an abstract way of defining like "All instances of EntityRepository will return an entity of that type defined in getEntity() when loading an entity"
I doubt there's a blanket way of doing this. Even using PHPStorm meta you have to be explicit for each case. Perhaps the way of doing this is by doing something like adding a repository facade e.g.
class RepositoryFacade {
public static function __callStatic($method, $args) {
if ($args[0] == People::class) {
array_shift($args);
return new PeopleRepository()->{$method}(...$args);
}
}
}
Then you might be able to typehint this using:
override(RepositoryFacade::loadById(0), type(0));
Of course the facade is not really the best pattern to be using in general so I can see how this might not be ideal.
I'm looking for a way to extend my Symfony2 (i currently use 2.3) Entity class with a method to effectively filter its relations on demand. So, imaging i have such 2 classes with OneToMany relation:
/**
* ME\MyBundle\Entity\Kindergarten
*/
class Kindergarten
{
/**
* #var integer $id
*/
private $id;
/**
* #var ME\MyBundle\Entity\Kinder
*/
private $kinders;
public function __construct()
{
$this->kinders = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get kinders
*
* #return Doctrine\Common\Collections\Collection
*/
public function getKinders()
{
return $this->kinders;
}
}
/**
* ME\MyBundle\Entity\Kinder
*/
class Kinder
{
/**
* #var integer $id
*/
private $id;
/**
* #var string $name
*/
private $name;
/**
* #var integer $age
*/
private $age;
}
My goal is to have a method on Kindergarten class to get on demand all kinders with age, for instance, between 10 and 12:
$myKindergarten->getKindersByAgeInInterval(10,12);
Of course, i can do something like:
class Kindergarten
{
...
public function getKindersByAgeInInterval($start, $end)
{
return $this->getKinders()->filter(
function($kinder) use ($start, $end)
{
$kinderAge = $kinder->getAge();
if($kinderAge < $start || $kinderAge > $end)
{
return false;
}
return true;
}
);
}
...
}
The solution above will work, but it's very inefficient, since I need to iterate across ALL kinders which can be a really big list and have no way to cache such filters. I have in mind usage of Criteria class or some proxy patterns, but not sure about a way to do it nice in Symfony2 especially since they probably will need access to EntityManager.
Any ideas?
I would suggest extracting this responsibility into an EntityRepository:
<?php
class KinderRepository extends \Doctrine\ORM\EntityRepository
{
public function findByKindergartenAndAge(Kindergarten $entity, $minAge = 10, $maxAge = 20)
{
return $this->createQueryBuilder()
->... // your query logic here
}
}
All the lookups should really happen in classes where you have access to the entity manager.
This is actually the way suggested by the Doctrine architecture. You can never have access to any services from your entities, and if you ever think you need it, well, then something is wrong with your architecture.
Of course, it may occur to you that the repository method could become pretty ugly if you later decide on adding more criteria (imagine you'll be searching by kindergarten, age, weight and height too, see http://www.whitewashing.de/2013/03/04/doctrine_repositories.html). Then you should consider implementing more logic, but again, that should not be that necessary.
I'm using the composite pattern to have reusable elements to build a page. for this i have a simple interface which drives the pattern
interface Ai1ec_Renderable {
/**
* This is the main function, it just renders the method for the element,
* taking care of childrens ( if any )
*/
public function render();
}
Since only some of the elements will be allowed to have children, i have created an abstract class that adds that behaviour
abstract class Ai1ec_Can_Have_Children {
/**
*
* #var array
*/
protected $renderables = array();
/**
* Adds a renderable child to the element
*
* #param Ai1ec_Renderable $renderable
*/
public function add_renderable_children( Ai1ec_Renderable $renderable ) {
$this->renderables[] = $renderable;
}
}
so if the object can have children it extends the abstract class. The problem arise because i have a second abstract class for html elements
abstract class Ai1ec_Html_Element {
/**
*
* #var string
*/
protected $id;
/**
*
* #var array
*/
protected $classes = array();
/**
*
* #param $id string
*/
public function set_id( $id ) {
$this->id = $id;
}
public function add_class( $class ) {
$this->classes[] = $class;
}
protected function create_class_markup() {
if (empty( $this->classes )) {
return '';
}
$classes = implode( ' ', $this->classes );
return "class='$classes'";
}
protected function create_attribute_markup(
$attribute_name,
$attribute_value
) {
if (empty( $attribute_value )) {
return '';
}
return "$attribute_name='$attribute_value'";
}
}
The problem is that all the objects of the composite must implement the interface, some of them must extend only the first class ( can_have_children ) but not the second ( this is because they are higher level abstraction that configure another renderable object to do the job ), some of them the second but not the first and some of them both classes.
Have i done somthing wrong while designing my classes?How do i come out of it? The most obvious way is to make a class duplicating some code
abstract class Ai1ec_Can_Have_Children extends Ai1ec_Html_Element {
/**
*
* #var array
*/
protected $renderables = array();
/**
* Adds a renderable child to the element
*
* #param Ai1ec_Renderable $renderable
*/
public function add_renderable_children( Ai1ec_Renderable $renderable ) {
$this->renderables[] = $renderable;
}
}
this would work, but it's a smell that something is not right, as i would need to duplicate code if i add something to Can_Have_Children. What should i do?
P.S. No traits, i support 5.2
It seems there are two major responsibilities here: rendering and having children. So I would start with two separate interfaces:
interface Renderable {
public function render();
}
interface Container {
public function addChild(Renderable $renderable);
}
Then have a concrete implementation of Container (not abstract):
class BasicContainer implements Container, Renderable {
/* similar to your Ai1ec_Can_Have_Children class */
}
Then you can define your HTML element classes as follows, using composition instead of inheritance for adding container functionality:
abstract class HtmlElement implements Renderable {
/* similar to your Ai1ec_Html_Element class */
}
abstract class ContainerHtmlElement extends HtmlElement implements Container {
private $container = new BasicContainer();
public function addChild(Renderable $renderable) {
$this->container->addChild($renderable);
}
public function render() {
parent::render();
$this->container->render();
}
}
Two important Design Pattern principles can be found here:
Program to an interface and not an implementation
Favor object composition over inheritance
If you look at the original class diagram in the GoF book, you'll see that the Component interface has two implementations: Leaf and Composite. The Leaf participant only implements the Operation() and none of the others. For example, consider the following:
<?php
class Leaf implements IComponent
{
private $sName;
public function __construct($sNodeName)
{
$this->sName=$sNodeName;
}
/* None of this batch of methods are used by Leaf */
/* However in order to correctly implement the interface */
/* you need some kind of implementation */
public function add(IComponent $comOn){}
public function remove(IComponent $comGone){}
public function getChild($someInt){}
/* Some userful content is required for the operation */
public function operation()
{
echo $this->sName . "<br />";
}
}
?>
So while the Leaf participant in the pattern only implements the operation() method, it has dummy implementations of the other interface methods. You can find more details at:
http://www.php5dp.com/the-composite-design-pattern-in-php-part-i-from-conceptual-to-practical/
and
http://www.php5dp.com/category/design-patterns/composite/
The Composite is one of the few where you'll find this kind of "one-wing" implementation.
Is it possible to get the base object from derived object in php
Something like this
class base {}
class derived extends base{
public function getBase()
{
return (base)$this;
}
The above code, throws out a error
You can use parent:: to resolve to a parent method, property or constant.
If you're trying to get the name of the base class, here's a way to do that:
class base {
public function getClassName() {
return "base";
}
}
class derived extends base{
public function getBaseClassName() {
return parent::getClassName();
}
public function getClassName() {
return "derived";
}
}
$d = new derived();
echo $d->getBaseClassName();
Edit: When you use inheritance to extend a class (eg: derived extends base), you are saying that derived is a kind of base, and all instances of derived are also instances of base. In most OO languages, the two instances, base and derived are not separate entities, and they can not be treated separately. (C++ is an exception to the rule in this regard).
If you need to treat the instances separately, then inheritance is the wrong tool for the job. Use extension by containment, rather than inheritance. This will look something like the following:
class base {
public someBaseFunction() {
// ...
}
}
class derived {
/**
* each instance of `derived` *contains* an in instance of `base`
* that instance will be stored in this protected property
*/
protected $base;
/**
* constructor
*/
function __construct() {
// remember to call base's constructor
// passing along whatever parameters (if any) are needed
$this->base = new base();
// ... now do your constructor logic, if any ...
}
/**
* Here's the method that fetches the contained
* instance of `base`
*/
public function getBase() {
return $this->base;
}
/**
* If needed, `derived` can implement public elements
* from `base`'s interface. The logic can either delegate
* directly to the contained instance of base, or it can
* do something specific to `derived`, thus "overriding"
* `base`'s implementation.
*/
public function someBaseFunction() {
return $this->base->someBaseFunction();
}
/**
* of course, `derived` can implement its own public
* interface as well...
*/
public function someOtherFunction() {
}
}