From 2c8514788269a49d62f93b5df51f082eb63547b0 Mon Sep 17 00:00:00 2001 From: Kiv4h Date: Fri, 1 Jun 2012 19:38:34 +0200 Subject: [PATCH] Provides RESTful access to database objects. --- com.woltlab.wcf/option.xml | 7 ++ .../files/lib/action/APIAction.class.php | 119 ++++++++++++++++++ .../rest/response/IRESTfulResponse.class.php | 21 ++++ .../lib/system/request/RouteHandler.class.php | 9 ++ 4 files changed, 156 insertions(+) create mode 100644 wcfsetup/install/files/lib/action/APIAction.class.php create mode 100644 wcfsetup/install/files/lib/system/api/rest/response/IRESTfulResponse.class.php diff --git a/com.woltlab.wcf/option.xml b/com.woltlab.wcf/option.xml index 00b1e2d44f..daf92b2c2d 100644 --- a/com.woltlab.wcf/option.xml +++ b/com.woltlab.wcf/option.xml @@ -121,6 +121,13 @@ boolean 1 + + + diff --git a/wcfsetup/install/files/lib/action/APIAction.class.php b/wcfsetup/install/files/lib/action/APIAction.class.php new file mode 100644 index 0000000000..e8b3707aa1 --- /dev/null +++ b/wcfsetup/install/files/lib/action/APIAction.class.php @@ -0,0 +1,119 @@ + + * @package com.woltlab.wcf + * @subpackage action + * @category Community Framework + */ +final class APIAction extends AbstractAjaxAction { + /** + * needed modules to execute this action + * @var array + */ + public $neededModules = array('MODULE_API_ACCESS'); + + /** + * @see wcf\action\IAction::execute() + */ + public function execute() { + parent::execute(); + + $routeData = RouteHandler::getInstance()->getRouteData(); + + if (!isset($routeData['className']) || !isset($routeData['id'])) { + throw new IllegalLinkException(); + } + + // validate class name + if (!preg_match('~^[a-z0-9_]+$~i', $routeData['className'])) { + throw new AJAXException("Illegal class name '".$routeData['className']."'"); + } + + //get class data + $classData = $this->getClassData($routeData['className']); + + if ($classData === null) { + throw new AJAXException("unable to find class for controller '".$routeData['className']."'"); + } + else if (!class_exists($classData['className'])) { + throw new AJAXException("unable to find class '".$classData['className']."'"); + } + + //create object + $object = new $classData['className']($routeData['id']); + + if (!$object || !($object instanceof IRESTfulResponse)) { + throw new AJAXException("unable to create object of '".$routeData['className']."'"); + } + + $this->data = $this->prune($object); + + if(empty($this->data)) { + throw new AJAXException("no results"); + } + + $this->executed(); + } + + /** + * @see wcf\action\AbstractAction::executed() + */ + protected function executed() { + $this->sendJsonResponse($this->data); + } + + /** + * Checks fields, prunes given array and returns it + * + * @return array + */ + protected function prune(DatabaseObject $object) { + $prunedArray = array(); + + foreach($object->getResponseFields() as $fieldName) { + if ($object->$fieldName) { + $prunedArray[$fieldName] = $object->$fieldName; + } + } + + return $prunedArray; + } + + /** + * Tries to find class and returns class name and controller. + * + * @return array + */ + protected function getClassData($controller, $application = 'wcf') { + $className = $application.'\\data\\'.$controller.'\\'.ucfirst($controller); + if ($application != 'wcf' && !class_exists($className)) { + $className = 'wcf\\data\\'.$controller.'\\'.ucfirst($controller); + } + if (!class_exists($className)) { + return null; + } + + // check whether the class is abstract + $reflectionClass = new \ReflectionClass($className); + if ($reflectionClass->isAbstract()) { + return null; + } + + return array( + 'className' => $className, + 'controller' => $controller + ); + } +} diff --git a/wcfsetup/install/files/lib/system/api/rest/response/IRESTfulResponse.class.php b/wcfsetup/install/files/lib/system/api/rest/response/IRESTfulResponse.class.php new file mode 100644 index 0000000000..ba1088b7ce --- /dev/null +++ b/wcfsetup/install/files/lib/system/api/rest/response/IRESTfulResponse.class.php @@ -0,0 +1,21 @@ + + * @package com.woltlab.wcf + * @subpackage system.api.rest.response + * @category Community Framework + */ +interface IRESTfulResponse { + /** + * Returns a list of fields for responsing data. + * + * @return array + */ + public function getResponseFields(); +} diff --git a/wcfsetup/install/files/lib/system/request/RouteHandler.class.php b/wcfsetup/install/files/lib/system/request/RouteHandler.class.php index bf06ab0707..d3fe7d7f47 100644 --- a/wcfsetup/install/files/lib/system/request/RouteHandler.class.php +++ b/wcfsetup/install/files/lib/system/request/RouteHandler.class.php @@ -69,6 +69,15 @@ class RouteHandler extends SingletonFactory { $acpRoute->setParameterOption('id', null, '\d+', true); $this->addRoute($acpRoute); + if (MODULE_API_ACCESS) { + $apiRoute = new Route('api'); + $apiRoute->setSchema('/{controller}/{className}-{id}'); + $apiRoute->setParameterOption('controller', 'API'); + $apiRoute->setParameterOption('className', null, '\w+'); + $apiRoute->setParameterOption('id', null, '\d+'); + $this->addRoute($apiRoute); + } + $defaultRoute = new Route('default'); $defaultRoute->setSchema('/{controller}/{id}'); $defaultRoute->setParameterOption('controller', 'Index', null, true); -- 2.20.1