Пример #1
0
 /**
  * Generates cacheable url to method mapping
  *
  * @param string $className
  * @param string $resourcePath
  */
 protected function generateMap($className, $resourcePath = '')
 {
     /*
      * Mapping Rules - Optional parameters should not be mapped to URL - if
      * a required parameter is of primitive type - Map them to URL - Do not
      * create routes with out it - if a required parameter is not primitive
      * type - Do not include it in URL
      */
     $reflection = new ReflectionClass($className);
     $classMetadata = CommentParser::parse($reflection->getDocComment());
     $methods = $reflection->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();
         $metadata = CommentParser::parse($doc) + $classMetadata;
         //@access should not be private
         if (isset($metadata['access']) && $metadata['access'] == 'private') {
             continue;
         }
         $arguments = array();
         $defaults = array();
         $params = $method->getParameters();
         $position = 0;
         $ignorePathTill = false;
         $allowAmbiguity = isset($metadata['smart-auto-routing']) && $metadata['smart-auto-routing'] != 'true' || !Defaults::$smartAutoRouting;
         $metadata['resourcePath'] = $resourcePath;
         if (isset($classMetadata['description'])) {
             $metadata['classDescription'] = $classMetadata['description'];
         }
         if (isset($classMetadata['classLongDescription'])) {
             $metadata['classLongDescription'] = $classMetadata['longDescription'];
         }
         if (!isset($metadata['param'])) {
             $metadata['param'] = array();
         }
         foreach ($params as $param) {
             $type = $param->isArray() ? 'array' : $param->getClass();
             if ($type instanceof ReflectionClass) {
                 $type = $type->getName();
             }
             $arguments[$param->getName()] = $position;
             $defaults[$position] = $param->isDefaultValueAvailable() ? $param->getDefaultValue() : null;
             if (!isset($metadata['param'][$position])) {
                 $metadata['param'][$position] = array();
             }
             $m =& $metadata['param'][$position];
             if (isset($type)) {
                 $m['type'] = $type;
             }
             $m['name'] = trim($param->getName(), '$ ');
             $m['default'] = $defaults[$position];
             $m['required'] = !$param->isOptional();
             if (isset($m[CommentParser::$embeddedDataName]['from'])) {
                 $from = $m[CommentParser::$embeddedDataName]['from'];
             } else {
                 if (isset($type) && Util::isObjectOrArray($type) || $param->getName() == Defaults::$fullRequestDataName) {
                     $from = 'body';
                 } elseif ($m['required']) {
                     $from = 'path';
                 } else {
                     $from = 'query';
                 }
             }
             $m['from'] = $from;
             if (!$allowAmbiguity && $from == 'path') {
                 $ignorePathTill = $position + 1;
             }
             $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('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], '/');
                 $this->routes[$httpMethod][$url] = $call;
             }
             //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;
             if (!$ignorePathTill) {
                 $this->routes[$httpMethod][$url] = $call;
             }
             $position = 1;
             foreach ($params as $param) {
                 $from = $metadata['param'][$position - 1]['from'];
                 if ($from == 'body' && ($httpMethod == 'GET' || $httpMethod == 'DELETE')) {
                     $from = $metadata['param'][$position - 1]['from'] = 'query';
                 }
                 if (!$allowAmbiguity && $from != 'path') {
                     break;
                 }
                 if (!empty($url)) {
                     $url .= '/';
                 }
                 $url .= '{' . $param->getName() . '}';
                 if ($allowAmbiguity || $position == $ignorePathTill) {
                     $this->routes[$httpMethod][$url] = $call;
                 }
                 $position++;
             }
         }
     }
 }
Пример #2
0
 /**
  * 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') ?: [];
                 } 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];
 }
Пример #3
0
<?php

/**
 * Restler 2 compatibility mode enabler
 */
use Luracast\Restler\Defaults;
use Luracast\Restler\AutoLoader;
use Luracast\Restler\CommentParser;
//changes in auto loading
$classMap = array();
//find lowercase php files representing a class/interface
foreach (explode(PATH_SEPARATOR, get_include_path()) as $path) {
    foreach (new DirectoryIterator($path) as $fileInfo) {
        if ($fileInfo->isFile() && 'php' === $fileInfo->getExtension() && ctype_lower($fileInfo->getBasename('.php')) && preg_match('/^ *(class|interface|abstract +class)' . ' +([a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*)/m', file_get_contents($fileInfo->getPathname()), $matches)) {
            $classMap[$matches[2]] = $fileInfo->getPathname();
        }
    }
}
AutoLoader::seen($classMap);
//changes in iAuthenticate
Defaults::$authenticationMethod = '__isAuthenticated';
include __DIR__ . '/iAuthenticate.php';
//changes in auto routing
Defaults::$smartAutoRouting = false;
Defaults::$smartParameterParsing = false;
Defaults::$autoValidationEnabled = false;
//changes in parsing embedded data in comments
CommentParser::$embeddedDataPattern = '/\\((\\S+)\\)/ms';
CommentParser::$embeddedDataIndex = 1;
Пример #4
0
 protected function _model($className, $instance = null)
 {
     $id = $this->_noNamespace($className);
     if (isset($this->_models->{$id})) {
         return;
     }
     $properties = array();
     if (!$instance) {
         if (!class_exists($className)) {
             return;
         }
         $instance = new $className();
     }
     $data = get_object_vars($instance);
     $reflectionClass = new \ReflectionClass($className);
     foreach ($data as $key => $value) {
         $propertyMetaData = null;
         try {
             $property = $reflectionClass->getProperty($key);
             if ($c = $property->getDocComment()) {
                 $propertyMetaData = Util::nestedValue(CommentParser::parse($c), 'var');
             }
         } catch (\ReflectionException $e) {
         }
         if (is_null($propertyMetaData)) {
             $type = $this->getType($value, true);
             $description = '';
         } else {
             $type = Util::nestedValue($propertyMetaData, 'type') ?: $this->getType($value, true);
             $description = Util::nestedValue($propertyMetaData, 'description') ?: '';
             if (class_exists($type)) {
                 $this->_model($type);
                 $type = $this->_noNamespace($type);
             }
         }
         if (isset(static::$dataTypeAlias[$type])) {
             $type = static::$dataTypeAlias[$type];
         }
         $properties[$key] = array('type' => $type, 'description' => $description);
         if (Util::nestedValue($propertyMetaData, CommentParser::$embeddedDataName, 'required')) {
             $properties[$key]['required'] = true;
         }
         if ($type == 'Array') {
             $itemType = Util::nestedValue($propertyMetaData, CommentParser::$embeddedDataName, 'type') ?: (count($value) ? $this->getType(end($value), true) : 'string');
             if (class_exists($itemType)) {
                 $this->_model($itemType);
                 $itemType = $this->_noNamespace($itemType);
             }
             $properties[$key]['item'] = array('type' => $itemType);
         } else {
             if (preg_match('/^Array\\[(.+)\\]$/', $type, $matches)) {
                 $itemType = $matches[1];
                 $properties[$key]['type'] = 'Array';
                 $properties[$key]['item']['type'] = $itemType;
                 if (class_exists($itemType)) {
                     $this->_model($itemType);
                 }
             }
         }
     }
     if (!empty($properties)) {
         $model = new stdClass();
         $model->id = $id;
         $model->properties = $properties;
         $this->_models->{$id} = $model;
     }
 }
Пример #5
0
 /**
  * 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)
 {
     $className = $class->getName();
     if (isset(static::$models[$className])) {
         return static::$models[$className];
     }
     $children = array();
     try {
         $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') ?: [];
             } 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' => $child['name'] == 'email' ? 'email' : 'string', 'label' => static::label($child['name']));
             isset($child[CommentParser::$embeddedDataName]) ? $child[CommentParser::$embeddedDataName] += array('required' => true) : ($child[CommentParser::$embeddedDataName]['required'] = true);
             if ($qualified = Scope::resolve($child['type'], $scope)) {
                 list($child['type'], $child['children']) = static::getTypeAndModel(new ReflectionClass($qualified), $scope);
             } elseif (($contentType = Util::nestedValue($child, CommentParser::$embeddedDataName, 'type')) && ($qualified = Scope::resolve($contentType, $scope))) {
                 list($child['contentType'], $child['children']) = static::getTypeAndModel(new ReflectionClass($qualified), $scope);
             }
             $children[$name] = $child;
         }
     } catch (Exception $e) {
         if (String::endsWith($e->getFile(), 'CommentParser.php')) {
             throw new RestException(500, "Error while parsing comments of `{$className}` class. " . $e->getMessage());
         }
         throw $e;
     }
     static::$models[$className] = array($className, $children);
     return static::$models[$className];
 }
Пример #6
0
 /**
  * @param ReflectionClass $class
  *
  * @return array
  *
  * @access protected
  */
 protected static function getTypeAndModel(ReflectionClass $class)
 {
     $children = array();
     $props = $class->getProperties(ReflectionProperty::IS_PUBLIC);
     foreach ($props as $prop) {
         if ($c = $prop->getDocComment()) {
             $children[$prop->getName()] = array('name' => $prop->getName()) + Util::nestedValue(CommentParser::parse($c), 'var') + array('type' => 'string');
         }
     }
     return array($class->getName(), $children);
 }
Пример #7
0
 private function _model($className, $instance = null)
 {
     $properties = array();
     $reflectionClass = new \ReflectionClass($className);
     if (!$instance) {
         $instance = new $className();
     }
     $data = get_object_vars($instance);
     foreach ($data as $key => $value) {
         $propertyMetaData = null;
         try {
             $property = $reflectionClass->getProperty($key);
             if ($c = $property->getDocComment()) {
                 $propertyMetaData = CommentParser::parse($c);
             }
         } catch (\ReflectionException $e) {
         }
         if ($propertyMetaData !== null) {
             $type = isset($propertyMetaData['var']) ? $propertyMetaData['var'] : 'string';
             $description = @$propertyMetaData['description'] ?: '';
             if (class_exists($type)) {
                 $this->_model($type);
             }
         } else {
             $type = $this->getType($value, true);
             $description = '';
         }
         if (isset(static::$dataTypeAlias[$type])) {
             $type = static::$dataTypeAlias[$type];
         }
         $properties[$key] = array('type' => $type, 'description' => $description);
         if ($type == 'Array') {
             $itemType = count($value) ? $this->getType($value[0], true) : 'string';
             $properties[$key]['item'] = array('type' => $itemType);
         } else {
             if (preg_match('/^Array\\[(.+)\\]$/', $type, $matches)) {
                 $itemType = $matches[1];
                 $properties[$key]['type'] = 'Array';
                 $properties[$key]['item']['type'] = $itemType;
                 if (class_exists($itemType)) {
                     $this->_model($itemType);
                 }
             }
         }
     }
     if (!empty($properties)) {
         $id = $this->_noNamespace($className);
         $model = new stdClass();
         $model->id = $id;
         $model->properties = $properties;
         $this->_models->{$id} = $model;
     }
 }