rest-proxy.php

Simple proxy for RESTful APIs
git clone git://git.finwo.net/app/rest-proxy.php
Log | Files | Refs | README

commit 5b95fa98ba7dc4d56aac97196ddf43191c637465
parent 7af0fb8f83b1aa4741e4a92b2c29fc02b4542cbc
Author: finwo <finwo@pm.me>
Date:   Tue, 19 Apr 2016 00:32:12 +0200

Named controller calling

Diffstat:
Mcomposer.json | 3++-
Mcomposer.lock | 74++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Mconfig/config.yml | 3++-
Msrc/Finwo/Framework/Application.php | 109+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
Asrc/Finwo/Framework/DataTransformer.php | 12++++++++++++
Msrc/Finwo/Framework/ParameterBag.php | 13++++++++++++-
Msrc/Finwo/Framework/Route.php | 44++++++++++++++++++++++++++++++++++----------
Msrc/Finwo/RestProxy/Controller/DefaultController.php | 2+-
Msrc/Finwo/RestProxy/Controller/RestController.php | 7+++++--
9 files changed, 227 insertions(+), 40 deletions(-)

diff --git a/composer.json b/composer.json @@ -17,6 +17,7 @@ "finwo/property-accessor": "*@dev", "adoy/oauth2": "^1.3", "finwo/data-tools": "dev-master", - "netresearch/jsonmapper": "^0.11.0" + "netresearch/jsonmapper": "^0.11.0", + "PHP-DI/invoker": "^1.3" } } diff --git a/composer.lock b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "2cc138d78d7557c16a2bfe561924152c", - "content-hash": "595a6a175bf73be26bb25ccdda3d8017", + "hash": "30c1581acde8d7118cc2c82cfc74a0ba", + "content-hash": "4ff42c18a3c18166064b1fba0792795b", "packages": [ { "name": "adoy/oauth2", @@ -48,6 +48,33 @@ "time": "2015-08-03 19:57:06" }, { + "name": "container-interop/container-interop", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/container-interop/container-interop.git", + "reference": "fc08354828f8fd3245f77a66b9e23a6bca48297e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/container-interop/container-interop/zipball/fc08354828f8fd3245f77a66b9e23a6bca48297e", + "reference": "fc08354828f8fd3245f77a66b9e23a6bca48297e", + "shasum": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Interop\\Container\\": "src/Interop/Container/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Promoting the interoperability of container objects (DIC, SL, etc.)", + "time": "2014-12-30 15:22:37" + }, + { "name": "finwo/data-tools", "version": "dev-master", "source": { @@ -199,6 +226,49 @@ ], "description": "Map nested JSON structures onto PHP classes", "time": "2016-04-14 21:59:35" + }, + { + "name": "php-di/invoker", + "version": "1.3.0", + "source": { + "type": "git", + "url": "https://github.com/PHP-DI/Invoker.git", + "reference": "c5c50237115803d7410d13d9d6afb5afe6526fac" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-DI/Invoker/zipball/c5c50237115803d7410d13d9d6afb5afe6526fac", + "reference": "c5c50237115803d7410d13d9d6afb5afe6526fac", + "shasum": "" + }, + "require": { + "container-interop/container-interop": "~1.1" + }, + "require-dev": { + "athletic/athletic": "~0.1.8", + "phpunit/phpunit": "~4.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Invoker\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Generic and extensible callable invoker", + "homepage": "https://github.com/PHP-DI/Invoker", + "keywords": [ + "callable", + "dependency", + "dependency-injection", + "injection", + "invoke", + "invoker" + ], + "time": "2016-03-20 17:49:41" } ], "packages-dev": [], diff --git a/config/config.yml b/config/config.yml @@ -10,7 +10,8 @@ routes: rest_proxy: type: rest path: ^\/(?<resource>[a-z\/]+)(\.(?<extension>[a-z]+))?$ -# controller: Finwo\RestProxy:Rest:get method: GET + prefix: /rest + controller: Finwo\RestProxy:Rest:get defaults: extension: json \ No newline at end of file diff --git a/src/Finwo/Framework/Application.php b/src/Finwo/Framework/Application.php @@ -3,6 +3,7 @@ namespace Finwo\Framework; use Finwo\PropertyAccessor\PropertyAccessor; +use Invoker\Invoker; class Application { @@ -127,29 +128,45 @@ class Application return $route->match(); })); - // Start known route if possible + // Construct a callable + $controller = ''; + $method = ''; if (!is_null($route)) { - - // Fetch the controller - $callable = $this->routeToCallable($route); - - var_dump($route, $callable); - die(); - - // Search for the appropriate controller - + // Fetch callable for the route + list($controller, $method) = $this->routeToCallable($route); } - var_dump($route); - die(get_class($this)); + // Create the controller object + $controller = new $controller($this->container); + + // Call the function + $invoker = new Invoker(); + $answer = $invoker->call(array($controller, $method), array_merge( + $route->getParameters(), + array( + 'route' => $route, + 'container' => $this->container, + 'query' => $route->getParameters() + ) + )); + + var_dump($answer); + die(); } protected function routeToCallable( Route $route ) { @list( $namespace, $controller, $method ) = explode(':', $route->getController()); + // This might introduce bugs we don't want +// // Add prefix to the uri if used + $parsedPath = $route->getParsedUri()['path']; +// if (strlen($prefix=$route->getPrefix())) { +// $parsedPath = $prefix . $parsedPath; +// } + // Pre-fetch uri, we might need to work with it - $uri = explode('/', trim($route->getRequestUri(), '/')); + $uri = explode('/', trim($parsedPath, '/')); // Auto-detect namespace if needed if (is_null($namespace) || !strlen($namespace)) { @@ -183,17 +200,65 @@ class Application // Merge fields into full controller class name $controller = sprintf("%s\\%sController", $namespace, $controller); - // Fetch proper method + // Fix method if needed + if( is_null($method) || !strlen($method) || !method_exists($controller, $method) ) { + $parts = $uri; + + // Check if appending 'action' does the trick + if (method_exists($controller, $method . 'Action')) { + $method .= 'Action'; + } else { + // Make sure the rest of the code catches this + $method = null; + } + + if (is_null($method) || !strlen($method)) { + while(count($parts)) { + if(method_exists($controller, ($camelized = $this->camelizedArray($parts)) . 'Action')) { + $method = $camelized . 'Action'; + break; + } + array_pop($parts); + } + + } + + // Try request method + if (is_null($method) || !strlen($method)) { + if (method_exists($controller, ($m=strtolower($route->getRequestMethod())) . 'Action')) { + $method = $m . 'Action'; + } + } + + // Try index method + if (is_null($method) || !strlen($method)) { + if (method_exists($controller, 'indexAction')) { + $method = 'indexAction'; + } + } + + // Throw exception, we don't have a function + if (is_null($method) || !strlen($method)) { + throw new \Exception('No method for the route found'); + } + } + + // Fetch how to call the method (parameters etc) + $parameters = array(); + + // We're here, that means we have all the requirements + $chosenController = new $controller($this->container); + + return array($controller,$method); + } + + protected function camelizedArray($input) { + $output = lcfirst(array_shift($input)); - // But first, debugging - if(method_exists($controller, 'indexAction')) { - die('VICTORY!!'); - } else { - die('FAILURE'); + foreach($input as $str) { + $output .= ucfirst($str); } - var_dump($namespace, $controller, $method); - var_dump($actualController); - return null; + return $output; } } \ No newline at end of file diff --git a/src/Finwo/Framework/DataTransformer.php b/src/Finwo/Framework/DataTransformer.php @@ -0,0 +1,11 @@ +<?php + +namespace Finwo\Framework; + +class DataTransformer +{ + public static function convertTo($data, $type = 'json') + { + return json_encode($data); + } +} +\ No newline at end of file diff --git a/src/Finwo/Framework/ParameterBag.php b/src/Finwo/Framework/ParameterBag.php @@ -3,8 +3,9 @@ namespace Finwo\Framework; use Finwo\PropertyAccessor\PropertyAccessor; +use Invoker\ParameterResolver\ParameterResolver; -class ParameterBag +class ParameterBag implements ParameterResolver { /** * Parameters @@ -49,6 +50,16 @@ class ParameterBag return $this->parameters; } + public function getParameters( + \ReflectionFunctionAbstract $reflection, + array $providedParameters, + array $resolvedParameters + ) + { + var_dump($reflection, $providedParameters, $resolvedParameters); + die(); + } + public function set($key, $value) { $acc = $this->getAccessor(); diff --git a/src/Finwo/Framework/Route.php b/src/Finwo/Framework/Route.php @@ -15,6 +15,7 @@ class Route extends Mappable protected $controller; protected $defaults; protected $prefix; + protected $parsedUri; // After-parse values protected $parameters; @@ -34,6 +35,15 @@ class Route extends Mappable { // If this function gets called, process the request.. No sooner + // Handle path prefix + if(strlen($this->prefix)) { + if( substr($this->requestUri, 0, strlen($this->prefix)) == $this->prefix ) { + $this->requestUri = substr($this->requestUri, strlen($this->prefix)); + } else { + return false; + } + } + // Host match if (!is_null($this->host) && !preg_match('/' . $this->host . '/i', $this->httpHost)) { return false; @@ -44,20 +54,17 @@ class Route extends Mappable return false; } - // Handle path prefix - if(strlen($this->prefix)) { - if( substr($this->requestUri, 0, strlen($this->prefix)) == $this->prefix ) { - $this->requestUri = substr($this->requestUri, strlen($this->prefix)); - } else { - return false; - } - } - // Parse the path $parsed = array_merge(array( 'path' => '/', 'query' => '' ), parse_url($this->requestUri)); + + // Store parsed uri + $this->parsedUri = $parsed; + parse_str($this->parsedUri['query'], $query); + $this->parsedUri['query'] = $query; + if (!is_null($this->path) && !preg_match('/' . $this->path . '/i', $parsed['path'], $this->parameters)) { return false; } @@ -71,13 +78,30 @@ class Route extends Mappable // Parse the query parse_str($parsed['query'], $matches); - $this->parameters = array_merge((array)$this->defaults, $this->parameters, $matches); return true; } /** + * @return mixed + */ + public function getParsedUri() + { + return $this->parsedUri; + } + + /** + * @param mixed $parsedUri + * @return Route + */ + public function setParsedUri($parsedUri) + { + $this->parsedUri = $parsedUri; + return $this; + } + + /** * @return string */ public function getType() diff --git a/src/Finwo/RestProxy/Controller/DefaultController.php b/src/Finwo/RestProxy/Controller/DefaultController.php @@ -8,6 +8,6 @@ class DefaultController extends Controller { public function indexAction() { - return 'Hello World'; + return __FILE__; } } \ No newline at end of file diff --git a/src/Finwo/RestProxy/Controller/RestController.php b/src/Finwo/RestProxy/Controller/RestController.php @@ -3,11 +3,14 @@ namespace Finwo\RestProxy\Controller; use Finwo\Framework\RestController as BaseController; +use Finwo\Framework\Route; class RestController extends BaseController { - public function indexAction() + public function getAction($resource = '', $query = array()) { - return false; + var_dump($resource); + var_dump($query); + return; } } \ No newline at end of file