| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822 |
- <?php
- namespace Luracast\Restler;
- use Luracast\Restler\Data\ApiMethodInfo;
- use Luracast\Restler\Data\Text;
- use ReflectionClass;
- use ReflectionMethod;
- use ReflectionProperty;
- use Exception;
- /**
- * Router class that routes the urls to api methods along with parameters
- *
- * @category Framework
- * @package Restler
- * @author R.Arul Kumaran <arul@luracast.com>
- * @copyright 2010 Luracast
- * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
- * @link http://luracast.com/products/restler/
- *
- */
- class Routes
- {
- public static $prefixingParameterNames = array(
- 'id'
- );
- public static $fieldTypesByName = array(
- 'email' => 'email',
- 'password' => 'password',
- 'phone' => 'tel',
- 'mobile' => 'tel',
- 'tel' => 'tel',
- 'search' => 'search',
- 'date' => 'date',
- 'created_at' => 'datetime',
- 'modified_at' => 'datetime',
- 'url' => 'url',
- 'link' => 'url',
- 'href' => 'url',
- 'website' => 'url',
- 'color' => 'color',
- 'colour' => 'color',
- );
- protected static $routes = array();
- protected static $models = array();
- /**
- * Route the public and protected methods of an Api class
- *
- * @param string $className
- * @param string $resourcePath
- * @param int $version
- *
- * @throws RestException
- */
- public static function addAPIClass($className, $resourcePath = '', $version = 1)
- {
- /*
- * Mapping Rules
- * =============
- *
- * - Optional parameters should not be mapped to URL
- * - If a required parameter is of primitive type
- * - If one of the self::$prefixingParameterNames
- * - Map it to URL
- * - Else If request method is POST/PUT/PATCH
- * - Map it to body
- * - Else If request method is GET/DELETE
- * - Map it to body
- * - If a required parameter is not primitive type
- * - Do not include it in URL
- */
- $class = new ReflectionClass($className);
- $dataName = CommentParser::$embeddedDataName;
- try {
- $classMetadata = CommentParser::parse($class->getDocComment());
- } catch (Exception $e) {
- throw new RestException(500, "Error while parsing comments of `$className` class. " . $e->getMessage());
- }
- $classMetadata['scope'] = $scope = static::scope($class);
- $methods = $class->getMethods(ReflectionMethod::IS_PUBLIC +
- ReflectionMethod::IS_PROTECTED);
- foreach ($methods as $method) {
- $methodUrl = strtolower($method->getName());
- //method name should not begin with _
- if ($methodUrl[0] == '_') {
- continue;
- }
- $doc = $method->getDocComment();
- try {
- $metadata = CommentParser::parse($doc) + $classMetadata;
- } catch (Exception $e) {
- throw new RestException(500, "Error while parsing comments of `{$className}::{$method->getName()}` method. " . $e->getMessage());
- }
- //@access should not be private
- if (isset($metadata['access'])
- && $metadata['access'] == 'private'
- ) {
- continue;
- }
- $arguments = array();
- $defaults = array();
- $params = $method->getParameters();
- $position = 0;
- $pathParams = array();
- $allowAmbiguity
- = (isset($metadata['smart-auto-routing'])
- && $metadata['smart-auto-routing'] != 'true')
- || !Defaults::$smartAutoRouting;
- $metadata['resourcePath'] = trim($resourcePath, '/');
- if (isset($classMetadata['description'])) {
- $metadata['classDescription'] = $classMetadata['description'];
- }
- if (isset($classMetadata['classLongDescription'])) {
- $metadata['classLongDescription']
- = $classMetadata['longDescription'];
- }
- if (!isset($metadata['param'])) {
- $metadata['param'] = array();
- }
- if (isset($metadata['return']['type'])) {
- if ($qualified = Scope::resolve($metadata['return']['type'], $scope))
- list($metadata['return']['type'], $metadata['return']['children']) =
- static::getTypeAndModel(new ReflectionClass($qualified), $scope);
- } else {
- //assume return type is array
- $metadata['return']['type'] = 'array';
- }
- foreach ($params as $param) {
- $children = array();
- $type =
- $param->isArray() ? 'array' : $param->getClass();
- $arguments[$param->getName()] = $position;
- $defaults[$position] = $param->isDefaultValueAvailable() ?
- $param->getDefaultValue() : null;
- if (!isset($metadata['param'][$position])) {
- $metadata['param'][$position] = array();
- }
- $m = & $metadata ['param'] [$position];
- $m ['name'] = $param->getName();
- if (!isset($m[$dataName])) {
- $m[$dataName] = array();
- }
- $p = &$m[$dataName];
- if (empty($m['label']))
- $m['label'] = Text::title($m['name']);
- if (is_null($type) && isset($m['type'])) {
- $type = $m['type'];
- }
- if (isset(static::$fieldTypesByName[$m['name']]) && empty($p['type']) && $type == 'string') {
- $p['type'] = static::$fieldTypesByName[$m['name']];
- }
- $m ['default'] = $defaults [$position];
- $m ['required'] = !$param->isOptional();
- $contentType = Util::nestedValue($p,'type');
- if ($type == 'array' && $contentType && $qualified = Scope::resolve($contentType, $scope)) {
- list($p['type'], $children, $modelName) = static::getTypeAndModel(
- new ReflectionClass($qualified), $scope,
- $className . Text::title($methodUrl), $p
- );
- }
- if ($type instanceof ReflectionClass) {
- list($type, $children, $modelName) = static::getTypeAndModel($type, $scope,
- $className . Text::title($methodUrl), $p);
- } elseif ($type && is_string($type) && $qualified = Scope::resolve($type, $scope)) {
- list($type, $children, $modelName)
- = static::getTypeAndModel(new ReflectionClass($qualified), $scope,
- $className . Text::title($methodUrl), $p);
- }
- if (isset($type)) {
- $m['type'] = $type;
- }
- $m['children'] = $children;
- if (isset($modelName)) {
- $m['model'] = $modelName;
- }
- if ($m['name'] == Defaults::$fullRequestDataName) {
- $from = 'body';
- if (!isset($m['type'])) {
- $type = $m['type'] = 'array';
- }
- } elseif (isset($p['from'])) {
- $from = $p['from'];
- } else {
- if ((isset($type) && Util::isObjectOrArray($type))
- ) {
- $from = 'body';
- if (!isset($type)) {
- $type = $m['type'] = 'array';
- }
- } elseif ($m['required'] && in_array($m['name'], static::$prefixingParameterNames)) {
- $from = 'path';
- } else {
- $from = 'body';
- }
- }
- $p['from'] = $from;
- if (!isset($m['type'])) {
- $type = $m['type'] = static::type($defaults[$position]);
- }
- if ($allowAmbiguity || $from == 'path') {
- $pathParams [] = $position;
- }
- $position++;
- }
- $accessLevel = 0;
- if ($method->isProtected()) {
- $accessLevel = 3;
- } elseif (isset($metadata['access'])) {
- if ($metadata['access'] == 'protected') {
- $accessLevel = 2;
- } elseif ($metadata['access'] == 'hybrid') {
- $accessLevel = 1;
- }
- } elseif (isset($metadata['protected'])) {
- $accessLevel = 2;
- }
- /*
- echo " access level $accessLevel for $className::"
- .$method->getName().$method->isProtected().PHP_EOL;
- */
- // take note of the order
- $call = array(
- 'url' => null,
- 'className' => $className,
- 'path' => rtrim($resourcePath, '/'),
- 'methodName' => $method->getName(),
- 'arguments' => $arguments,
- 'defaults' => $defaults,
- 'metadata' => $metadata,
- 'accessLevel' => $accessLevel,
- );
- // if manual route
- if (preg_match_all(
- '/@url\s+(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)'
- . '[ \t]*\/?(\S*)/s',
- $doc, $matches, PREG_SET_ORDER
- )
- ) {
- foreach ($matches as $match) {
- $httpMethod = $match[1];
- $url = rtrim($resourcePath . $match[2], '/');
- //deep copy the call, as it may change for each @url
- $copy = unserialize(serialize($call));
- foreach ($copy['metadata']['param'] as $i => $p) {
- $inPath =
- strpos($url, '{' . $p['name'] . '}') ||
- strpos($url, ':' . $p['name']);
- if ($inPath) {
- $copy['metadata']['param'][$i][$dataName]['from'] = 'path';
- } elseif ($httpMethod == 'GET' || $httpMethod == 'DELETE') {
- $copy['metadata']['param'][$i][$dataName]['from'] = 'query';
- } elseif (empty($p[$dataName]['from']) || $p[$dataName]['from'] == 'path') {
- $copy['metadata']['param'][$i][$dataName]['from'] = 'body';
- }
- }
- $url = preg_replace_callback('/{[^}]+}|:[^\/]+/',
- function ($matches) use ($copy) {
- $match = trim($matches[0], '{}:');
- $index = $copy['arguments'][$match];
- return '{' .
- Routes::typeChar(isset(
- $copy['metadata']['param'][$index]['type'])
- ? $copy['metadata']['param'][$index]['type']
- : null)
- . $index . '}';
- }, $url);
- static::addPath($url, $copy, $httpMethod, $version);
- }
- //if auto route enabled, do so
- } elseif (Defaults::$autoRoutingEnabled) {
- // no configuration found so use convention
- if (preg_match_all(
- '/^(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)/i',
- $methodUrl, $matches)
- ) {
- $httpMethod = strtoupper($matches[0][0]);
- $methodUrl = substr($methodUrl, strlen($httpMethod));
- } else {
- $httpMethod = 'GET';
- }
- if ($methodUrl == 'index') {
- $methodUrl = '';
- }
- $url = empty($methodUrl) ? rtrim($resourcePath, '/')
- : $resourcePath . $methodUrl;
- for ($position = 0; $position < count($params); $position++) {
- $from = $metadata['param'][$position][$dataName]['from'];
- if ($from == 'body' && ($httpMethod == 'GET' ||
- $httpMethod == 'DELETE')
- ) {
- $call['metadata']['param'][$position][$dataName]['from']
- = 'query';
- }
- }
- if (empty($pathParams) || $allowAmbiguity) {
- static::addPath($url, $call, $httpMethod, $version);
- }
- $lastPathParam = end($pathParams);
- foreach ($pathParams as $position) {
- if (!empty($url))
- $url .= '/';
- $url .= '{' .
- static::typeChar(isset($call['metadata']['param'][$position]['type'])
- ? $call['metadata']['param'][$position]['type']
- : null)
- . $position . '}';
- if ($allowAmbiguity || $position == $lastPathParam) {
- static::addPath($url, $call, $httpMethod, $version);
- }
- }
- }
- }
- }
- /**
- * @access private
- */
- public static function typeChar($type = null)
- {
- if (!$type) {
- return 's';
- }
- switch ($type[0]) {
- case 'i':
- case 'f':
- return 'n';
- }
- return 's';
- }
- protected static function addPath($path, array $call,
- $httpMethod = 'GET', $version = 1)
- {
- $call['url'] = preg_replace_callback(
- "/\{\S(\d+)\}/",
- function ($matches) use ($call) {
- return '{' .
- $call['metadata']['param'][$matches[1]]['name'] . '}';
- },
- $path
- );
- //check for wildcard routes
- if (substr($path, -1, 1) == '*') {
- $path = rtrim($path, '/*');
- static::$routes["v$version"]['*'][$path][$httpMethod] = $call;
- } else {
- static::$routes["v$version"][$path][$httpMethod] = $call;
- //create an alias with index if the method name is index
- if ($call['methodName'] == 'index')
- static::$routes["v$version"][ltrim("$path/index", '/')][$httpMethod] = $call;
- }
- }
- /**
- * Find the api method for the given url and http method
- *
- * @param string $path Requested url path
- * @param string $httpMethod GET|POST|PUT|PATCH|DELETE etc
- * @param int $version Api Version number
- * @param array $data Data collected from the request
- *
- * @throws RestException
- * @return ApiMethodInfo
- */
- public static function find($path, $httpMethod,
- $version = 1, array $data = array())
- {
- $p = Util::nestedValue(static::$routes, "v$version");
- if (!$p) {
- throw new RestException(
- 404,
- $version == 1 ? '' : "Version $version is not supported"
- );
- }
- $status = 404;
- $message = null;
- $methods = array();
- if (isset($p[$path][$httpMethod])) {
- //================== static routes ==========================
- return static::populate($p[$path][$httpMethod], $data);
- } elseif (isset($p['*'])) {
- //================== wildcard routes ========================
- uksort($p['*'], function ($a, $b) {
- return strlen($b) - strlen($a);
- });
- foreach ($p['*'] as $key => $value) {
- if (strpos($path, $key) === 0 && isset($value[$httpMethod])) {
- //path found, convert rest of the path to parameters
- $path = substr($path, strlen($key) + 1);
- $call = ApiMethodInfo::__set_state($value[$httpMethod]);
- $call->parameters = empty($path)
- ? array()
- : explode('/', $path);
- return $call;
- }
- }
- }
- //================== dynamic routes =============================
- //add newline char if trailing slash is found
- if (substr($path, -1) == '/')
- $path .= PHP_EOL;
- //if double slash is found fill in newline char;
- $path = str_replace('//', '/' . PHP_EOL . '/', $path);
- ksort($p);
- foreach ($p as $key => $value) {
- if (!isset($value[$httpMethod])) {
- continue;
- }
- $regex = str_replace(array('{', '}'),
- array('(?P<', '>[^/]+)'), $key);
- if (preg_match_all(":^$regex$:i", $path, $matches, PREG_SET_ORDER)) {
- $matches = $matches[0];
- $found = true;
- foreach ($matches as $k => $v) {
- if (is_numeric($k)) {
- unset($matches[$k]);
- continue;
- }
- $index = intval(substr($k, 1));
- $details = $value[$httpMethod]['metadata']['param'][$index];
- if ($k[0] == 's' || strpos($k, static::pathVarTypeOf($v)) === 0) {
- //remove the newlines
- $data[$details['name']] = trim($v, PHP_EOL);
- } else {
- $status = 400;
- $message = 'invalid value specified for `'
- . $details['name'] . '`';
- $found = false;
- break;
- }
- }
- if ($found) {
- return static::populate($value[$httpMethod], $data);
- }
- }
- }
- if ($status == 404) {
- //check if other methods are allowed
- if (isset($p[$path])) {
- $status = 405;
- $methods = array_keys($p[$path]);
- }
- }
- if ($status == 405) {
- header('Allow: ' . implode(', ', $methods));
- }
- throw new RestException($status, $message);
- }
- public static function findAll(array $excludedPaths = array(), array $excludedHttpMethods = array(), $version = 1)
- {
- $map = array();
- $all = Util::nestedValue(self::$routes, "v$version");
- $filter = array();
- if (isset($all['*'])) {
- $all = $all['*'] + $all;
- unset($all['*']);
- }
- if(is_array($all)){
- foreach ($all as $fullPath => $routes) {
- foreach ($routes as $httpMethod => $route) {
- if (in_array($httpMethod, $excludedHttpMethods)) {
- continue;
- }
- foreach ($excludedPaths as $exclude) {
- if (empty($exclude)) {
- if ($fullPath == $exclude || $fullPath == 'index')
- continue 2;
- } elseif (Text::beginsWith($fullPath, $exclude)) {
- continue 2;
- }
- }
- $hash = "$httpMethod " . $route['url'];
- if (!isset($filter[$hash])) {
- $route['httpMethod'] = $httpMethod;
- $map[$route['metadata']['resourcePath']][]
- = array('access' => static::verifyAccess($route), 'route' => $route, 'hash' => $hash);
- $filter[$hash] = true;
- }
- }
- }
- }
- return $map;
- }
- public static function verifyAccess($route)
- {
- if ($route['accessLevel'] < 2)
- return true;
- /** @var Restler $r */
- $r = Scope::get('Restler');
- $authenticated = $r->_authenticated;
- if (!$authenticated && $route['accessLevel'] > 1)
- return false;
- if (
- $authenticated &&
- Defaults::$accessControlFunction &&
- (!call_user_func(Defaults::$accessControlFunction, $route['metadata']))
- ) {
- return false;
- }
- return true;
- }
- /**
- * Populates the parameter values
- *
- * @param array $call
- * @param $data
- *
- * @return ApiMethodInfo
- *
- * @access private
- */
- protected static function populate(array $call, $data)
- {
- $call['parameters'] = $call['defaults'];
- $p = & $call['parameters'];
- $dataName = CommentParser::$embeddedDataName;
- foreach ($data as $key => $value) {
- if (isset($call['arguments'][$key])) {
- $p[$call['arguments'][$key]] = $value;
- }
- }
- if (Defaults::$smartParameterParsing) {
- if (
- ($m = Util::nestedValue($call, 'metadata', 'param', 0)) &&
- !array_key_exists($m['name'], $data) &&
- array_key_exists(Defaults::$fullRequestDataName, $data) &&
- !is_null($d = $data[Defaults::$fullRequestDataName]) &&
- isset($m['type']) &&
- static::typeMatch($m['type'], $d)
- ) {
- $p[0] = $d;
- } else {
- $bodyParamCount = 0;
- $lastBodyParamIndex = -1;
- $lastM = null;
- foreach ($call['metadata']['param'] as $k => $m) {
- if ($m[$dataName]['from'] == 'body') {
- $bodyParamCount++;
- $lastBodyParamIndex = $k;
- $lastM = $m;
- }
- }
- if (
- $bodyParamCount == 1 &&
- !array_key_exists($lastM['name'], $data) &&
- array_key_exists(Defaults::$fullRequestDataName, $data) &&
- !is_null($d = $data[Defaults::$fullRequestDataName])
- ) {
- $p[$lastBodyParamIndex] = $d;
- }
- }
- }
- $r = ApiMethodInfo::__set_state($call);
- $modifier = "_modify_{$r->methodName}_api";
- if (method_exists($r->className, $modifier)) {
- $stage = end(Scope::get('Restler')->getEvents());
- if (empty($stage))
- $stage = 'setup';
- $r = Scope::get($r->className)->$modifier($r, $stage) ? : $r;
- }
- return $r;
- }
- /**
- * @access private
- */
- protected static function pathVarTypeOf($var)
- {
- if (is_numeric($var)) {
- return 'n';
- }
- if ($var === 'true' || $var === 'false') {
- return 'b';
- }
- return 's';
- }
- protected static function typeMatch($type, $var)
- {
- switch ($type) {
- case 'boolean':
- case 'bool':
- return is_bool($var);
- case 'array':
- case 'object':
- return is_array($var);
- case 'string':
- case 'int':
- case 'integer':
- case 'float':
- case 'number':
- return is_scalar($var);
- }
- return true;
- }
- protected static function parseMagic(ReflectionClass $class, $forResponse = true)
- {
- if (!$c = CommentParser::parse($class->getDocComment())) {
- return false;
- }
- $p = 'property';
- $r = empty($c[$p]) ? array() : $c[$p];
- $p .= '-' . ($forResponse ? 'read' : 'write');
- if (!empty($c[$p])) {
- $r = array_merge($r, $c[$p]);
- }
- return $r;
- }
- /**
- * Get the type and associated model
- *
- * @param ReflectionClass $class
- * @param array $scope
- *
- * @throws RestException
- * @throws \Exception
- * @return array
- *
- * @access protected
- */
- protected static function getTypeAndModel(ReflectionClass $class, array $scope, $prefix='', array $rules=array())
- {
- $className = $class->getName();
- $dataName = CommentParser::$embeddedDataName;
- if (isset(static::$models[$prefix.$className])) {
- return static::$models[$prefix.$className];
- }
- $children = array();
- try {
- if ($magic_properties = static::parseMagic($class, empty($prefix))) {
- foreach ($magic_properties as $prop) {
- if (!isset($prop['name'])) {
- throw new Exception('@property comment is not properly defined in ' . $className . ' class');
- }
- if (!isset($prop[$dataName]['label'])) {
- $prop[$dataName]['label'] = Text::title($prop['name']);
- }
- if (isset(static::$fieldTypesByName[$prop['name']]) && $prop['type'] == 'string' && !isset($prop[$dataName]['type'])) {
- $prop[$dataName]['type'] = static::$fieldTypesByName[$prop['name']];
- }
- $children[$prop['name']] = $prop;
- }
- } else {
- $props = $class->getProperties(ReflectionProperty::IS_PUBLIC);
- foreach ($props as $prop) {
- $name = $prop->getName();
- $child = array('name' => $name);
- if ($c = $prop->getDocComment()) {
- $child += Util::nestedValue(CommentParser::parse($c), 'var') ?: array();
- } else {
- $o = $class->newInstance();
- $p = $prop->getValue($o);
- if (is_object($p)) {
- $child['type'] = get_class($p);
- } elseif (is_array($p)) {
- $child['type'] = 'array';
- if (count($p)) {
- $pc = reset($p);
- if (is_object($pc)) {
- $child['contentType'] = get_class($pc);
- }
- }
- }
- }
- $child += array(
- 'type' => isset(static::$fieldTypesByName[$child['name']])
- ? static::$fieldTypesByName[$child['name']]
- : 'string',
- 'label' => Text::title($child['name'])
- );
- isset($child[$dataName])
- ? $child[$dataName] += array('required' => true)
- : $child[$dataName]['required'] = true;
- if ($prop->class != $className && $qualified = Scope::resolve($child['type'], $scope)) {
- list($child['type'], $child['children'])
- = static::getTypeAndModel(new ReflectionClass($qualified), $scope);
- } elseif (
- ($contentType = Util::nestedValue($child, $dataName, 'type')) &&
- ($qualified = Scope::resolve($contentType, $scope))
- ) {
- list($child['contentType'], $child['children'])
- = static::getTypeAndModel(new ReflectionClass($qualified), $scope);
- }
- $children[$name] = $child;
- }
- }
- } catch (Exception $e) {
- if (Text::endsWith($e->getFile(), 'CommentParser.php')) {
- throw new RestException(500, "Error while parsing comments of `$className` class. " . $e->getMessage());
- }
- throw $e;
- }
- if ($properties = Util::nestedValue($rules, 'properties')) {
- if (is_string($properties)) {
- $properties = array($properties);
- }
- $c = array();
- foreach ($properties as $property) {
- if (isset($children[$property])) {
- $c[$property] = $children[$property];
- }
- }
- $children = $c;
- }
- if ($required = Util::nestedValue($rules, 'required')) {
- //override required on children
- if (is_bool($required)) {
- // true means all are required false means none are required
- $required = $required ? array_keys($children) : array();
- } elseif (is_string($required)) {
- $required = array($required);
- }
- $required = array_fill_keys($required, true);
- foreach ($children as $name => $child) {
- $children[$name][$dataName]['required'] = isset($required[$name]);
- }
- }
- static::$models[$prefix.$className] = array($className, $children, $prefix.$className);
- return static::$models[$prefix.$className];
- }
- /**
- * Import previously created routes from cache
- *
- * @param array $routes
- */
- public static function fromArray(array $routes)
- {
- static::$routes = $routes;
- }
- /**
- * Export current routes for cache
- *
- * @return array
- */
- public static function toArray()
- {
- return static::$routes;
- }
- public static function type($var)
- {
- if (is_object($var)) return get_class($var);
- if (is_array($var)) return 'array';
- if (is_bool($var)) return 'boolean';
- if (is_numeric($var)) return is_float($var) ? 'float' : 'int';
- return 'string';
- }
- public static function scope(ReflectionClass $class)
- {
- $namespace = $class->getNamespaceName();
- $imports = array(
- '*' => empty($namespace) ? '' : $namespace . '\\'
- );
- $file = file_get_contents($class->getFileName());
- $tokens = token_get_all($file);
- $namespace = '';
- $alias = '';
- $reading = false;
- $last = 0;
- foreach ($tokens as $token) {
- if (is_string($token)) {
- if ($reading && ',' == $token) {
- //===== STOP =====//
- $reading = false;
- if (!empty($namespace))
- $imports[$alias] = trim($namespace, '\\');
- //===== START =====//
- $reading = true;
- $namespace = '';
- $alias = '';
- } else {
- //===== STOP =====//
- $reading = false;
- if (!empty($namespace))
- $imports[$alias] = trim($namespace, '\\');
- }
- } elseif (T_USE == $token[0]) {
- //===== START =====//
- $reading = true;
- $namespace = '';
- $alias = '';
- } elseif ($reading) {
- //echo token_name($token[0]) . ' ' . $token[1] . PHP_EOL;
- switch ($token[0]) {
- case T_WHITESPACE:
- continue 2;
- case T_STRING:
- $alias = $token[1];
- if (T_AS == $last) {
- break;
- }
- //don't break;
- case T_NS_SEPARATOR:
- $namespace .= $token[1];
- break;
- }
- $last = $token[0];
- }
- }
- return $imports;
- }
- }
|