Beispiel #1
0
 public static function get($for = '', $activeTrail = null)
 {
     if (empty(static::$tree)) {
         /** @var Restler $restler */
         $restler = Scope::get('Restler');
         if (static::$addExtension) {
             static::$extension = isset($restler->responseFormat) ? '.' . $restler->responseFormat->getExtension() : '.html';
         }
         static::$url = $restler->getBaseUrl();
         if (empty(static::$url)) {
             static::$url = '';
         }
         static::$activeTrail = $activeTrail = empty($activeTrail) ? empty($restler->url) || $restler->url == 'index' ? static::$root : $restler->url : $activeTrail;
         if (static::$addExtension) {
             static::$extension = isset($restler->responseFormat) ? '.' . $restler->responseFormat->getExtension() : '.html';
         }
         static::addUrls(static::$prepends);
         $map = Routes::findAll(static::$excludedPaths, array('POST', 'DELETE', 'PUT', 'PATCH'), $restler->getRequestedApiVersion());
         foreach ($map as $path => $data) {
             foreach ($data as $item) {
                 $access = $item['access'];
                 $route = $item['route'];
                 $url = $route['url'];
                 if ($access && !Text::contains($url, '{')) {
                     $label = Util::nestedValue($route, 'metadata', CommentParser::$embeddedDataName, 'label');
                     if (!empty($url)) {
                         $url .= static::$extension;
                     }
                     static::add($url, $label);
                 }
             }
         }
         static::addUrls(static::$appends);
     } elseif (empty($activeTrail)) {
         $activeTrail = static::$activeTrail;
     }
     $tree = static::$tree;
     $activeTrail = explode('/', $activeTrail);
     $nested =& static::nested($tree, $activeTrail);
     if (is_array($nested)) {
         $nested['active'] = true;
     }
     if (!empty($for)) {
         $for = explode('/', $for);
         $tree = static::nested($tree, $for)['children'];
     }
     return array_filter($tree);
 }
Beispiel #2
0
 /**
  * Redirect to given url
  *
  * @param string $url       relative path or full url
  * @param array  $params    associative array of query parameters
  * @param array  $flashData associative array of properties to be set in $_SESSION for one time use
  * @param int    $status    http status code to send the response with ideally 301 or 302
  *
  * @return array
  */
 public static function to($url, array $params = array(), array $flashData = array(), $status = 302)
 {
     $url = ltrim($url, '/');
     /** @var $r Restler */
     $r = Scope::get('Restler');
     $base = $r->getBaseUrl() . '/';
     if (0 !== strpos($url, 'http')) {
         $url = $base . $url;
     }
     if (!empty($flashData) || $base . $r->url !== $url || Util::getRequestMethod() != 'GET') {
         if ($r->responseFormat instanceof JsonFormat) {
             return array('redirect' => $url);
         }
         if (!empty($params)) {
             $url .= '?' . http_build_query($params);
         }
         Flash::set($flashData);
         header("{$_SERVER['SERVER_PROTOCOL']} {$status} " . (isset(RestException::$codes[$status]) ? RestException::$codes[$status] : ''));
         header("Location: {$url}");
         die('');
     }
     return array();
 }
 /**
  * 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];
 }
Beispiel #4
0
 public function getStages()
 {
     $e = Scope::get('Restler')->getEvents();
     $i = array_search($this->stage, $e);
     return array('success' => array_slice($e, 0, $i), 'failure' => array_slice($e, $i));
 }
Beispiel #5
0
 /**
  * Maximum api version supported by the api class
  * @return int
  */
 public static function __getMaximumSupportedVersion()
 {
     return Scope::get('Restler')->getApiVersion();
 }
Beispiel #6
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];
 }
Beispiel #7
0
 /**
  * post call
  *
  * call _post_{methodName}_{extension} if exists with the composed and
  * serialized (applying the repose format) response data
  *
  * @example _post_get_json
  */
 protected function postCall()
 {
     $o =& $this->apiMethodInfo;
     $postCall = '_post_' . $o->methodName . '_' . $this->responseFormat->getExtension();
     if (method_exists($o->className, $postCall)) {
         $this->dispatch('postCall');
         $this->responseData = call_user_func(array(Scope::get($o->className), $postCall), $this->responseData);
     }
 }
Beispiel #8
0
 /**
  * Get the form key
  *
  * @param string $method   http method for form key
  * @param string $action   relative path from the web root. When set to null
  *                         it uses the current api method's path
  *
  * @return string generated form key
  */
 public static function key($method = 'POST', $action = null)
 {
     if (is_null($action)) {
         $action = Scope::get('Restler')->url;
     }
     $target = "{$method} {$action}";
     if (empty(static::$key[$target])) {
         static::$key[$target] = md5($target . User::getIpAddress() . uniqid(mt_rand()));
     }
     $_SESSION[static::FORM_KEY] = static::$key;
     return static::$key[$target];
 }
Beispiel #9
0
 public static function blade(array $data, $debug = true)
 {
     $resolver = new EngineResolver();
     $files = new Filesystem();
     $compiler = new BladeCompiler($files, static::$cacheDirectory);
     $engine = new CompilerEngine($compiler);
     $resolver->register('blade', function () use($engine) {
         return $engine;
     });
     /** @var Restler $restler */
     $restler = Scope::get('Restler');
     //Lets expose shortcuts for our classes
     spl_autoload_register(function ($className) use($restler) {
         if (isset($restler->apiMethodInfo->metadata['scope'][$className])) {
             return class_alias($restler->apiMethodInfo->metadata['scope'][$className], $className);
         }
         if (isset(Scope::$classAliases[$className])) {
             return class_alias(Scope::$classAliases[$className], $className);
         }
         return false;
     }, true, true);
     $viewFinder = new FileViewFinder($files, array(static::$viewPath));
     $factory = new Factory($resolver, $viewFinder, new Dispatcher());
     $path = $viewFinder->find(self::$view);
     $view = new View($factory, $engine, self::$view, $path, $data);
     $factory->callCreator($view);
     return $view->render();
 }
Beispiel #10
0
 /**
  * Validate the given input
  *
  * Validates the input and attempts to fix it when fix is requested
  *
  * @param mixed          $input
  * @param ValidationInfo $info
  * @param null           $full
  *
  * @throws \Exception
  * @return array|bool|float|int|mixed|null|number|string
  */
 public static function validate($input, ValidationInfo $info, $full = null)
 {
     $html = Scope::get('Restler')->responseFormat instanceof HtmlFormat;
     $name = $html ? "<strong>{$info->label}</strong>" : "`{$info->name}`";
     try {
         if (is_null($input)) {
             if ($info->required) {
                 throw new RestException(400, "{$name} is required.");
             }
             return null;
         }
         $error = isset($info->message) ? $info->message : "Invalid value specified for {$name}";
         //if a validation method is specified
         if (!empty($info->method)) {
             $method = $info->method;
             $info->method = '';
             $r = self::validate($input, $info);
             return $info->apiClassInstance->{$method}($r);
         }
         // when type is an array check if it passes for any type
         if (is_array($info->type)) {
             //trace("types are ".print_r($info->type, true));
             $types = $info->type;
             foreach ($types as $type) {
                 $info->type = $type;
                 try {
                     $r = self::validate($input, $info);
                     if ($r !== false) {
                         return $r;
                     }
                 } catch (RestException $e) {
                     // just continue
                 }
             }
             throw new RestException(400, $error);
         }
         //patterns are supported only for non numeric types
         if (isset($info->pattern) && $info->type != 'int' && $info->type != 'float' && $info->type != 'number') {
             if (!preg_match($info->pattern, $input)) {
                 throw new RestException(400, $error);
             }
         }
         if (isset($info->choice)) {
             if (is_array($input)) {
                 foreach ($input as $i) {
                     if (!in_array($i, $info->choice)) {
                         $error .= ". Expected one of (" . implode(',', $info->choice) . ").";
                         throw new RestException(400, $error);
                     }
                 }
             } elseif (!in_array($input, $info->choice)) {
                 $error .= ". Expected one of (" . implode(',', $info->choice) . ").";
                 throw new RestException(400, $error);
             }
         }
         if (method_exists($class = get_called_class(), $info->type) && $info->type != 'validate') {
             try {
                 return call_user_func("{$class}::{$info->type}", $input, $info);
             } catch (Invalid $e) {
                 throw new RestException(400, $error . '. ' . $e->getMessage());
             }
         }
         switch ($info->type) {
             case 'int':
             case 'float':
             case 'number':
                 if (!is_numeric($input)) {
                     $error .= '. Expecting ' . ($info->type == 'int' ? 'integer' : 'numeric') . ' value';
                     break;
                 }
                 if ($info->type == 'int' && (int) $input != $input) {
                     if ($info->fix) {
                         $r = (int) $input;
                     } else {
                         $error .= '. Expecting integer value';
                         break;
                     }
                 } else {
                     $r = $info->numericValue($input);
                 }
                 if (isset($info->min) && $r < $info->min) {
                     if ($info->fix) {
                         $r = $info->min;
                     } else {
                         $error .= ". Minimum required value is {$info->min}.";
                         break;
                     }
                 }
                 if (isset($info->max) && $r > $info->max) {
                     if ($info->fix) {
                         $r = $info->max;
                     } else {
                         $error .= ". Maximum allowed value is {$info->max}.";
                         break;
                     }
                 }
                 return $r;
             case 'string':
                 if (!is_string($input)) {
                     $error .= '. Expecting alpha numeric value';
                     break;
                 }
                 if ($info->required && $input === '') {
                     $error = "{$name} is required.";
                     break;
                 }
                 $r = strlen($input);
                 if (isset($info->min) && $r < $info->min) {
                     if ($info->fix) {
                         $input = str_pad($input, $info->min, $input);
                     } else {
                         $char = $info->min > 1 ? 'characters' : 'character';
                         $error .= ". Minimum {$info->min} {$char} required.";
                         break;
                     }
                 }
                 if (isset($info->max) && $r > $info->max) {
                     if ($info->fix) {
                         $input = substr($input, 0, $info->max);
                     } else {
                         $char = $info->max > 1 ? 'characters' : 'character';
                         $error .= ". Maximum {$info->max} {$char} allowed.";
                         break;
                     }
                 }
                 return $input;
             case 'bool':
             case 'boolean':
                 if ($input === 'true' || $input === true) {
                     return true;
                 }
                 if (is_numeric($input)) {
                     return $input > 0;
                 }
                 return false;
             case 'array':
                 if ($info->fix && is_string($input)) {
                     $input = explode(CommentParser::$arrayDelimiter, $input);
                 }
                 if (is_array($input)) {
                     $contentType = Util::nestedValue($info, 'contentType') ?: null;
                     if ($info->fix) {
                         if ($contentType == 'indexed') {
                             $input = $info->filterArray($input, true);
                         } elseif ($contentType == 'associative') {
                             $input = $info->filterArray($input, true);
                         }
                     } elseif ($contentType == 'indexed' && array_values($input) != $input) {
                         $error .= '. Expecting a list of items but an item is given';
                         break;
                     } elseif ($contentType == 'associative' && array_values($input) == $input && count($input)) {
                         $error .= '. Expecting an item but a list is given';
                         break;
                     }
                     $r = count($input);
                     if (isset($info->min) && $r < $info->min) {
                         $item = $info->max > 1 ? 'items' : 'item';
                         $error .= ". Minimum {$info->min} {$item} required.";
                         break;
                     }
                     if (isset($info->max) && $r > $info->max) {
                         if ($info->fix) {
                             $input = array_slice($input, 0, $info->max);
                         } else {
                             $item = $info->max > 1 ? 'items' : 'item';
                             $error .= ". Maximum {$info->max} {$item} allowed.";
                             break;
                         }
                     }
                     if (isset($contentType) && $contentType != 'associative' && $contentType != 'indexed') {
                         $name = $info->name;
                         $info->type = $contentType;
                         unset($info->contentType);
                         foreach ($input as $key => $chinput) {
                             $info->name = "{$name}[{$key}]";
                             $input[$key] = static::validate($chinput, $info);
                         }
                     }
                     return $input;
                 } elseif (isset($contentType)) {
                     $error .= '. Expecting items of type ' . ($html ? "<strong>{$contentType}</strong>" : "`{$contentType}`");
                     break;
                 }
                 break;
             case 'mixed':
             case 'unknown_type':
             case 'unknown':
             case null:
                 //treat as unknown
                 return $input;
             default:
                 if (!is_array($input)) {
                     break;
                 }
                 //do type conversion
                 if (class_exists($info->type)) {
                     $input = $info->filterArray($input, false);
                     $implements = class_implements($info->type);
                     if (is_array($implements) && in_array('Luracast\\Restler\\Data\\iValueObject', $implements)) {
                         return call_user_func("{$info->type}::__set_state", $input);
                     }
                     $class = $info->type;
                     $instance = new $class();
                     if (is_array($info->children)) {
                         if (empty($input) || !is_array($input) || $input === array_values($input)) {
                             $error .= '. Expecting an item of type ' . ($html ? "<strong>{$info->type}</strong>" : "`{$info->type}`");
                             break;
                         }
                         foreach ($info->children as $key => $value) {
                             $cv = new ValidationInfo($value);
                             if (array_key_exists($key, $input) || $cv->required) {
                                 $instance->{$key} = static::validate(Util::nestedValue($input, $key), $cv);
                             }
                         }
                     }
                     return $instance;
                 }
         }
         throw new RestException(400, $error);
     } catch (\Exception $e) {
         static::$exceptions[] = $e;
         if (static::$holdException) {
             return null;
         }
         throw $e;
     }
 }
Beispiel #11
0
 public static function get($for = '', $activeUrl = null)
 {
     if (!static::$accessControlFunction && Defaults::$accessControlFunction) {
         static::$accessControlFunction = Defaults::$accessControlFunction;
     }
     /** @var Restler $restler */
     $restler = Scope::get('Restler');
     if (static::$addExtension) {
         static::$extension = '.' . $restler->responseFormat->getExtension();
     }
     if (is_null($activeUrl)) {
         $activeUrl = $restler->url;
     }
     $tree = array();
     foreach (static::$prepends as $path => $text) {
         $url = null;
         if (is_array($text)) {
             if (isset($text['url'])) {
                 $url = $text['url'];
                 $text = $text['text'];
             } else {
                 $url = current(array_keys($text));
                 $text = current($text);
             }
         }
         if (is_numeric($path)) {
             $path = $text;
             $text = null;
         }
         if (empty($for) || 0 === strpos($path, "{$for}/")) {
             static::build($tree, $path, $url, $text, $activeUrl);
         }
     }
     $routes = Routes::toArray();
     $routes = $routes['v' . $restler->getRequestedApiVersion()];
     foreach ($routes as $value) {
         foreach ($value as $httpMethod => $route) {
             if ($httpMethod != 'GET') {
                 continue;
             }
             $path = $route['url'];
             if (false !== strpos($path, '{')) {
                 continue;
             }
             if ($route['accessLevel'] > 1 && !Util::$restler->_authenticated) {
                 continue;
             }
             foreach (static::$excludedPaths as $exclude) {
                 if (empty($exclude)) {
                     if (empty($path)) {
                         continue 2;
                     }
                 } elseif (0 === strpos($path, $exclude)) {
                     continue 2;
                 }
             }
             if ($restler->_authenticated && static::$accessControlFunction && !call_user_func(static::$accessControlFunction, $route['metadata'])) {
                 continue;
             }
             $text = Util::nestedValue($route, 'metadata', CommentParser::$embeddedDataName, 'label');
             if (empty($for) || 0 === strpos($path, "{$for}/")) {
                 static::build($tree, $path, null, $text, $activeUrl);
             }
         }
     }
     foreach (static::$appends as $path => $text) {
         $url = null;
         if (is_array($text)) {
             if (isset($text['url'])) {
                 $url = $text['url'];
                 $text = $text['text'];
             } else {
                 $url = current(array_keys($text));
                 $text = current($text);
             }
         }
         if (is_numeric($path)) {
             $path = $text;
             $text = null;
         }
         if (empty($for) || 0 === strpos($path, "{$for}/")) {
             static::build($tree, $path, $url, $text, $activeUrl);
         }
     }
     if (!empty($for)) {
         $for = explode('/', $for);
         $p =& $tree;
         foreach ($for as $f) {
             if (isset($p[$f]['children'])) {
                 $p =& $p[$f]['children'];
             } else {
                 return array();
             }
         }
         return $p;
     }
     return $tree;
 }