private function operation($route) { $r = new stdClass(); $r->method = $route['httpMethod']; $r->nickname = $this->nickname($route); $r->parameters = $this->parameters($route); $m = $route['metadata']; $r->summary = isset($m['description']) ? $m['description'] : ''; $r->summary .= $route['accessLevel'] > 2 ? static::$apiDescriptionSuffixSymbols[2] : static::$apiDescriptionSuffixSymbols[$route['accessLevel']]; $r->notes = isset($m['longDescription']) ? $m['longDescription'] : ''; $r->responseMessages = $this->responseMessages($route); $this->setType($r, new ValidationInfo(Util::nestedValue($m, 'return') ?: array())); if (is_null($r->type) || 'mixed' == $r->type) { $r->type = 'array'; } elseif ($r->type == 'null') { $r->type = 'void'; } elseif (Text::contains($r->type, '|')) { $r->type = 'array'; } //TODO: add $r->authorizations //A list of authorizations required to execute this operation. While not mandatory, if used, it overrides //the value given at the API Declaration's authorizations. In order to completely remove API Declaration's //authorizations completely, an empty object ({}) may be applied. //TODO: add $r->produces //TODO: add $r->consumes //A list of MIME types this operation can produce/consume. This is overrides the global produces definition at the root of the API Declaration. Each string value SHOULD represent a MIME type. //TODO: add $r->deprecated //Declares this operation to be deprecated. Usage of the declared operation should be refrained. Valid value MUST be either "true" or "false". Note: This field will change to type boolean in the future. 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') ?: []; } 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]; }
/** * ============ json array =================== * @Given /^the response contains (\[[^]]*\])$/ * * ============ json object ================== * @Given /^the response contains (\{(?>[^\{\}]+|(?1))*\})$/ * * ============ json string ================== * @Given /^the response contains ("[^"]*")$/ * * ============ json int ===================== * @Given /^the response contains ([-+]?[0-9]*\.?[0-9]+)$/ * * ============ json null or boolean ========= * @Given /^the response contains (null|true|false)$/ */ public function theResponseContains($response) { $data = json_encode($this->_data); if (!Text::contains($data, $response)) { throw new Exception("Response value does not contain '{$response}' only\n\n" . $this->echoLastResponse()); } }
public static function build(array $r) { $p =& static::$tree; $parts = $r['parts']; $last = count($parts) - 1; foreach ($parts as $i => $part) { if ($i == $last) { $p[$part]['text'] = $r['label']; $p[$part]['href'] = $r['url']; $p[$part]['class'] = Text::slug($part); /* dynamically do it at run time instead if ($r['path'] == static::$activeTrail) $p[$part]['active'] = true; */ } elseif (!isset($p[$part])) { $p[$part] = array(); $p[$part]['text'] = Text::title($part); $p[$part]['href'] = '#'; $p[$part]['children'] = array(); } $p =& $p[$part]['children']; } }
private function formatVar(array $value) { $r = array(); $data = array_shift($value); if (empty($data)) { $r['type'] = 'mixed'; } elseif ($data[0] == '$') { $r['name'] = substr($data, 1); $r['type'] = 'mixed'; } else { $data = explode('|', $data); $r['type'] = count($data) == 1 ? $data[0] : $data; } if (isset($r['type']) && Text::endsWith($r['type'], '[]')) { $r[static::$embeddedDataName]['type'] = substr($r['type'], 0, -2); $r['type'] = 'array'; } if ($value) { $r['description'] = implode(' ', $value); } return $r; }
/** * Access verification method. * * API access will be denied when this method returns false * * @return boolean true when api access is allowed false otherwise * * @throws RestException 403 security violation */ public function __isAllowed() { if (session_id() == '') { session_start(); } /** @var Restler $restler */ $restler = $this->restler; $url = $restler->url; foreach (static::$excludedPaths as $exclude) { if (empty($exclude)) { if ($url == $exclude) { return true; } } elseif (Text::beginsWith($url, $exclude)) { return true; } } $check = static::$filterFormRequestsOnly ? $restler->requestFormat instanceof UrlEncodedFormat || $restler->requestFormat instanceof UploadFormat : true; if (!empty($_POST) && $check) { if (isset($_POST[static::FORM_KEY]) && ($target = Util::getRequestMethod() . ' ' . $restler->url) && isset($_SESSION[static::FORM_KEY][$target]) && $_POST[static::FORM_KEY] == $_SESSION[static::FORM_KEY][$target]) { return true; } throw new RestException(403, 'Insecure form submission'); } return true; }
protected function _mapResources(array $allRoutes, array &$map, $version = 1) { foreach ($allRoutes as $fullPath => $routes) { $path = explode('/', $fullPath); $resource = isset($path[0]) ? $path[0] : ''; if ($resource == 'resources' || Text::endsWith($resource, 'index')) { continue; } foreach ($routes as $httpMethod => $route) { if (in_array($httpMethod, static::$excludedHttpMethods)) { continue; } if (!static::verifyAccess($route)) { continue; } foreach (static::$excludedPaths as $exclude) { if (empty($exclude)) { if ($fullPath == $exclude) { continue 2; } } elseif (Text::beginsWith($fullPath, $exclude)) { continue 2; } } $res = $resource ? $version == 1 ? "/resources/{$resource}" : "/v{$version}/resources/{$resource}-v{$version}" : ($version == 1 ? "/resources/root" : "/v{$version}/resources/root-v{$version}"); if (empty($map[$res])) { $map[$res] = isset($route['metadata']['classDescription']) ? $route['metadata']['classDescription'] : ''; } } } }