class = get_class($this); // Set up the extensions if($extensions = $this->stat('extensions')) { foreach($extensions as $extension) { $instance = eval("return new $extension;"); $instance->setOwner($this); $this->extension_instances[$instance->class] = $instance; } } if(!isset(Object::$classConstructed[$this->class])) { $this->defineMethods(); Object::$classConstructed[$this->class] = true; } } /** * Returns true if this object "exists", i.e., has a sensible value. * Overload this in subclasses. * For example, an empty DataObject record could return false. */ public function exists() { return true; } /** * Returns true if the given method exists. */ public function hasMethod($methodName) { if(!isset($this->class)) $this->class = get_class($this); if(!isset(Object::$builtInMethods['_set'][$this->class])) $this->buildMethodList(); if(isset(Object::$builtInMethods[$this->class][$methodName])) return true; if(isset(Object::$extraMethods[$this->class][$methodName])) return true; return false; } /** * Calls a method. * Extra methods can be hooked to a class using */ public function __call($methodName, $args) { if(isset(Object::$extraMethods[$this->class][$methodName])) { $config = Object::$extraMethods[$this->class][$methodName]; if(isset($config['parameterName'])) { if(isset($config['arrayIndex'])) $obj = $this->{$config['parameterName']}[$config['arrayIndex']]; else $obj = $this->{$config['parameterName']}; if($obj) { return call_user_func_array(array(&$obj, $methodName), $args); } else { if($this->destroyed) user_error("Attempted to call $methodName on destroyed '$this->class' object", E_USER_ERROR); else user_error("'$this->class' object doesn't have a parameter $config[parameterName]($config[arrayIndex]) to pass control to. Perhaps this object has been mistakenly destroyed?", E_USER_WARNING); } } else if(isset($config['wrap'])) { array_unshift($args, $methodName); return call_user_func_array(array(&$this, $config['wrap']), $args); } else if(isset($config['function'])) { $function = $config['function']; return $function($this, $args); } else if($config['function_str']) { $function = Object::$extraMethods[$this->class][$methodName]['function'] = create_function('$obj, $args', $config['function_str']); return $function($this, $args); } else { user_error("Object::__call() Method '$methodName' in class '$this->class' an invalid format: " . var_export(Object::$extraMethods[$this->class][$methodName],true), E_USER_ERROR); } } else { user_error("Object::__call() Method '$methodName' not found in class '$this->class'", E_USER_ERROR); } } /** * Add the all methods from a given parameter to this object. * This is used for extensions. * @param parameterName The name of the parameter. This parameter must be instanciated with an item of the correct class. * @param arrayIndex If parameterName is an array, this can be an index. If null, we'll assume the value is all that is needed. */ protected function addMethodsFrom($parameterName, $arrayIndex = null) { $obj = isset($arrayIndex) ? $this->{$parameterName}[$arrayIndex] : $this->$parameterName; if(!$obj) user_error("Object::addMethodsFrom: $parameterName/$arrayIndex", E_USER_ERROR); // Hack to fix Fatal error: Call to undefined method stdClass::allMethodNames() if(method_exists($obj, 'allMethodNames')) { $methodNames = $obj->allMethodNames(true); foreach($methodNames as $methodName) { Object::$extraMethods[$this->class][$methodName] = array("parameterName" => $parameterName, "arrayIndex" => $arrayIndex); } } } /** * Add a 'wrapper method'. * For example, Thumbnail($arg, $arg) can be defined to call generateImage("Thumbnail", $arg, $arg) */ protected function addWrapperMethod($methodName, $wrapperMethod) { Object::$extraMethods[$this->class][$methodName] = array("wrap" => $wrapperMethod); } /** * Create a new method * @param methodName The name of the method * @param methodCode The PHP code of the method, in a string. Arguments will be contained * in an array called $args. The object will be $obj, not $this. You won't be able to access * any protected methods; the method is actually contained in an external function. */ protected function createMethod($methodName, $methodCode) { Object::$extraMethods[$this->class][$methodName] = array("function_str" => $methodCode); } /** * Return the names of all the methods on this object. * param includeCustom If set to true, then return custom methods too. */ function allMethodNames($includeCustom = false) { if(!$this->class) $this->class = get_class($this); if(!isset(Object::$builtInMethods['_set'][$this->class])) $this->buildMethodList(); if($includeCustom && isset(Object::$extraMethods[$this->class])) { return array_merge(Object::$builtInMethods[$this->class], array_keys(Object::$extraMethods[$this->class])); } else { return Object::$builtInMethods[$this->class]; } } function buildMethodList() { if(!$this->class) $this->class = get_class($this); $reflection = new ReflectionClass($this->class); $methods = $reflection->getMethods(); foreach($methods as $method) { $name = $method->getName(); $methodNames[$name] = $name; } Object::$builtInMethods[$this->class] = $methodNames; Object::$builtInMethods['_set'][$this->class] = true ; } /** * This constructor will be called the first time an object of this class is created. * You can overload it with methods for setting up the class - for example, extra methods. */ protected function defineMethods() { if($this->extension_instances) foreach($this->extension_instances as $i => $instance) { $this->addMethodsFrom('extension_instances', $i); } if(isset($_REQUEST['debugmethods']) && isset(Object::$builtInMethods[$this->class])) { Debug::require_developer_login(); echo "