time-tracking/lib/class/helpable.php

248 lines
6.2 KiB
PHP

<?php
/**
* Tzn Framework
*
* @package tzn_core_classes
* @author Stan Ozier <framework@tirzen.com>
* @version 0.2
* @copyright GNU Lesser General Public License (LGPL) version 3
*/
/**
* Helpable
*
* add possibility to have helpers, and call helper method if it doesn't exist
* @since 0.1
*/
abstract class Helpable {
protected $_helpers;
public function __construct() {
$this->_helpers = array();
}
/**
* add helper to the class
* @param string $helper name of helper (flat format)
* @param object $obj object to be passed on
*/
public function addHelper() {
$args = func_get_args();
// helper's name
$helper = array_shift($args);
$class = StringHelper::flatToCamel($helper, true).'Helper';
// reference to this object
$obj = array_shift($args);
if (is_null($obj)) {
$obj = $this;
}
// add helper (didn't find any better way to deal with variable constructor parameters)
switch(count($args)) {
case 4:
$this->_helpers[$helper] = new $class($obj, $args[0], $args[1], $args[2], $args[3]);
break;
case 3:
$this->_helpers[$helper] = new $class($obj, $args[0], $args[1], $args[2]);
break;
case 2:
$this->_helpers[$helper] = new $class($obj, $args[0], $args[1]);
break;
case 1:
$this->_helpers[$helper] = new $class($obj, $args[0]);
break;
default:
$this->_helpers[$helper] = new $class($obj);
break;
}
}
/**
* call helper method
* @param string $key the helper key
* @param string $method the method to be called
*/
public function callHelper() {
$args = func_get_args();
$helper = array_shift($args);
$method = array_shift($args);
return call_user_func_array(array($this->_helpers[$helper], $method), $args);
}
/**
* call helper's method (arguments are passed as an array
*/
public function callHelperArray() {
$args = func_get_args();
$helper = array_shift($args);
$method = array_shift($args);
if (!empty($args)) {
return call_user_func_array(array($this->_helpers[$helper], $method), $args[0]);
} else {
return $this->_helpers[$helper]->$method();
}
}
/**
* call all available helpers method
* @param string $method the method to be called
*/
protected function callHelpers($method) {
if (!count($this->_helpers)) {
return false;
}
$arr = array();
$args = func_get_args();
$method = array_shift($args);
foreach ($this->_helpers as $key => $obj) {
if (!method_exists($obj, $method)) {
continue;
}
$r = call_user_func_array(array($obj,$method),$args);
$arr[$key] = $r;
}
return $arr;
}
/**
* check if helper is available
*/
public function hasHelper($helper) {
return array_key_exists($helper, $this->_helpers);
}
/**
* get helper
*/
public function &getHelper($helper) {
if ($this->hasHelper($helper)) {
return $this->_helpers[$helper];
} else {
throw new AppException('Unknown helper '.$helper.' in '.get_class($this));
}
}
/**
* call helper method if not defined here
*/
public function __call($name, $args) {
if (!count($this->_helpers)) {
throw new AppException('Unknown method '.$name.' in '.get_class($this).' (and no helper available)');
}
// check if helper's name has been added to method's name eg. methodHelper
/* TOO UGLY, TOO COSTY
$subname = StringHelper::camelToFlat($name);
if ($idx = strrpos($subname, '__')) {
$subhelp = substr($subname, $idx+1);
if (array_key_exists($subhelp, $this->_helpers)) {
$subname = StringHelper::flatToCamel(substr($subname, 0, $idx));
$obj = $this->_helpers[$subhelp];
if (method_exists($obj, $name)) {
return call_user_func_array(array($obj, $name), $args);
}
}
}
*/
// check if method exists in one of the helper
foreach ($this->_helpers as $key => $obj) {
if (method_exists($obj, $name)) {
return call_user_func_array(array($obj, $name), $args);
}
}
// try again within helper if __call is available
foreach ($this->_helpers as $key => $obj) {
if (method_exists($obj, '__call')) {
return call_user_func_array(array($obj, $name), $args);
}
}
// nope, forget it
throw new AppException('Unknown method '.$name.' in '.get_class($this).' or any helper ('.implode(', ',array_keys($this->_helpers)).')');
}
}
/**
* Singleton helpable super class
*
* sucks duplicating code, but needed for singletons as constructor must be private
* @since 0.1
*/
abstract class HelpableSingleton {
private $_helpers;
private function __construct() {
$this->_helpers = array();
}
/**
* add helper to the class
*/
protected function addHelper($helper, $obj=null) {
$class = StringHelper::flatToCamel($helper, true).'Helper';
$this->_helpers[$helper] = new $class($obj);
}
/**
* check if helper is available
*/
public function hasHelper($helper) {
return array_key_exists($helper, $this->_helpers);
}
/**
* get helper
*/
public function &getHelper($helper) {
if ($this->hasHelper($helper)) {
return $this->_helpers[$helper];
} else {
throw new AppException('Unknown helper '.$helper.' in '.get_class($this));
}
}
/**
* call helper method if not defined here
*/
public function __call($name, $args) {
if (!count($this->_helpers)) {
throw new AppException('Unknown method '.$name.' in '.__CLASS__.' (and no helper available)');
}
foreach ($this->_helpers as $key => $obj) {
foreach ($this->_helpers as $key => $obj) {
if (method_exists($obj, $name)) {
return call_user_func_array(array($obj, $name), $args);
}
}
if (is_a($obj, 'Callable2')) {
return call_user_func_array(array($obj, $name), $args);
}
}
throw new AppException('Unknown method '.$name.' in '.__CLASS__.' or any helper ('.implode(', ',array_keys($this->_helpers)).')');
}
}
/**
* Callable interface
*
* class implementing this will be able to send calls to other nested classes
*/
interface Callable2 {
public function __call($name, $args);
/*
public function __call($name, $args) {
$arr = array('class1','class2');
foreach ($arr as $class) {
if (method_exists($this->$class, $name)) {
return call_user_func_array(array($this->$class, $name), $args);
}
}
throw new AppException('Unknown method '.$name.' in '.__CLASS__.', '.implode(', ',$arr));
}
*/
}