<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* This file defines PEAR_Delegator extensions, which are added to any delegator with the addExtensions() method.
*
* @package PEAR_Delegator
* @author Michael Witten <lingwitt@yahoo.com>
* @copyright 2004-2005 Michael Witten
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @link http://pear.php.net/package/PEAR_Delegator
*/
// /* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP Version 5 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2004 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 3.0 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available through the world-wide-web at the following url: |
// | http://www.php.net/license/3_0.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Authors: Michael Witten 4100 85 <LingWitt@yahoo.com> |
// | Martin Jansen <mj@php.net> for overwhelming encouragement |
// +----------------------------------------------------------------------+
// 4100 85
// $Id$
/**
* This class provides a static delegate that adds methods to a PEAR_Delegator instance
*
* @since PHP 5.0.0
* @author Michael Witten <LingWitt@yahoo.com> 4100 85
* @see http://pear.php.net/manual/
* @package PEAR_Delegator
*/
class PEAR_Delegator_Extensions
{
/**
* Determines whether or not the calling object adopts a particular delegate.
*
* This returns the availability of a delegate not including subdelegates.
*
* @see PEAR_Delegator::hasDelegate()
* @param class $specifier This specifies a delegate classname.
* @return bool If the calling object has adopted the specifed classname
*/
public function hasDelegateExact($owner, $specifier = null)
{
if (array_key_exists($specifier, $owner->_delegates)) {
return true;
}
foreach ($owner->_delegates as $delegate) {
if (PEAR_Delegator::is_aExact($delegate, $specifier)) {
return true;
}
}
return false;
}
/**
* Gets the delegate object that is an instance of the specified class.
*
* This method returns classes of the specified type. This does not return
* subdelegates. That is, it uses only the actual class structures.
*
* @see PEAR_Delegator::getAllDelegates(), PEAR_Delegator::getDelegate(),
* PEAR_Delegator_Extensions::getDelegateRecursive(),
* PEAR_Delegator_Extensions::getDelegateRecursiveExact()
* @param class $classname1 This specifies a delegate classname. Any
* number of arguments after this is acceptable.
* @return array <pre> The result is an
* associative array of the form:
* Array
* (
* [classname1] = Array
* (
* delegate11
* delegate12
* ...
* )
* [classnamei] = Array
* (
* delegate1i
* delegate1i
* ...
* )
* ...
* )
* Note: If a single classname is passed, a traditional array with numbered
* elements is returned.
* </pre>
*/
public function getDelegateExact($owner, $classname1)
{
$result = null;
$args = func_get_args();
unset($args[0]);
foreach ($args as $classname) {
foreach ($owner->_delegates as $delegate) {
if (PEAR_Delegator::is_aExact($delegate, $classname)) {
$result[$classname][] = $delegate;
}
}
}
if ($result) {
return (count($args) > 1) ? $result : $result[$classname1];
} else {
return null;
}
}
/**
* Gets the delegates that is of the specified class.
*
* This method returns instances of the specified classname as well as
* child instances of the specified classname, including subdelegates,
* which are anywhere in the delegate hierarchy. This method is provided,
* because it may be useful, but its use is discouraged, as objects should
* logically only have access to their native delegates.
*
* @see PEAR_Delegator::getAllDelegates(), PEAR_Delegator::getDelegate(),
* PEAR_Delegator_Extensions::getDelegateRecursive(),
* PEAR_Delegator_Extensions::getDelegateRecursiveExact()
* @param class $classname1 This specifies a delegate classname. Any
* number of arguments after this is acceptable.
* @return array <pre> The result is an
* associative array of the form:
* Array
* (
* [classname1] = Array
* (
* delegate11
* delegate12
* ...
* )
* [classnamei] = Array
* (
* delegate1i
* delegate1i
* ...
* )
* ...
* )
* Note: If a single classname is passed, a traditional array with numbered
* elements is returned.
* </pre>
*/
public function getDelegateRecursive($owner, $classname1)
{
$args = func_get_args();
unset($args[0]);
$result = array();
foreach ($args as $arg) {
foreach ($owner->_delegates as $delegate) {
if (is_object($delegate) && $delegate instanceof PEAR_Delegator) {
if ($others = $this->getDelegateRecursive($delegate, $arg)) {
$others = array($arg => $others);
$result = array_merge_recursive($result, $others);
$result[$arg][] = $delegate;
continue;
}
}
if (PEAR_Delegator::is_aExact($delegate, $arg)) {
$result[$arg][] = $delegate;
}
}
}
if (count($result)) {
return (count($args) > 1) ? $result : $result[$classname1];
} else {
return null;
}
}
/**
* Gets the delegate that is of the specified class.
*
* This method returns classes of the specified type. This does not return
* subdelegates. This method is provided, because it may be useful, but its
* use is discouraged, as objects should logically only have access to their
* native delegates.
*
* @see PEAR_Delegator::getAllDelegates(), PEAR_Delegator::getDelegate(),
* PEAR_Delegator_Extensions::getDelegateRecursive(),
* PEAR_Delegator_Extensions::getDelegateRecursiveExact()
* @param class $classname1 This specifies a delegate classname. Any
* number of arguments after this is acceptable.
* @return array <pre> The result is an
* associative array of the form:
* Array
* (
* [classname1] = Array
* (
* delegate11
* delegate12
* ...
* )
* [classnamei] = Array
* (
* delegate1i
* delegate1i
* ...
* )
* ...
* )
* Note: If a single classname is passed, a traditional array with numbered
* elements is returned.
* </pre>
*/
public function getDelegateRecursiveExact($owner, $classname1)
{
$result = array();
$args = func_get_args();
unset($args[0]);
foreach ($args as $classname) {
if ($native = $this->getDelegateExact($owner, $classname)) {
$native = array($classname => $native);
$result = array_merge_recursive($result, $native);
continue;
}
foreach ($owner->_delegates as $delegate) {
if (is_object($delegate) && ($delegate instanceof PEAR_Delegator) && ($delegateNative = $this->getDelegateRecursiveExact($delegate, $classname))) {
$delegateNative = array($classname => $delegateNative);
$result = array_merge_recursive($result, $delegateNative);
}
}
}
if (count($result)) {
return (count($args) > 1) ? $result : $result[$classname1];
} else {
return null;
}
}
/**
* Gets the delegate objects that respond to a certain method.
*
* This method returns delegates native to the calling delegator as well
* as delegates of delegate owning delegates (it's recursive). This method is
* provided, because it may be useful, but its use is discouraged, as objects
* should logically only have access to their native delegates.
*
* @see PEAR_Delegator_Extensions::getDelegateForMethodRecursiveExact()
* @uses PEAR_Delegator::method_exists()
* @param string $method1,... This specifies the method for whose responder is searched.
* @return array <pre>The result is an
* associative array of the form:
* Array
* (
* [method1] = Array
* (
* delegate11
* delegate12
* ...
* )
* [methodi] = Array
* (
* delegate1i
* delegate1i
* ...
* )
* ...
* )
* Note: If a single method is passed, a traditional array with numbered
* elements is returned.
* </pre>
*/
public function getDelegateForMethodRecursive($owner, $method1)
{
$result = array();
$args = func_get_args();
unset($args[0]);
foreach ($args as $method) {
foreach ($owner->_delegates as $delegate) {
if (is_object($delegate) && $delegate instanceof PEAR_Delegator) {
if ($others = $this->getDelegateForMethodRecursive($delegate, $method)) {
$result = array_merge_recursive($result, array($method => $others));
$result[$method][] = $delegate;
continue;
}
}
if (PEAR_Delegator::method_exists($delegate, $method)) {
$result[$method][] = $delegate;
}
}
}
if (count($result)) {
return (count($args) > 1) ? $result : $result[$method1];
} else {
return null;
}
}
/**
* Gets the delegate object (native or otherwise) that implements the method in question.
*
* This method returns the delegate in the delegate hierarchy
* which actually implements the method. This method is provided, because it may be useful,
* but its use is discouraged, as objects should logically only have access to their native
* delegates.
*
* @see PEAR_Delegator_Extensions::getDelegateForMethodRecursive()
* @param string $method1,... This specifies the method for whose implementor is searched.
* @return array <pre> An array of the form:
* Array
* (
* [method1] = Array
* (
* delegate11
* delegate12
* ...
* )
* [methodi] = Array
* (
* delegate1i
* delegate1i
* ...
* )
* ...
* )
* Note: If a single method is passed, a traditional array with numbered
* elements is returned.
* </pre>
*/
public function getDelegateForMethodRecursiveExact($owner, $method1)
{
$result = array();
$args = func_get_args();
unset($args[0]);
foreach ($args as $method) {
foreach ($owner->_delegates as $delegate) {
if (PEAR_Delegator::method_existsExact($delegate, $method)) {
$result[$method][] = $delegate;
}
if (is_object($delegate) && $delegate instanceof PEAR_Delegator) {
if ($match = $this->getDelegateForMethodRecursiveExact($delegate, $method)) {
$result = array_merge_recursive($result, array($method => $match));
}
}
}
}
if (count($result)) {
return (count($args) > 1) ? $result : $result[$method1];
} else {
return null;
}
}
/**
* Gets the first native delegate that responds to a certain method.
*
* The method returns the first delegate native to the calling delegator, which can
* respond to each method in question. Moreover, this method returns delegates that
* actually implement methods over those that inherit them from delegates.
*
* @see PEAR_Delegator_Extensions::getDelegateForMethodRecursive(),
* PEAR_Delegator_Extensions::getDelegateForMethodRecursiveExact()
* @uses PEAR_Delegator::method_exists()
* @param string $method,... This specifies the method for whose responder is searched.
* @return array <pre>The result is an
* associative array of the form:
* Array
* (
* [method1] = $delegate
* [methodi] = $delegatei
* ...
* )
* Note: If a single classname is passed, the actual object is returned.
* </pre>
*/
public function getDelegateForMethodFirst($owner, $method)
{
$args = func_get_args();
unset($args[0]);
$delegates = call_user_func_array(array($owner, 'getDelegateForMethod'), $args);
if ($delegates) {
$delegateArrayImplementors = array();
$delegateArrayNonimplementors = array();
if (count($args) > 1) {
foreach ($delegates as $method => $delegateArray) {
foreach ($delegateArray as $delegate) {
if (is_string($delegate) || method_exists($delegate, $method)) {
$delegateArrayImplementors[] = $delegate;
}
else {
$delegateArrayNonimplementors[] = $delegate;
}
}
$delegateArray = array_merge($delegateArrayImplementors, $delegateArrayNonimplementors);
$delegates[$method] = $delegateArray[0];
}
}
else {
foreach ($delegates as $delegate) {
if (is_string($delegate) || method_exists($delegate, $method)) {
$delegateArrayImplementors[] = $delegate;
}
else {
$delegateArrayNonimplementors[] = $delegate;
}
}
$delegates = array_merge($delegateArrayImplementors, $delegateArrayNonimplementors);
$delegates = $delegates[0];
}
}
return $delegates;
}
/**
* Removes the specified delegate recursively
*
* Only exact delegates are removed, as it is otherwise superfluous.
*
* @see PEAR_Delegator::removeAllDelegates(), PEAR_Delegator::removeDelegate()
* @param mixed $specifier,... Specifies the delegate, whose information is
* is to be removed. If it is a string, then it
* adheres to the tests of getDelegateExact(). If it
* is an object, then it searches the for that
* delegate to remove.
* @uses filterMethodMapWithDelegate()
*/
public function removeDelegateRecursiveExact($owner, $specifier)
{
$args = func_get_args();
unset($args[0]);
foreach ($args as $arg) {
foreach ($owner->_delegates as $delegate) {
if (is_object($arg)) {
if ($delegate === $arg) {
unset($owner->_delegates[get_class($delegate)]);
$owner->_method_map = $owner->filterMethodMapWithDelegate($delegate);
}
} else {
if (PEAR_Delegator::is_aExact($delegate, $arg)) {
unset($owner->_delegates[is_string($delegate) ? $delegate : get_class($delegate)]);
$owner->_method_map = $owner->filterMethodMapWithDelegate($delegate);
}
}
if ($delegate instanceof PEAR_Delegator) {
$this->removeDelegateRecursiveExact($delegate, $arg);
}
}
}
}
/**
* Removes an entry from the _method_map array.
*
* This method is for removing entries in the _method_map array.
* it simply tests for the entry for existence and removes it.
*
* This is an internal method.
*
* @see PEAR_Delegator::cacheMethod()
* @param string $method This method must be in lowercase.
* @return bool If entry exists true; false otherwise.
*/
protected function uncacheMethod($owner, $method)
{
$ok = false;
if ($ok = isset($owner->_method_map[$method]))
unset($owner->_method_map[$method]);
return $ok;
}
}
?>