Polymorphism/Resource loader with Zend - php

I've never worked before with polymorphism. I just heard about it when this question came up.
I have a little backend with 2 permissions. Admin/Normal User. Depending on the permission, i want to display a different navigation, less or more options on the forms etc. But i don't want to create a form for each permission but rather disable the elements i don't need etc.
How would i go with that?
At the moment, i'm using something like that: (Which isn't really polymorphism)
<?php
class My_Resources_ResourceLoader extends Zend_Application_Resource_ResourceAbstract {
public $templateForm = null;
public $customerForm = null;
function init() {
$permission = 'admind';
if($permission == 'admin') {
$this->templateForm = new Application_Form_newTemplate;
} else {
$form = new Application_Form_newTemplate;
$form->removeElement('newTemplate_customer');
$this->templateForm = $form;
}
return $this;
}
}
And in my controller e.g.
<?php
$bootstrap = $this->getInvokeArg('bootstrap');
$xx = $bootstrap->getResource('ResourceLoader');
$this->view->test = $xx->templateForm;
The roles never gonna change. This will probably be okay but isn't the very best solution. What would be a better approach to this?

I've thrown away the approach above and now use real polymorphism like this:
at Application/Model got an interface like:
And 2 Classes like:
<?php
class Application_Model_TemplateUser implements Application_Model_TemplateInterface {
private $table = null;
private $row = null;
private $id = null;
private $formValues = null;
function __construct() {}
public function exist() {}
public function save() {}
public function getCustomerId($name) {}
public function update() {}
public function getForm() {
$form = new Application_Form_newTemplate;
$form->removeElement('newTemplate_customer');
return $form;
}
}
And
<?php
class Application_Model_TemplateAdmin implements Application_Model_TemplateInterface {
private $table = null;
private $row = null;
private $id = null;
private $formValues = null;
function __construct() {}
public function exist() {}
public function save() {}
public function getCustomerId($name) {}
public function update() {}
public function getForm() {
return new Application_Form_NewTemplate();
}
}
In my Controller i do:
<?php
$permission = 'User'; //TODO: Get from Session
$class = 'Application_Model_Template' . $permission;
$xx = new $class;
$form = $xx->getForm();
$this->view->test = $form;
This are just examples. But i think like that I'm really on a better way. Maybe i'm going to use abstract classes since i'm using Zend_Db-Table_Row, which is always the same for updating a row, so it would make more sense using a abstract class instead of an interface.
Nice article about Polymorphism in PHP: http://net.tutsplus.com/tutorials/php/understanding-and-applying-polymorphism-in-php/

Related

Accessing variables from constructors in static methods

I have a class with methods, some of these methods use the same variable across board - "$company_id". Now, I don't want to explicitly define what is contained in $company_id for every method. I want to define it once in a constructor and then reference it in my methods. Please how do I do this? This is how it looks currently.
public function __construct(){
//what should I do here?
}
public static function getItemLimit(){
$company_id = Auth::user()->company_id;
$item_limit = Company::where('id', $company_id)->count();
return $item_limit;
}
public static function currentItemCount(){
$company_id = Auth::user()->company_id;
$item_count = Item::where('company_id', $company_id)->count();
return $item_count;
}
Try this Use Company_Id instead of $abcVar
class Abc{
public static $abcVar = '';
public function __construct()
{
self::$abcVar = 11;
}
public static function getItemLimit()
{
echo self::$abcVar;
exit;
}
}
$obj = new Abc();
Abc::getItemLimit();

Creating a static array without changing thousands of lines of code

We have a class that holds a public array called $saved that contains lots of data required to share between methods (example below)...
class Common {
public $saved = array();
public function setUser($data) {
$this->saved['user_data'] = $data;
}
public function getUserID() {
return $this->saved['user_data']['id'];
}
}
There are literally thousands of lines of code that work like this.
The problem is that new instance of classes that extend Common are being made within some methods so when they access $saved it does not hold the same data.
The solution is to make $saved a static variable, however I can't change all of the references to $this->saved so I want to try and keep the code identical but make it act static.
Here is my attempt to make $this->saved calls static...
class PropertyTest {
private $data = array();
public function __set($name, $value) {
$this->data[$name] = $value;
}
public function __get($name) {
if (array_key_exists($name, $this->data)) {
return $this->data[$name];
}
return null;
}
public function __isset($name) {
return isset($this->data[$name]);
}
public function __unset($name) {
unset($this->data[$name]);
}
}
class Common {
public $saved;
private static $_instance;
public function __construct() {
$this->saved = self::getInstance();
}
public static function getInstance() {
if (self::$_instance === null) {
self::$_instance = new PropertyTest();
self::$_instance->foo = array();
}
return self::$_instance->foo;
}
}
This doesn't quite work when setting a variable it doesn't seem to stay static (test case below)...
class Template extends Common {
public function __construct() {
parent::__construct();
$this->saved['user_data'] = array('name' => 'bob');
$user = new User();
}
}
class User extends Common {
public function __construct() {
parent::__construct();
$this->saved['user_data']['name'] .= " rocks!";
$this->saved['user_data']['id'] = array(400, 10, 20);
}
}
$tpl = new Template();
print_r($tpl->saved['user_data']);
$this->saved is empty when User gets initialized and doesn't seem to be the same variable, the final print_r only shows an array of name => bob.
Any ideas?
First of all, I have to say that, IMO, it is not that good to use an instance's property as a class's property ($saved is not declared as static but its value is shared with all instance).
Here is a working version http://codepad.org/8hj1MOCT, and here is the commented code. Basically, the trick is located in using both ArrayAccess interface and the singleton pattern.
class Accumulator implements ArrayAccess {
private $container = array();
private static $instance = null;
private function __construct() {
}
public function getInstance() {
if( self::$instance === null ) {
self::$instance = new self();
}
return self::$instance;
}
public function offsetSet($offset, $value) {
if (is_null($offset)) {
$this->container[] = $value;
} else {
$this->container[$offset] = $value;
}
}
public function offsetExists($offset) {
return isset($this->container[$offset]);
}
public function offsetUnset($offset) {
unset($this->container[$offset]);
}
public function offsetGet($offset) {
return isset($this->container[$offset]) ? $this->container[$offset] : null;
}
}
class Common {
public $saved = null;
public function __construct() {
// initialize the "saved" object's property with the singleton
// that variable can be used with the array syntax thanks to the ArrayAccess interface
// so you won't have to modify your actual code
// but also, since it's an object, this local "$this->saved" is a reference to the singleton object
// so any change made to "$this->saved" is in reality made into the Accumulator::$instance variable
$this->saved = Accumulator::getInstance();
}
public function setUser($data) {
$this->saved['user_data'] = $data;
}
public function getUser() {
return $this->saved['user_data'];
}
}
class Template extends Common {
// you can redeclare the variable or not. Since the property is inherited, IMO you should not redeclare it, but it works in both cases
// public $saved = null;
public function __construct() {
// maybe we can move this initialization in a method in the parent class and call that method here
$this->saved = Accumulator::getInstance();
}
}
I think there are a number of issues with this implementation that could well come back to bite you. However, in your current implementation your contructing a new instance (albeit through a static call) every time.
Instead use getInstance() as your singleton hook, and make your __construct private, as you'll only be accessing it from with the context of the Common class.
Like so:
class Common {
public $saved;
private static $_instance;
private function __construct() {
}
public static function getInstance() {
if (self::$_instance === null) {
self::$_instance = new self();
... any other modifications you want to make ....
}
return self::$_instance;
}
}
And don't ever run parent::_construct(), instead always use the getInstance() method.
You might also want to ditch the idea of extending this singleton class. This is really a bad antipattern and could cost you a number of issues in the long run. Instead just maintain a Common class that other classes can read / write to. As its a singleton you don't need to worry about injection.
I seem to have solved the problem, by making $this->saved a reference to a static variable it works...
class Common {
private static $savedData = array();
public $saved;
public function __construct() {
$this->saved =& self::$savedData;
}
}

Class function only available to "parent" - PHP

I want to create a function in a class that is available for a set of users, but that they won't be able to access. Ex:
class Stuff_for_user {
private $errors;
/*
* private $errors gets modified by private functions
*/
public function get_errors(){ // This is for users to display errors.
return $this->errors;
}
/*something here...*/ function set_errors($str){
$this->errors = $str;
}
}
So far so good, but now I want the parent class to be able to set Stuff_for_User's errors:
class Main_mess {
public index(){
$user_available_data = new Stuff_for_user();
if($big_error)
$user_available_data->set_errors("BIG ERROR!!!");
$this->send_to_users($user_available_data);
}
}
I want only Main_mess to be able to access Stuff_for_User's set_errors() method. Is that possible?
No, that is not possible like that, since Main_mess is not a parent class of Stuff_for_users (and this is probably what you want, looking at what your code actually does). So set_errors has to be public if you want to call it from the outside.
This is not possible how you want to implement it.
Some ideas (i dont know why or how you want to do that but just ideas...):
do set_error($str,$access_key) and let $access_key be an access string only you know!
let Stuff_for_user be in Extended_Stuff_for_user which has the set_error function like:
class Extended_Stuff_for_user {
private $errors;
private $Stuff_for_user;
public function set_errors() {
/* ... */
}
public function getStuffForUser() {
return $this->Stuff_for_user;
}
}
It seems that you are looking for implementation of something called friend class in php. Well .. i'm sorry to tell you this, but it is not possible.
You should look at other possible solutions to your problem.
class SecureContainer{
protected $user = null;
protected $target = null;
public function __construct( $target, $user )
{
$this->target = $target;
$this->user = $user;
}
public function __call( $method, $arguments )
{
if ( $this->user->isAllowed(getType( $this->target ), $method))
{
return call_user_func_array(
array( $this->target, $method), $arguments );
}
}
}
Use it like this:
$something = new UnsecureSomething;
$user = new User( $uid );
$something = new SecureContainer( $something, $user );
This should let you control the access to methods.
Yes it possible but it can be dirty.
Like This.
class Stuff_for_user {
private $errors;
/*
* private $errors gets modified by private functions
*/
public function get_errors(){ // This is for users to display errors.
return $this->errors;
}
/*
This way the child classes of Main will able be to use the set_errors function;
*/
function set_errors($class,$str){
if($class instanceof Main_mess)
{
$this->errors = $str;
}
/*
AndThis way the only Main_mess will be able;
*/
function set_errors($class,$str){
if(get_class($class)=="Main_mess")
{
$this->errors = $str;
}
}
class Main_mess {
public index(){
$user_available_data = new Stuff_for_user();
if($big_error)
$user_available_data->set_errors($this,"BIG ERROR!!!");
$this->send_to_users($user_available_data);
}
}

How can I avoid repeating variables?

In the following code, I have to use $module = $this->uri->segment(4);, table = "omc_".$module; and $id = $this->uri->segment(5); in every function in this class.
How can I avoiding this repetition?
Thanks in advance.
class Admin extends Shop_Admin_Controller {
function Admin(){
parent::Shop_Admin_Controller();
}
function changeStatus(){
$module = $this->uri->segment(4);
$table = "omc_".$module;
$id = $this->uri->segment(5);
if($id && $table){
$this->MKaimonokago->changeStatus($table,$id);
}
flashMsg('success',$this->lang->line('kaimonokago_status_changed'));
redirect("$module/admin/index/","refresh");
}
.................
.................
You could simply add then as instance (i.e.: class level) variables with the appropriate visibility (protected or private) and then initialise them within your constructor.
By doing this you wouldn't need to initialise them within each method, and would still have a more convenient naming regime.
For example:
class Admin extends Shop_Admin_Controller {
private $module;
private $table;
private $id;
public function __construct() {
parent::__construct();
// Initialise uri class here, unless this is done
// in the parent constructor.
$this->module = $this->uri->segment(4);
$this->table = "omc_".$module;
$this->id = $this->uri->segment(5);
}
public function changeStatus() {
if($this->id && $this->table) {
...
}
}
}
Incidentally, I'd also recommend setting the appropriate visibility on your methods, unless of course you're targeting PHP 4, in which case replace the "private" with "var" in the above example and remove the visibility properties from the methods.
How about setting them in the constructor?
function Admin(){
parent::Shop_Admin_Controller();
$this->module = $this->uri->segment(4);
$this->table = "omc_" . $this->module;
$this->id = $this->uri->segment(5);
}
They can then be used as e.g. $this->module in the other functions in your class.
This of course presumes that you don't have properties with those names in the parent class. If you do, you use different names.
Maybe set them as protected attributes in your constructor?
class Admin
{
protected $_module;
protected $_table;
protected $_id;
public function __construct()
{
// do something that initializes $this->uri;
$this->_module = $this->uri->segment(4);
$this->_table = 'omc_' . $module;
$this->_id = $this->uri->segment(5);
}
}

workaround for multiple inheritances in PHP?

In a lot of my PHP classes, I have this code:
private $strError = "";
private $intErrorCode = NULL;
private $blnError = FALSE;
public function isError() {
return $this->blnError;
}
public function getErrorCode() {
return $this->intErrorCode;
}
private function setError( $strError, $intErrorCode = NULL ) {
$this->blnError = TRUE;
$this->intErrorCode = $intErrorCode;
$this->strError = $strError;
}
The point is so that outside code can know if an object has an error state, what the string of the error is, etc. But to have this exact code in a bunch of different classes is repetitious!
I'd love to have a dual-extension where I could do
class childClass extends parentClass, error {
...
}
And have those properties and methods inborn, But PHP doesn't support multiple inheritances. What I'm thinking about doing is creating an error class that exists inside each class. If I make it public, I can call it directly through the object
if ( $myObject->error->isError() ) {...}
but wouldn't that also make its error status settable from outside the containing class,
$myObject->error->setError("I shouldn't be doing this here");
which I would rather avoid?
Or I could write 'gateway' functions in the containing class, which do the appropriate calls on the error object, and prevent setting the error status from outside,
class childClass extends parentClass {
private $error;
public function __construct(...) {
...
$error = & new error();
...
}
public function isError() {...}
public function getError() {...}
public function getErrorCode() {...}
private function setError() {...}
...
}
but that leads to (some of) the code duplication that I'm trying to avoid.
What's the optimal solution here? I'm trying to have functionality for error statuses for a number of objects, so that the outside world can see their error state, with minimal repetition.
Use composition instead of inheritance.
class Errors {
private $strError = "";
private $intErrorCode = NULL;
private $blnError = FALSE;
public function isError() {
return $this->blnError;
}
public function getErrorCode() {
return $this->intErrorCode;
}
private function setError( $strError, $intErrorCode = NULL ) {
$this->blnError = TRUE;
$this->intErrorCode = $intErrorCode;
$this->strError = $strError;
}
}
And now use a private instance variable to refer to it:
class childClass extends parentClass {
private $errors = new Errors();
...
}
The private visibility prevents you from referencing $errors outside of the class.
There's also no need to create isError(), getError(), etc. inside childClass (and therefore no need to worry about code duplication). Simply call $this->errors->isError(), $this->errors->getError(), etc. If you still wanted to require those methods to be implemented though, as suggested below, you could specify an interface.
You could also abuse the __call magic method to do the same thing:
public function __call($name, array $arguments) {
$name = strtolower($name);
if (isset($this->methods[$name])) {
array_unshift($arguments, $this);
return call_user_func_array($this->methods[$name], $arguments);
}
throw new BadMethodCallException('Method does not exist');
}
Note that I said abuse... Ideally, I'd think of a different architecture rather than having all these "common methods" everywhere. Why not use an exception instead of checking $foo->isError? If that's not appropriate, why not decorate a class?
class Errors
protected $object = null;
public function __construct($object) {
$this->object = $object;
}
public function __call($method, array $arguments) {
$callback = array($this->object, $method);
if (is_callable($callback)) {
return call_user_func_array($callback, $arguments);
}
throw new BadMethodCallException('Method does not exist');
}
public function __get($name) { return $this->object->$name; }
public function __set($name, $value) { $this->object->$name = $value; }
// Your methods here
public function isInstance($name) { return $this->object instanceof $name; }
}
Then just "wrap" your existing object in that class:
$obj = new Errors($obj);
$obj->foo();
As of PHP 5.4, you can use Traits.
For example you could make Trait called ErrorTrait like this:
trait ErrorTrait {
private $strError = "";
private $intErrorCode = NULL;
private $blnError = FALSE;
public function isError() {
return $this->blnError;
}
public function getErrorCode() {
return $this->intErrorCode;
}
private function setError( $strError, $intErrorCode = NULL ) {
$this->blnError = TRUE;
$this->intErrorCode = $intErrorCode;
$this->strError = $strError;
}
}
Then you would define your child class like this:
class childClass extends parentClass {
use ErrorTrait;
...
}
Traits work basically like copy/paste so all of the code in the trait would be available within the class (without the code duplication).

Categories