* @license http://opensource.org/licenses/lgpl-2.1.php LGPL or MIT-like license. * @see QueryPathExtension * @see QueryPathExtensionRegistry::extend() */ /** @addtogroup querypath_extensions Extensions * The QueryPath extension system and bundled extensions. * * Much like jQuery, QueryPath provides a simple extension mechanism that allows * extensions to auto-register themselves upon being loaded. For a simple example, see * QPXML. For the internals, see QueryPathExntesion and QueryPath::__construct(). */ /** * A QueryPathExtension is a tool that extends the capabilities of a QueryPath object. * * Extensions to QueryPath should implement the QueryPathExtension interface. The * only requirement is that the extension provide a constructor that takes a * QueryPath object as a parameter. * * Here is an example QueryPath extension: * qp = $qp; * } * * public function stubToe() { * $this->qp->find(':root')->append('')->end(); * return $this->qp; * } * } * QueryPathExtensionRegistry::extend('StubExtensionOne'); * ?> * In this example, the StubExtensionOne class implements QueryPathExtension. * The constructor stores a local copyof the QueryPath object. This is important * if you are planning on fully integrating with QueryPath's Fluent Interface. * * Finally, the stubToe() function illustrates how the extension makes use of * QueryPath internally, and remains part of the fluent interface by returning * the $qp object. * * Notice that beneath the class, there is a single call to register the * extension with QueryPath's registry. Your extension should end with a line * similar to this. * * How is a QueryPath extension called? * * QueryPath extensions are called like regular QueryPath functions. For * example, the extension above can be called like this: * * qp('some.xml')->stubToe(); * * Since it returns the QueryPath ($qp) object, chaining is supported: * * print qp('some.xml')->stubToe()->xml(); * * When you write your own extensions, anything that does not need to return a * specific value should return the QueryPath object. Between that and the * extension registry, this will provide the best developer experience. * * @ingroup querypath_extensions */ interface QueryPathExtension { public function __construct(QueryPath $qp); } /** * A registry for QueryPath extensions. * * QueryPath extensions should call the {@link QueryPathExtensionRegistry::extend()} * function to register their extension classes. The QueryPath library then * uses this information to determine what QueryPath extensions should be loaded and * executed. * * @ingroup querypath_extensions */ class QueryPathExtensionRegistry { /** * Internal flag indicating whether or not the registry should * be used for automatic extension loading. If this is false, then * implementations should not automatically load extensions. */ public static $useRegistry = TRUE; /** * The extension registry. This should consist of an array of class * names. */ protected static $extensionRegistry = array(); protected static $extensionMethodRegistry = array(); /** * Extend QueryPath with the given extension class. */ public static function extend($classname) { self::$extensionRegistry[] = $classname; $class = new ReflectionClass($classname); $methods = $class->getMethods(); foreach ($methods as $method) { self::$extensionMethodRegistry[$method->getName()] = $classname; } } /** * Check to see if a method is known. * This checks to see if the given method name belongs to one of the * registered extensions. If it does, then this will return TRUE. * * @param string $name * The name of the method to search for. * @return boolean * TRUE if the method exists, false otherwise. */ public static function hasMethod($name) { return isset(self::$extensionMethodRegistry[$name]); } /** * Check to see if the given extension class is registered. * Given a class name for a {@link QueryPathExtension} class, this * will check to see if that class is registered. If so, it will return * TRUE. * * @param string $name * The name of the class. * @return boolean * TRUE if the class is registered, FALSE otherwise. */ public static function hasExtension($name) { return in_array($name, self::$extensionRegistry); } /** * Get the class that a given method belongs to. * Given a method name, this will check all registered extension classes * to see if any of them has the named method. If so, this will return * the classname. * * Note that if two extensions are registered that contain the same * method name, the last one registred will be the only one recognized. * * @param string $name * The name of the method. * @return string * The name of the class. */ public static function getMethodClass($name) { return self::$extensionMethodRegistry[$name]; } /** * Get extensions for the given QueryPath object. * * Given a {@link QueryPath} object, this will return * an associative array of extension names to (new) instances. * Generally, this is intended to be used internally. * * @param QueryPath $qp * The QueryPath into which the extensions should be registered. * @return array * An associative array of classnames to instances. */ public static function getExtensions(QueryPath $qp) { $extInstances = array(); foreach (self::$extensionRegistry as $ext) { $extInstances[$ext] = new $ext($qp); } return $extInstances; } /** * Enable or disable automatic extension loading. * * If extension autoloading is disabled, then QueryPath will not * automatically load all registred extensions when a new QueryPath * object is created using {@link qp()}. */ public static function autoloadExtensions($boolean = TRUE) { self::$useRegistry = $boolean; } }