Update Restler to 3.0.0RC6
This commit is contained in:
parent
2d558174f2
commit
b60389cec4
@ -13,7 +13,7 @@ use Luracast\Restler\iCache;
|
||||
* @copyright 2013 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
class ApcCache implements iCache
|
||||
{
|
||||
|
||||
@ -12,7 +12,7 @@ namespace Luracast\Restler {
|
||||
* @subpackage helper
|
||||
* @author Nick Lombard <github@jigsoft.co.za>
|
||||
* @copyright 2012 Luracast
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
class AutoLoader
|
||||
{
|
||||
@ -301,8 +301,6 @@ class AutoLoader
|
||||
*/
|
||||
private function alias($className, $currentClass)
|
||||
{
|
||||
if ($className == 'Luracast\Restler\string') return;
|
||||
if ($className == 'Luracast\Restler\mixed') return;
|
||||
if ($className != $currentClass
|
||||
&& false !== strpos($className, $currentClass))
|
||||
if (!class_exists($currentClass, false)
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
namespace Luracast\Restler;
|
||||
|
||||
use Exception;
|
||||
use Luracast\Restler\Data\Text;
|
||||
|
||||
/**
|
||||
* Parses the PHPDoc comments for metadata. Inspired by `Documentor` code base.
|
||||
@ -13,7 +14,7 @@ use Exception;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
class CommentParser
|
||||
{
|
||||
@ -50,6 +51,15 @@ class CommentParser
|
||||
*/
|
||||
public static $arrayDelimiter = ',';
|
||||
|
||||
/**
|
||||
* @var array annotations that support array value
|
||||
*/
|
||||
public static $allowsArrayValue = array(
|
||||
'choice' => true,
|
||||
'select' => true,
|
||||
'properties' => true,
|
||||
);
|
||||
|
||||
/**
|
||||
* character sequence used to escape \@
|
||||
*/
|
||||
@ -195,7 +205,7 @@ class CommentParser
|
||||
list(, $param, $value) = preg_split('/\@|\s/', $line, 3)
|
||||
+ array('', '', '');
|
||||
list($value, $embedded) = $this->parseEmbeddedData($value);
|
||||
$value = array_filter(preg_split('/\s+/msu', $value));
|
||||
$value = array_filter(preg_split('/\s+/msu', $value), 'strlen');
|
||||
$this->parseParam($param, $value, $embedded);
|
||||
}
|
||||
return $this->_data;
|
||||
@ -214,6 +224,9 @@ class CommentParser
|
||||
$allowMultiple = false;
|
||||
switch ($param) {
|
||||
case 'param' :
|
||||
case 'property' :
|
||||
case 'property-read' :
|
||||
case 'property-write' :
|
||||
$value = $this->formatParam($value);
|
||||
$allowMultiple = true;
|
||||
break;
|
||||
@ -280,7 +293,12 @@ class CommentParser
|
||||
$value[self::$embeddedDataName]
|
||||
+= $data[$param][self::$embeddedDataName];
|
||||
}
|
||||
$data[$param] = $value + $data[$param];
|
||||
if (!is_array($data[$param])) {
|
||||
$data[$param] = array('description' => (string) $data[$param]);
|
||||
}
|
||||
if (is_array($value)) {
|
||||
$data[$param] = $value + $data[$param];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -303,14 +321,15 @@ class CommentParser
|
||||
}
|
||||
while (preg_match('/{@(\w+)\s?([^}]*)}/ms', $subject, $matches)) {
|
||||
$subject = str_replace($matches[0], '', $subject);
|
||||
if ($matches[2] == 'true' || $matches[2] == 'false') {
|
||||
if ($matches[1] == 'pattern') {
|
||||
throw new Exception('Inline pattern tag should follow {@pattern /REGEX_PATTERN_HERE/} format and can optionally include PCRE modifiers following the ending `/`');
|
||||
} elseif (isset(static::$allowsArrayValue[$matches[1]])) {
|
||||
$matches[2] = explode(static::$arrayDelimiter, $matches[2]);
|
||||
} elseif ($matches[2] == 'true' || $matches[2] == 'false') {
|
||||
$matches[2] = $matches[2] == 'true';
|
||||
} elseif ($matches[2] == '') {
|
||||
$matches[2] = true;
|
||||
}
|
||||
if ($matches[1] == 'pattern') {
|
||||
throw new Exception('Inline pattern tag should follow {@pattern /REGEX_PATTERN_HERE/} format and can optionally include PCRE modifiers following the ending `/`');
|
||||
} elseif (false !== strpos($matches[2], static::$arrayDelimiter)) {
|
||||
} elseif ($matches[1] == 'required') {
|
||||
$matches[2] = explode(static::$arrayDelimiter, $matches[2]);
|
||||
}
|
||||
$data[$matches[1]] = $matches[2];
|
||||
@ -376,12 +395,36 @@ class CommentParser
|
||||
|
||||
private function formatThrows(array $value)
|
||||
{
|
||||
$r = array();
|
||||
$r['code'] = count($value) && is_numeric($value[0])
|
||||
? intval(array_shift($value)) : 500;
|
||||
$reason = implode(' ', $value);
|
||||
$r['reason'] = empty($reason) ? '' : $reason;
|
||||
return $r;
|
||||
$code = 500;
|
||||
$exception = 'Exception';
|
||||
if(count($value)>1){
|
||||
$v1 = $value[0];
|
||||
$v2 = $value[1];
|
||||
if(is_numeric($v1)){
|
||||
$code = $v1;
|
||||
$exception = $v2;
|
||||
array_shift($value);
|
||||
array_shift($value);
|
||||
} elseif(is_numeric($v2)){
|
||||
$code = $v2;
|
||||
$exception = $v1;
|
||||
array_shift($value);
|
||||
array_shift($value);
|
||||
} else {
|
||||
$exception = $v1;
|
||||
array_shift($value);
|
||||
}
|
||||
} elseif(count($value) && is_numeric($value[0])) {
|
||||
$code = $value[0];
|
||||
array_shift($value);
|
||||
}
|
||||
$message = implode(' ', $value);
|
||||
if(!isset(RestException::$codes[$code])){
|
||||
$code = 500;
|
||||
} elseif(empty($message)){
|
||||
$message = RestException::$codes[$code];
|
||||
}
|
||||
return compact('code','message','exception');
|
||||
}
|
||||
|
||||
private function formatClass(array $value)
|
||||
@ -439,6 +482,10 @@ class CommentParser
|
||||
$r['name'] = substr($data, 1);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
@ -458,6 +505,10 @@ class CommentParser
|
||||
$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);
|
||||
}
|
||||
|
||||
@ -11,6 +11,7 @@ namespace Luracast\Restler;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
class Compose implements iCompose
|
||||
{
|
||||
|
||||
@ -11,7 +11,7 @@ namespace Luracast\Restler\Data;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
class ApiMethodInfo extends ValueObject
|
||||
{
|
||||
|
||||
@ -10,6 +10,7 @@ namespace Luracast\Restler\Data;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
class Arr
|
||||
{
|
||||
|
||||
@ -12,7 +12,7 @@ use Exception;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
class Invalid extends Exception
|
||||
{
|
||||
|
||||
@ -11,7 +11,7 @@ namespace Luracast\Restler\Data;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
class Object
|
||||
{
|
||||
|
||||
@ -0,0 +1,96 @@
|
||||
<?php
|
||||
namespace Luracast\Restler\Data;
|
||||
|
||||
/**
|
||||
* Convenience class for String manipulation
|
||||
*
|
||||
* @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/
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
class Text
|
||||
{
|
||||
/**
|
||||
* Given haystack contains the needle or not?
|
||||
*
|
||||
* @param string $haystack
|
||||
* @param string $needle
|
||||
* @param bool $caseSensitive
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function contains($haystack, $needle, $caseSensitive = true)
|
||||
{
|
||||
if (empty($needle))
|
||||
return true;
|
||||
return $caseSensitive
|
||||
? strpos($haystack, $needle) !== false
|
||||
: stripos($haystack, $needle) !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given haystack begins with the needle or not?
|
||||
*
|
||||
* @param string $haystack
|
||||
* @param string $needle
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function beginsWith($haystack, $needle)
|
||||
{
|
||||
$length = strlen($needle);
|
||||
return (substr($haystack, 0, $length) === $needle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given haystack ends with the needle or not?
|
||||
*
|
||||
* @param string $haystack
|
||||
* @param string $needle
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function endsWith($haystack, $needle)
|
||||
{
|
||||
$length = strlen($needle);
|
||||
if ($length == 0) {
|
||||
return true;
|
||||
}
|
||||
return (substr($haystack, -$length) === $needle);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert camelCased or underscored string in to a title
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function title($name)
|
||||
{
|
||||
return
|
||||
ucwords(
|
||||
preg_replace(
|
||||
array('/(?<=[^A-Z])([A-Z])/', '/(?<=[^0-9])([0-9])/', '/([_-])/', '/[^a-zA-Z0-9\s]|\s\s+/'),
|
||||
array(' $0', ' $0', ' ', ' '),
|
||||
$name
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert given string to be used as a slug or css class
|
||||
*
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
public static function slug($name)
|
||||
{
|
||||
return preg_replace('/[^a-zA-Z]+/', '-', strtolower(strip_tags($name)));
|
||||
}
|
||||
}
|
||||
@ -15,7 +15,7 @@ use Luracast\Restler\Util;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
class ValidationInfo implements iValueObject
|
||||
{
|
||||
|
||||
@ -17,13 +17,24 @@ use Luracast\Restler\Util;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
class Validator implements iValidate
|
||||
{
|
||||
public static $holdException = false;
|
||||
public static $exceptions = array();
|
||||
|
||||
public static $preFilters = array(
|
||||
'*' => 'trim',
|
||||
//'string' => 'strip_tags',
|
||||
//'string' => 'htmlspecialchars',
|
||||
//'int' => 'abs',
|
||||
//'float' => 'abs',
|
||||
//'CustomClass' => 'MyFilterClass::custom',
|
||||
// please note that you wont get an instance
|
||||
// of CustomClass. you will get an array instead
|
||||
);
|
||||
|
||||
/**
|
||||
* Validate alphabetic characters.
|
||||
*
|
||||
@ -116,6 +127,25 @@ class Validator implements iValidate
|
||||
throw new Invalid('Expecting only hexadecimal digits.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Color specified as hexadecimals
|
||||
*
|
||||
* Check that given value contains only color.
|
||||
*
|
||||
* @param $input
|
||||
* @param ValidationInfo|null $info
|
||||
*
|
||||
* @return string
|
||||
* @throws Invalid
|
||||
*/
|
||||
public static function color($input, ValidationInfo $info = null)
|
||||
{
|
||||
if (preg_match('/^#[a-f0-9]{6}$/i', $input)) {
|
||||
return $input;
|
||||
}
|
||||
throw new Invalid('Expecting color as hexadecimal digits.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate Telephone number
|
||||
*
|
||||
@ -360,6 +390,20 @@ class Validator implements iValidate
|
||||
{
|
||||
$html = Scope::get('Restler')->responseFormat instanceof HtmlFormat;
|
||||
$name = $html ? "<strong>$info->label</strong>" : "`$info->name`";
|
||||
if (
|
||||
isset(static::$preFilters['*']) &&
|
||||
is_scalar($input) &&
|
||||
is_callable($func = static::$preFilters['*'])
|
||||
) {
|
||||
$input = $func($input);
|
||||
}
|
||||
if (
|
||||
isset(static::$preFilters[$info->type]) &&
|
||||
(is_scalar($input) || !empty($info->children)) &&
|
||||
is_callable($func = static::$preFilters[$info->type])
|
||||
) {
|
||||
$input = $func($input);
|
||||
}
|
||||
try {
|
||||
if (is_null($input)) {
|
||||
if ($info->required) {
|
||||
@ -470,6 +514,8 @@ class Validator implements iValidate
|
||||
return $r;
|
||||
|
||||
case 'string' :
|
||||
case 'password' : //password fields with string
|
||||
case 'search' : //search field with string
|
||||
if (!is_string($input)) {
|
||||
$error .= '. Expecting alpha numeric value';
|
||||
break;
|
||||
@ -602,13 +648,13 @@ class Validator implements iValidate
|
||||
}
|
||||
foreach ($info->children as $key => $value) {
|
||||
$cv = new ValidationInfo($value);
|
||||
$cv->name = "{$info->name}[$key]";
|
||||
if (array_key_exists($key, $input) || $cv->required) {
|
||||
$instance->{$key} = static::validate(
|
||||
Util::nestedValue($input, $key),
|
||||
$cv
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return $instance;
|
||||
@ -616,7 +662,7 @@ class Validator implements iValidate
|
||||
}
|
||||
throw new RestException (400, $error);
|
||||
} catch (\Exception $e) {
|
||||
static::$exceptions[] = $e;
|
||||
static::$exceptions[$info->name] = $e;
|
||||
if (static::$holdException) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -11,7 +11,7 @@ namespace Luracast\Restler\Data;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
class ValueObject implements iValueObject
|
||||
{
|
||||
|
||||
@ -10,7 +10,7 @@ namespace Luracast\Restler\Data;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
interface iValidate {
|
||||
|
||||
|
||||
@ -11,7 +11,7 @@ namespace Luracast\Restler\Data;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
interface iValueObject
|
||||
{
|
||||
|
||||
@ -15,7 +15,7 @@ use Luracast\Restler\Data\Validator;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
class Defaults
|
||||
{
|
||||
@ -166,6 +166,12 @@ class Defaults
|
||||
*/
|
||||
public static $emptyBodyForNullResponse = true;
|
||||
|
||||
/**
|
||||
* @var bool when set to true, the response will not be outputted directly into the buffer.
|
||||
* If set, Restler::handle() will return the response as a string.
|
||||
*/
|
||||
public static $returnResponse = false;
|
||||
|
||||
/**
|
||||
* @var bool enables CORS support
|
||||
*/
|
||||
|
||||
@ -9,7 +9,7 @@ namespace Luracast\Restler;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
use Closure;
|
||||
|
||||
|
||||
582
htdocs/includes/restler/framework/Luracast/Restler/Explorer.php
Normal file
582
htdocs/includes/restler/framework/Luracast/Restler/Explorer.php
Normal file
@ -0,0 +1,582 @@
|
||||
<?php
|
||||
namespace Luracast\Restler;
|
||||
|
||||
use stdClass;
|
||||
use Luracast\Restler\Data\Text;
|
||||
use Luracast\Restler\Data\ValidationInfo;
|
||||
use Luracast\Restler\Scope;
|
||||
|
||||
/**
|
||||
* Class Explorer
|
||||
*
|
||||
* @package Luracast\Restler
|
||||
*
|
||||
* @access hybrid
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
class Explorer implements iProvideMultiVersionApi
|
||||
{
|
||||
const SWAGGER_VERSION = '1.2';
|
||||
/**
|
||||
* @var bool should protected resources be shown to unauthenticated users?
|
||||
*/
|
||||
public static $hideProtected = true;
|
||||
/**
|
||||
* @var bool should we use format as extension?
|
||||
*/
|
||||
public static $useFormatAsExtension = true;
|
||||
/*
|
||||
* @var bool can we accept scalar values (string, int, float etc) as the request body?
|
||||
*/
|
||||
public static $allowScalarValueOnRequestBody = false;
|
||||
/**
|
||||
* @var array all http methods specified here will be excluded from
|
||||
* documentation
|
||||
*/
|
||||
public static $excludedHttpMethods = array('OPTIONS');
|
||||
/**
|
||||
* @var array all paths beginning with any of the following will be excluded
|
||||
* from documentation
|
||||
*/
|
||||
public static $excludedPaths = array();
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public static $placeFormatExtensionBeforeDynamicParts = true;
|
||||
/**
|
||||
* @var bool should we group all the operations with the same url or not
|
||||
*/
|
||||
public static $groupOperations = false;
|
||||
|
||||
/**
|
||||
* @var string class that holds metadata as static properties
|
||||
*/
|
||||
public static $infoClass = 'Luracast\Restler\ExplorerInfo';
|
||||
/**
|
||||
* Injected at runtime
|
||||
*
|
||||
* @var Restler instance of restler
|
||||
*/
|
||||
public $restler;
|
||||
/**
|
||||
* @var string when format is not used as the extension this property is
|
||||
* used to set the extension manually
|
||||
*/
|
||||
public $formatString = '';
|
||||
|
||||
/**
|
||||
* @var array type mapping for converting data types to JSON-Schema Draft 4
|
||||
* Which is followed by swagger 1.2 spec
|
||||
*/
|
||||
public static $dataTypeAlias = array(
|
||||
//'string' => 'string',
|
||||
'int' => 'integer',
|
||||
'number' => 'number',
|
||||
'float' => array('number', 'float'),
|
||||
'bool' => 'boolean',
|
||||
//'boolean' => 'boolean',
|
||||
//'NULL' => 'null',
|
||||
'array' => 'array',
|
||||
//'object' => 'object',
|
||||
'stdClass' => 'object',
|
||||
'mixed' => 'string',
|
||||
'date' => array('string', 'date'),
|
||||
'datetime' => array('string', 'date-time'),
|
||||
);
|
||||
|
||||
/**
|
||||
* @var array configurable symbols to differentiate public, hybrid and
|
||||
* protected api
|
||||
*/
|
||||
public static $apiDescriptionSuffixSymbols = array(
|
||||
0 => ' <i class="fa fa-lg fa-unlock-alt"></i>', //public api
|
||||
1 => ' <i class="fa fa-lg fa-adjust"></i>', //hybrid api
|
||||
2 => ' <i class="fa fa-lg fa-lock"></i>', //protected api
|
||||
);
|
||||
|
||||
protected $models = array();
|
||||
/**
|
||||
* @var bool|stdClass
|
||||
*/
|
||||
protected $_fullDataRequested = false;
|
||||
protected $crud = array(
|
||||
'POST' => 'create',
|
||||
'GET' => 'retrieve',
|
||||
'PUT' => 'update',
|
||||
'DELETE' => 'delete',
|
||||
'PATCH' => 'partial update'
|
||||
);
|
||||
protected static $prefixes = array(
|
||||
'get' => 'retrieve',
|
||||
'index' => 'list',
|
||||
'post' => 'create',
|
||||
'put' => 'update',
|
||||
'patch' => 'modify',
|
||||
'delete' => 'remove',
|
||||
);
|
||||
protected $_authenticated = false;
|
||||
protected $cacheName = '';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Serve static files for exploring
|
||||
*
|
||||
* Serves explorer html, css, and js files
|
||||
*
|
||||
* @url GET *
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
if (func_num_args() > 1 && func_get_arg(0) == 'resources') {
|
||||
/**
|
||||
* BUGFIX:
|
||||
* If we use common resourcePath (e.g. $r->addAPIClass([api-class], 'api/shop')), than we must determine resource-ID of e.g. 'api/shop'!
|
||||
*/
|
||||
$arguments = func_get_args();
|
||||
// remove first entry
|
||||
array_shift($arguments);
|
||||
// create ID
|
||||
$id = implode('/', $arguments);
|
||||
return $this->getResources($id);
|
||||
}
|
||||
$filename = implode('/', func_get_args());
|
||||
$redirect = false;
|
||||
if (
|
||||
(empty($filename) && substr($_SERVER['REQUEST_URI'], -1, 1) != '/') ||
|
||||
$filename == 'index.html'
|
||||
) {
|
||||
$status = 302;
|
||||
$url = $this->restler->getBaseUrl() . '/' . $this->base() . '/';
|
||||
header("{$_SERVER['SERVER_PROTOCOL']} $status " . RestException::$codes[$status]);
|
||||
header("Location: $url");
|
||||
exit;
|
||||
}
|
||||
if (
|
||||
isset($this->restler->responseFormat) &&
|
||||
$this->restler->responseFormat->getExtension() == 'js'
|
||||
) {
|
||||
$filename .= '.js';
|
||||
}
|
||||
PassThrough::file(__DIR__ . '/explorer/' . (empty($filename) ? 'index.html' : $filename), false, 0); //60 * 60 * 24);
|
||||
}
|
||||
|
||||
public function resources()
|
||||
{
|
||||
$r = new stdClass();
|
||||
$r->apiVersion = (string)$this->restler->getRequestedApiVersion();
|
||||
$r->swaggerVersion = static::SWAGGER_VERSION;
|
||||
$r->apis = $this->apis($r->apiVersion);
|
||||
$r->authorizations = $this->authorizations();
|
||||
$r->info = array_filter(get_class_vars(static::$infoClass));
|
||||
return $r;
|
||||
}
|
||||
|
||||
public function getResources($id)
|
||||
{
|
||||
$r = new stdClass();
|
||||
$r->apiVersion = (string)$this->restler->getRequestedApiVersion();
|
||||
$r->swaggerVersion = static::SWAGGER_VERSION;
|
||||
$r->basePath = $this->restler->getBaseUrl();
|
||||
$r->resourcePath = "/$id";
|
||||
|
||||
$r->apis = $this->apis($r->apiVersion, $id);
|
||||
$r->models = (object)$this->models;
|
||||
|
||||
$r->produces = $this->restler->getWritableMimeTypes();
|
||||
$r->consumes = $this->restler->getReadableMimeTypes();
|
||||
$r->authorizations = $this->authorizations();
|
||||
return $r;
|
||||
}
|
||||
|
||||
private function apis($version = 1, $resource = false)
|
||||
{
|
||||
$map = Routes::findAll(static::$excludedPaths + array($this->base()), static::$excludedHttpMethods, $version);
|
||||
$r = array();
|
||||
$a = array();
|
||||
foreach ($map as $path => $data) {
|
||||
$route = $data[0]['route'];
|
||||
$access = $data[0]['access'];
|
||||
if ($access && !Text::contains($path, '{')) {
|
||||
$r[] = array(
|
||||
'path' => empty($path) ? '/root' : "/$path",
|
||||
//'description' => ''
|
||||
//TODO: Util::nestedValue($route, 'metadata', 'classDescription') ? : ''
|
||||
);
|
||||
}
|
||||
if (static::$hideProtected && !$access)
|
||||
continue;
|
||||
$grouper = array();
|
||||
foreach ($data as $item) {
|
||||
$route = $item['route'];
|
||||
$access = $item['access'];
|
||||
if (static::$hideProtected && !$access)
|
||||
continue;
|
||||
$url = $route['url'];
|
||||
if (isset($grouper[$url])) {
|
||||
$grouper[$url]['operations'][] = $this->operation($route);
|
||||
} else {
|
||||
$api = array(
|
||||
'path' => "/$url",
|
||||
'description' =>
|
||||
Util::nestedValue($route, 'metadata', 'classDescription') ? : '',
|
||||
'operations' => array($this->operation($route))
|
||||
);
|
||||
static::$groupOperations
|
||||
? $grouper[$url] = $api
|
||||
: $a[$path][] = $api;
|
||||
}
|
||||
}
|
||||
if (!empty($grouper)) {
|
||||
$a[$path] = array_values($grouper);
|
||||
// sort REST-endpoints by path
|
||||
foreach ($a as & $b) {
|
||||
usort(
|
||||
$b,
|
||||
function ($x, $y) {
|
||||
return $x['path'] > $y['path'];
|
||||
}
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$order = array(
|
||||
'GET' => 1,
|
||||
'POST' => 2,
|
||||
'PUT' => 3,
|
||||
'PATCH' => 4,
|
||||
'DELETE' => 5
|
||||
);
|
||||
foreach ($a as & $b) {
|
||||
usort(
|
||||
$b,
|
||||
function ($x, $y) use ($order) {
|
||||
return
|
||||
$x['operations'][0]->method ==
|
||||
$y['operations'][0]->method
|
||||
? $x['path'] > $y['path']
|
||||
: $order[$x['operations'][0]->method] >
|
||||
$order[$y['operations'][0]->method];
|
||||
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (false !== $resource) {
|
||||
if ($resource == 'root') $resource = '';
|
||||
if (isset($a[$resource])) return $a[$resource];
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private function parameters(array $route)
|
||||
{
|
||||
$r = array();
|
||||
$children = array();
|
||||
$required = false;
|
||||
foreach ($route['metadata']['param'] as $param) {
|
||||
$info = new ValidationInfo($param);
|
||||
$description = isset($param['description']) ? $param['description'] : '';
|
||||
if ('body' == $info->from) {
|
||||
if ($info->required)
|
||||
$required = true;
|
||||
$param['description'] = $description;
|
||||
$children[] = $param;
|
||||
} else {
|
||||
$r[] = $this->parameter($info, $description);
|
||||
}
|
||||
}
|
||||
if (!empty($children)) {
|
||||
if (
|
||||
1 == count($children) &&
|
||||
(static::$allowScalarValueOnRequestBody || !empty($children[0]['children']))
|
||||
) {
|
||||
$firstChild = $children[0];
|
||||
if (empty($firstChild['children'])) {
|
||||
$description = $firstChild['description'];
|
||||
} else {
|
||||
$description = '<section class="body-param">';
|
||||
foreach ($firstChild['children'] as $child) {
|
||||
$description .= isset($child['required']) && $child['required']
|
||||
? '<strong>' . $child['name'] . '</strong> (required)<br/>'
|
||||
: $child['name'] . '<br/>';
|
||||
}
|
||||
$description .= '</section>';
|
||||
}
|
||||
$r[] = $this->parameter(new ValidationInfo($firstChild), $description);
|
||||
} else {
|
||||
$description = '<section class="body-param">';
|
||||
foreach ($children as $child) {
|
||||
$description .= isset($child['required']) && $child['required']
|
||||
? '<strong>' . $child['name'] . '</strong> (required)<br/>'
|
||||
: $child['name'] . '<br/>';
|
||||
}
|
||||
$description .= '</section>';
|
||||
|
||||
//lets group all body parameters under a generated model name
|
||||
$name = $this->nameModel($route);
|
||||
$r[] = $this->parameter(
|
||||
new ValidationInfo(array(
|
||||
'name' => $name,
|
||||
'type' => $name,
|
||||
'from' => 'body',
|
||||
'required' => $required,
|
||||
'children' => $children
|
||||
)),
|
||||
$description
|
||||
);
|
||||
}
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
private function parameter(ValidationInfo $info, $description = '')
|
||||
{
|
||||
$p = new stdClass();
|
||||
if(isset($info->rules['model'])){
|
||||
$info->type = $info->rules['model'];
|
||||
}
|
||||
$p->name = $info->name;
|
||||
$this->setType($p, $info);
|
||||
if (empty($info->children) || $info->type != 'array') {
|
||||
//primitives
|
||||
if ($info->default)
|
||||
$p->defaultValue = $info->default;
|
||||
if ($info->choice)
|
||||
$p->enum = $info->choice;
|
||||
if ($info->min)
|
||||
$p->minimum = $info->min;
|
||||
if ($info->max)
|
||||
$p->maximum = $info->max;
|
||||
//TODO: $p->items and $p->uniqueItems boolean
|
||||
}
|
||||
$p->description = $description;
|
||||
$p->paramType = $info->from; //$info->from == 'body' ? 'form' : $info->from;
|
||||
$p->required = $info->required;
|
||||
$p->allowMultiple = false;
|
||||
return $p;
|
||||
}
|
||||
|
||||
private function responseMessages(array $route)
|
||||
{
|
||||
$r = array();
|
||||
if (is_array($throws = Util::nestedValue($route, 'metadata', 'throws'))) {
|
||||
foreach ($throws as $message) {
|
||||
$m = (object)$message;
|
||||
//TODO: add $m->responseModel from composer class
|
||||
$r[] = $m;
|
||||
}
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
private function model($type, array $children)
|
||||
{
|
||||
/**
|
||||
* Bugfix:
|
||||
* If we use namespaces, than the model will not be correct, if we use a short name for the type!
|
||||
*
|
||||
* Example (phpDoc/annotations in API-class, which uses custom domain-model with namespace):
|
||||
* @param Car $car {@from body} {@type Aoe\RestServices\Domain\Model\Car}
|
||||
* @return Car {@type Aoe\RestServices\Domain\Model\Car}
|
||||
* Than, the model (in swagger-spec) must also be 'Aoe\RestServices\Domain\Model\Car' and not 'Car'
|
||||
*
|
||||
* When we use namespaces, than we must use the @type-annotation, otherwise the automatic reconstitution
|
||||
* from request-data (e.g. when it is a POST-request) to custom domain-model-object will not work!
|
||||
*
|
||||
* Summary:
|
||||
* - When we use no namespaces, than the type would not be changed, if we would call 'Util::getShortName'
|
||||
* - When we use namespaces, than the model will not be correct, if we would call 'Util::getShortName'
|
||||
* ...so this method-call is either needless or will create a bug/error
|
||||
*/
|
||||
//$type = Util::getShortName($type);
|
||||
if (isset($this->models[$type]))
|
||||
return $this->models[$type];
|
||||
$r = new stdClass();
|
||||
$r->id = $type;
|
||||
$r->description = "$type Model"; //TODO: enhance this on Router
|
||||
$r->required = array();
|
||||
$r->properties = array();
|
||||
foreach ($children as $child) {
|
||||
$info = new ValidationInfo($child);
|
||||
$p = new stdClass();
|
||||
$this->setType($p, $info);
|
||||
$p->description = isset($child['description']) ? $child['description'] : '';
|
||||
if ($info->default)
|
||||
$p->defaultValue = $info->default;
|
||||
if ($info->choice)
|
||||
$p->enum = $info->choice;
|
||||
if ($info->min)
|
||||
$p->minimum = $info->min;
|
||||
if ($info->max)
|
||||
$p->maximum = $info->max;
|
||||
if ($info->required)
|
||||
$r->required[] = $info->name;
|
||||
$r->properties[$info->name] = $p;
|
||||
}
|
||||
//TODO: add $r->subTypes https://github.com/wordnik/swagger-spec/blob/master/versions/1.2.md#527-model-object
|
||||
//TODO: add $r->discriminator https://github.com/wordnik/swagger-spec/blob/master/versions/1.2.md#527-model-object
|
||||
$this->models[$type] = $r;
|
||||
return $r;
|
||||
}
|
||||
|
||||
private function setType(&$object, ValidationInfo $info)
|
||||
{
|
||||
//TODO: proper type management
|
||||
if ($info->type == 'array') {
|
||||
if ($info->children) {
|
||||
$this->model($info->contentType, $info->children);
|
||||
$object->items = (object)array(
|
||||
'$ref' => $info->contentType
|
||||
);
|
||||
} elseif ($info->contentType && $info->contentType == 'associative') {
|
||||
unset($info->contentType);
|
||||
$this->model($info->type = 'Object', array(
|
||||
array(
|
||||
'name' => 'property',
|
||||
'type' => 'string',
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'description' => ''
|
||||
)
|
||||
));
|
||||
} elseif ($info->contentType && $info->contentType != 'indexed') {
|
||||
$object->items = (object)array(
|
||||
'type' => $info->contentType
|
||||
);
|
||||
} else {
|
||||
$object->items = (object)array(
|
||||
'type' => 'string'
|
||||
);
|
||||
}
|
||||
} elseif ($info->children) {
|
||||
$this->model($info->type, $info->children);
|
||||
} elseif (is_string($info->type) && $t = Util::nestedValue(static::$dataTypeAlias, strtolower($info->type))) {
|
||||
if (is_array($t)) {
|
||||
list($info->type, $object->format) = $t;
|
||||
} else {
|
||||
$info->type = $t;
|
||||
}
|
||||
} else {
|
||||
$info->type = 'string';
|
||||
}
|
||||
$object->type = $info->type;
|
||||
$has64bit = PHP_INT_MAX > 2147483647;
|
||||
if ($object->type == 'integer') {
|
||||
$object->format = $has64bit
|
||||
? 'int64'
|
||||
: 'int32';
|
||||
} elseif ($object->type == 'number') {
|
||||
$object->format = $has64bit
|
||||
? 'double'
|
||||
: 'float';
|
||||
}
|
||||
}
|
||||
|
||||
private function nickname(array $route)
|
||||
{
|
||||
static $hash = array();
|
||||
$method = $route['methodName'];
|
||||
if (isset(static::$prefixes[$method])) {
|
||||
$method = static::$prefixes[$method];
|
||||
} else {
|
||||
$method = str_replace(
|
||||
array_keys(static::$prefixes),
|
||||
array_values(static::$prefixes),
|
||||
$method
|
||||
);
|
||||
}
|
||||
while (isset($hash[$method]) && $route['url'] != $hash[$method]) {
|
||||
//create another one
|
||||
$method .= '_';
|
||||
}
|
||||
$hash[$method] = $route['url'];
|
||||
return $method;
|
||||
}
|
||||
|
||||
private function nameModel(array $route)
|
||||
{
|
||||
static $hash = array();
|
||||
$count = 1;
|
||||
//$name = str_replace('/', '-', $route['url']) . 'Model';
|
||||
$name = $route['className'] . 'Model';
|
||||
while (isset($hash[$name . $count])) {
|
||||
//create another one
|
||||
$count++;
|
||||
}
|
||||
$name .= $count;
|
||||
$hash[$name] = $route['url'];
|
||||
return $name;
|
||||
}
|
||||
|
||||
private function authorizations()
|
||||
{
|
||||
$r = new stdClass();
|
||||
$r->apiKey = (object)array(
|
||||
'type' => 'apiKey',
|
||||
'passAs' => 'query',
|
||||
'keyname' => 'api_key',
|
||||
);
|
||||
return $r;
|
||||
}
|
||||
|
||||
private function base()
|
||||
{
|
||||
return strtok($this->restler->url, '/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Maximum api version supported by the api class
|
||||
* @return int
|
||||
*/
|
||||
public static function __getMaximumSupportedVersion()
|
||||
{
|
||||
return Scope::get('Restler')->getApiVersion();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
<?php namespace Luracast\Restler;
|
||||
|
||||
/**
|
||||
* Class ExplorerInfo
|
||||
* @package Luracast\Restler
|
||||
*
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
class ExplorerInfo
|
||||
{
|
||||
public static $title = 'Restler API Explorer';
|
||||
public static $description = 'Live API Documentation';
|
||||
public static $termsOfServiceUrl = null;
|
||||
public static $contact = 'arul@luracast.com';
|
||||
public static $license = 'LGPL-2.1';
|
||||
public static $licenseUrl = 'https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html';
|
||||
}
|
||||
@ -15,7 +15,7 @@ use Luracast\Restler\RestException;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
class RateLimit implements iFilter, iUseAuthentication
|
||||
{
|
||||
@ -53,7 +53,7 @@ class RateLimit implements iFilter, iUseAuthentication
|
||||
* @var array all paths beginning with any of the following will be excluded
|
||||
* from documentation
|
||||
*/
|
||||
public static $excludedPaths = array('resources');
|
||||
public static $excludedPaths = array('explorer');
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
namespace Luracast\Restler;
|
||||
|
||||
use Luracast\Restler\Format\HtmlFormat;
|
||||
use ArrayAccess;
|
||||
|
||||
/**
|
||||
* Storing and retrieving a message or array of key value pairs for one time use using $_SESSION
|
||||
@ -14,9 +15,9 @@ use Luracast\Restler\Format\HtmlFormat;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
class Flash //implements \JsonSerializable
|
||||
class Flash implements ArrayAccess
|
||||
{
|
||||
const SUCCESS = 'success';
|
||||
const INFO = 'info';
|
||||
@ -104,18 +105,22 @@ class Flash //implements \JsonSerializable
|
||||
*/
|
||||
public static function set(array $data)
|
||||
{
|
||||
if (!static::$instance)
|
||||
if (!static::$instance) {
|
||||
static::$instance = new Flash();
|
||||
if (!isset($_SESSION['flash']))
|
||||
}
|
||||
if (!isset($_SESSION['flash'])) {
|
||||
$_SESSION['flash'] = array();
|
||||
}
|
||||
$_SESSION['flash'] += $data;
|
||||
HtmlFormat::$data['flash'] = static::$instance;
|
||||
|
||||
return static::$instance;
|
||||
}
|
||||
|
||||
public function __get($name)
|
||||
{
|
||||
$this->usedOnce = true;
|
||||
|
||||
return Util::nestedValue($_SESSION, 'flash', $name);
|
||||
}
|
||||
|
||||
@ -126,8 +131,9 @@ class Flash //implements \JsonSerializable
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
if ($this->usedOnce)
|
||||
if ($this->usedOnce) {
|
||||
unset($_SESSION['flash']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -139,8 +145,30 @@ class Flash //implements \JsonSerializable
|
||||
public function jsonSerialize()
|
||||
{
|
||||
$this->usedOnce = true;
|
||||
|
||||
return isset($_SESSION['flash'])
|
||||
? $_SESSION['flash']
|
||||
: array();
|
||||
}
|
||||
|
||||
|
||||
public function offsetExists($offset)
|
||||
{
|
||||
return $this->__isset($offset);
|
||||
}
|
||||
|
||||
public function offsetGet($offset)
|
||||
{
|
||||
return $this->__get($offset);
|
||||
}
|
||||
|
||||
public function offsetSet($offset, $value)
|
||||
{
|
||||
//not implemented
|
||||
}
|
||||
|
||||
public function offsetUnset($offset)
|
||||
{
|
||||
//not implemented
|
||||
}
|
||||
}
|
||||
@ -17,13 +17,16 @@ use ZendAmf\Parser\OutputStream;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
class AmfFormat extends Format
|
||||
class AmfFormat extends DependentFormat
|
||||
{
|
||||
const MIME = 'application/x-amf';
|
||||
const EXTENSION = 'amf';
|
||||
|
||||
const PACKAGE_NAME = 'zendframework/zendamf:dev-master';
|
||||
const EXTERNAL_CLASS = 'ZendAmf\\Parser\\Amf3\\Deserializer';
|
||||
|
||||
public function encode($data, $humanReadable = false)
|
||||
{
|
||||
|
||||
|
||||
@ -15,7 +15,7 @@ use Luracast\Restler\RestException;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
class CsvFormat extends Format implements iDecodeStream
|
||||
{
|
||||
|
||||
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
namespace Luracast\Restler\Format;
|
||||
|
||||
|
||||
use Luracast\Restler\RestException;
|
||||
|
||||
abstract class DependentFormat extends Format
|
||||
{
|
||||
/**
|
||||
* override in the extending class
|
||||
*
|
||||
* @example symfony/yaml:*
|
||||
*/
|
||||
const PACKAGE_NAME = 'vendor/project:version';
|
||||
|
||||
/**
|
||||
* override in the extending class
|
||||
*
|
||||
* fully qualified class name
|
||||
*/
|
||||
const EXTERNAL_CLASS = 'Namespace\\ClassName';
|
||||
|
||||
/**
|
||||
* Get external class => packagist package name as an associative array
|
||||
*
|
||||
* @return array list of dependencies for the format
|
||||
*/
|
||||
public function getDependencyMap()
|
||||
{
|
||||
return array(
|
||||
static::EXTERNAL_CLASS => static::PACKAGE_NAME
|
||||
);
|
||||
}
|
||||
|
||||
protected function checkDependency($class = null)
|
||||
{
|
||||
if (empty($class)) {
|
||||
$class = key($this->getDependencyMap());
|
||||
}
|
||||
if (!class_exists($class, true)) {
|
||||
$map = $this->getDependencyMap();
|
||||
$package = $map[$class];
|
||||
throw new RestException(
|
||||
500,
|
||||
get_called_class() . ' has external dependency. Please run `composer require ' .
|
||||
$package . '` from the project root. Read https://getcomposer.org for more info'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->checkDependency();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
namespace Luracast\Restler\Format;
|
||||
|
||||
|
||||
use Luracast\Restler\RestException;
|
||||
|
||||
abstract class DependentMultiFormat extends MultiFormat
|
||||
{
|
||||
/**
|
||||
* Get external class => packagist package name as an associative array
|
||||
*
|
||||
* @return array list of dependencies for the format
|
||||
*
|
||||
* @example return ['Illuminate\\View\\View' => 'illuminate/view:4.2.*']
|
||||
*/
|
||||
abstract public function getDependencyMap();
|
||||
|
||||
protected function checkDependency($class = null)
|
||||
{
|
||||
if (empty($class)) {
|
||||
$class = key($this->getDependencyMap());
|
||||
}
|
||||
if (!class_exists($class, true)) {
|
||||
$map = $this->getDependencyMap();
|
||||
$package = $map[$class];
|
||||
throw new RestException(
|
||||
500,
|
||||
get_called_class() . ' has external dependency. Please run `composer require ' .
|
||||
$package . '` from the project root. Read https://getcomposer.org for more info'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->checkDependency();
|
||||
}
|
||||
|
||||
}
|
||||
@ -10,7 +10,7 @@ namespace Luracast\Restler\Format;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
abstract class Format implements iFormat
|
||||
{
|
||||
|
||||
@ -6,11 +6,11 @@ use Illuminate\Events\Dispatcher;
|
||||
use Illuminate\Filesystem\Filesystem;
|
||||
use Illuminate\View\Compilers\BladeCompiler;
|
||||
use Illuminate\View\Engines\CompilerEngine;
|
||||
use Illuminate\View\Engines\PhpEngine;
|
||||
use Illuminate\View\Engines\EngineResolver;
|
||||
use Illuminate\View\Factory;
|
||||
use Illuminate\View\FileViewFinder;
|
||||
use Illuminate\View\View;
|
||||
use Luracast\Restler\Data\ApiMethodInfo;
|
||||
use Luracast\Restler\Data\Object;
|
||||
use Luracast\Restler\Defaults;
|
||||
use Luracast\Restler\RestException;
|
||||
@ -29,9 +29,9 @@ use Luracast\Restler\Util;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
class HtmlFormat extends Format
|
||||
class HtmlFormat extends DependentFormat
|
||||
{
|
||||
public static $mime = 'text/html';
|
||||
public static $extension = 'html';
|
||||
@ -39,6 +39,7 @@ class HtmlFormat extends Format
|
||||
public static $errorView = 'debug.php';
|
||||
public static $template = 'php';
|
||||
public static $handleSession = true;
|
||||
public static $convertResponseToArray = false;
|
||||
|
||||
public static $useSmartViews = true;
|
||||
/**
|
||||
@ -83,11 +84,16 @@ class HtmlFormat extends Format
|
||||
}
|
||||
}
|
||||
|
||||
public function getDependencyMap(){
|
||||
return array(
|
||||
'Illuminate\View\View' => 'illuminate/view:4.2.*',
|
||||
'Twig_Environment' => 'twig/twig:v1.13.*',
|
||||
'Mustache_Engine' => 'mustache/mustache:dev-master',
|
||||
);
|
||||
}
|
||||
|
||||
public static function blade(array $data, $debug = true)
|
||||
{
|
||||
if (!class_exists('\Illuminate\View\View', true))
|
||||
throw new RestException(500,
|
||||
'Blade templates require laravel view classes to be installed using `composer install`');
|
||||
$resolver = new EngineResolver();
|
||||
$files = new Filesystem();
|
||||
$compiler = new BladeCompiler($files, static::$cacheDirectory);
|
||||
@ -95,6 +101,10 @@ class HtmlFormat extends Format
|
||||
$resolver->register('blade', function () use ($engine) {
|
||||
return $engine;
|
||||
});
|
||||
$phpEngine = new PhpEngine();
|
||||
$resolver->register('php', function () use ($phpEngine) {
|
||||
return $phpEngine;
|
||||
});
|
||||
|
||||
/** @var Restler $restler */
|
||||
$restler = Scope::get('Restler');
|
||||
@ -109,7 +119,7 @@ class HtmlFormat extends Format
|
||||
}
|
||||
return false;
|
||||
}, true, true);
|
||||
|
||||
|
||||
$viewFinder = new FileViewFinder($files, array(static::$viewPath));
|
||||
$factory = new Factory($resolver, $viewFinder, new Dispatcher());
|
||||
$path = $viewFinder->find(self::$view);
|
||||
@ -120,9 +130,6 @@ class HtmlFormat extends Format
|
||||
|
||||
public static function twig(array $data, $debug = true)
|
||||
{
|
||||
if (!class_exists('\Twig_Environment', true))
|
||||
throw new RestException(500,
|
||||
'Twig templates require twig classes to be installed using `composer install`');
|
||||
$loader = new \Twig_Loader_Filesystem(static::$viewPath);
|
||||
$twig = new \Twig_Environment($loader, array(
|
||||
'cache' => static::$cacheDirectory,
|
||||
@ -176,27 +183,21 @@ class HtmlFormat extends Format
|
||||
|
||||
public static function mustache(array $data, $debug = true)
|
||||
{
|
||||
if (!class_exists('\Mustache_Engine', true))
|
||||
throw new RestException(
|
||||
500,
|
||||
'Mustache/Handlebar templates require mustache classes ' .
|
||||
'to be installed using `composer install`'
|
||||
);
|
||||
if (!isset($data['nav']))
|
||||
$data['nav'] = array_values(Nav::get());
|
||||
$options = array(
|
||||
'loader' => new \Mustache_Loader_FilesystemLoader(
|
||||
static::$viewPath,
|
||||
array('extension' => static::getViewExtension())
|
||||
),
|
||||
static::$viewPath,
|
||||
array('extension' => static::getViewExtension())
|
||||
),
|
||||
'helpers' => array(
|
||||
'form' => function ($text, \Mustache_LambdaHelper $m) {
|
||||
$params = explode(',', $m->render($text));
|
||||
return call_user_func_array(
|
||||
'Luracast\Restler\UI\Forms::get',
|
||||
$params
|
||||
);
|
||||
},
|
||||
$params = explode(',', $m->render($text));
|
||||
return call_user_func_array(
|
||||
'Luracast\Restler\UI\Forms::get',
|
||||
$params
|
||||
);
|
||||
},
|
||||
)
|
||||
);
|
||||
if (!$debug)
|
||||
@ -313,7 +314,9 @@ class HtmlFormat extends Format
|
||||
$success = is_null($exception);
|
||||
$error = $success ? null : $exception->getMessage();
|
||||
$data = array(
|
||||
'response' => Object::toArray($data),
|
||||
'response' => static::$convertResponseToArray
|
||||
? Object::toArray($data)
|
||||
: $data,
|
||||
'stages' => $this->restler->getEvents(),
|
||||
'success' => $success,
|
||||
'error' => $error
|
||||
@ -334,10 +337,7 @@ class HtmlFormat extends Format
|
||||
self::$view = $metadata[$view];
|
||||
}
|
||||
} elseif (!self::$view) {
|
||||
$file = static::$viewPath . '/' . $this->restler->url . '.' . static::getViewExtension();
|
||||
self::$view = static::$useSmartViews && is_readable($file)
|
||||
? $this->restler->url
|
||||
: static::$errorView;
|
||||
self::$view = static::guessViewName($this->restler->url);
|
||||
}
|
||||
if (
|
||||
isset($metadata['param'])
|
||||
@ -368,12 +368,19 @@ class HtmlFormat extends Format
|
||||
if (!static::$cacheDirectory) {
|
||||
static::$cacheDirectory = Defaults::$cacheDirectory . DIRECTORY_SEPARATOR . $template;
|
||||
if (!file_exists(static::$cacheDirectory)) {
|
||||
if (!mkdir(static::$cacheDirectory)) {
|
||||
if (!mkdir(static::$cacheDirectory, 0770, true)) {
|
||||
throw new RestException(500, 'Unable to create cache directory `' . static::$cacheDirectory . '`');
|
||||
}
|
||||
}
|
||||
}
|
||||
if (method_exists($class = get_called_class(), $template)) {
|
||||
if ($template == 'blade') {
|
||||
$this->checkDependency('Illuminate\View\View');
|
||||
} elseif ($template == 'twig') {
|
||||
$this->checkDependency('Twig_Environment');
|
||||
} elseif ($template == 'mustache' || $template == 'handlebar') {
|
||||
$this->checkDependency('Mustache_Engine');
|
||||
}
|
||||
return call_user_func("$class::$template", $data, $humanReadable);
|
||||
}
|
||||
throw new RestException(500, "Unsupported template system `$template`");
|
||||
@ -384,6 +391,20 @@ class HtmlFormat extends Format
|
||||
}
|
||||
}
|
||||
|
||||
public static function guessViewName($path)
|
||||
{
|
||||
if (empty($path)) {
|
||||
$path = 'index';
|
||||
} elseif (strpos($path, '/')) {
|
||||
$path .= '/index';
|
||||
}
|
||||
$file = static::$viewPath . '/' . $path . '.' . static::getViewExtension();
|
||||
|
||||
return static::$useSmartViews && is_readable($file)
|
||||
? $path
|
||||
: static::$errorView;
|
||||
}
|
||||
|
||||
public static function getViewExtension()
|
||||
{
|
||||
return isset(static::$customTemplateExtensions[static::$template])
|
||||
|
||||
@ -11,7 +11,7 @@ namespace Luracast\Restler\Format;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
class JsFormat extends JsonFormat
|
||||
{
|
||||
|
||||
@ -14,7 +14,7 @@ use Luracast\Restler\RestException;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
class JsonFormat extends Format
|
||||
{
|
||||
@ -57,37 +57,60 @@ class JsonFormat extends Format
|
||||
if (is_null(self::$unEscapedUnicode)) {
|
||||
self::$unEscapedUnicode = $this->charset == 'utf-8';
|
||||
}
|
||||
|
||||
$options = 0;
|
||||
|
||||
if ((PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) // PHP >= 5.4
|
||||
|| PHP_MAJOR_VERSION > 5 // PHP >= 6.0
|
||||
) {
|
||||
if ($humanReadable) $options |= JSON_PRETTY_PRINT;
|
||||
if (self::$unEscapedSlashes) $options |= JSON_UNESCAPED_SLASHES;
|
||||
if (self::$bigIntAsString) $options |= JSON_BIGINT_AS_STRING;
|
||||
if (self::$unEscapedUnicode) $options |= JSON_UNESCAPED_UNICODE;
|
||||
return json_encode(
|
||||
Object::toArray($data, true), $options
|
||||
);
|
||||
|
||||
if ($humanReadable) {
|
||||
$options |= JSON_PRETTY_PRINT;
|
||||
}
|
||||
|
||||
if (self::$unEscapedSlashes) {
|
||||
$options |= JSON_UNESCAPED_SLASHES;
|
||||
}
|
||||
|
||||
if (self::$bigIntAsString) {
|
||||
$options |= JSON_BIGINT_AS_STRING;
|
||||
}
|
||||
|
||||
if (self::$unEscapedUnicode) {
|
||||
$options |= JSON_UNESCAPED_UNICODE;
|
||||
}
|
||||
|
||||
$result = json_encode(Object::toArray($data, true), $options);
|
||||
$this->handleJsonError();
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
$result = json_encode(Object::toArray($data, true));
|
||||
if ($humanReadable) $result = $this->formatJson($result);
|
||||
if (self::$unEscapedUnicode) {
|
||||
$result = preg_replace_callback('/\\\u(\w\w\w\w)/',
|
||||
function($matches)
|
||||
{
|
||||
if (function_exists('mb_convert_encoding'))
|
||||
{
|
||||
return mb_convert_encoding(pack('H*', $matches[1]), 'UTF-8', 'UTF-16BE');
|
||||
}
|
||||
else
|
||||
{
|
||||
return iconv('UTF-16BE','UTF-8',pack('H*', $matches[1]));
|
||||
}
|
||||
}
|
||||
, $result);
|
||||
$this->handleJsonError();
|
||||
|
||||
if ($humanReadable) {
|
||||
$result = $this->formatJson($result);
|
||||
}
|
||||
if (self::$unEscapedSlashes) $result = str_replace('\/', '/', $result);
|
||||
|
||||
if (self::$unEscapedUnicode) {
|
||||
$result = preg_replace_callback(
|
||||
'/\\\u(\w\w\w\w)/',
|
||||
function ($matches) {
|
||||
if (function_exists('mb_convert_encoding')) {
|
||||
return mb_convert_encoding(pack('H*', $matches[1]), 'UTF-8', 'UTF-16BE');
|
||||
} else {
|
||||
return iconv('UTF-16BE', 'UTF-8', pack('H*', $matches[1]));
|
||||
}
|
||||
},
|
||||
$result
|
||||
);
|
||||
}
|
||||
|
||||
if (self::$unEscapedSlashes) {
|
||||
$result = str_replace('\/', '/', $result);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
@ -102,39 +125,21 @@ class JsonFormat extends Format
|
||||
} else {
|
||||
$data = preg_replace(
|
||||
'/:\s*(\-?\d+(\.\d+)?([e|E][\-|\+]\d+)?)/',
|
||||
': "$1"', $data
|
||||
': "$1"',
|
||||
$data
|
||||
);
|
||||
}
|
||||
}
|
||||
$decoded = json_decode($data, $options);
|
||||
if (function_exists('json_last_error')) {
|
||||
switch (json_last_error()) {
|
||||
case JSON_ERROR_NONE :
|
||||
return Object::toArray($decoded);
|
||||
break;
|
||||
case JSON_ERROR_DEPTH :
|
||||
$message = 'maximum stack depth exceeded';
|
||||
break;
|
||||
case JSON_ERROR_STATE_MISMATCH :
|
||||
$message = 'underflow or the modes mismatch';
|
||||
break;
|
||||
case JSON_ERROR_CTRL_CHAR :
|
||||
$message = 'unexpected control character found';
|
||||
break;
|
||||
case JSON_ERROR_SYNTAX :
|
||||
$message = 'malformed JSON';
|
||||
break;
|
||||
case JSON_ERROR_UTF8 :
|
||||
$message = 'malformed UTF-8 characters, possibly ' .
|
||||
'incorrectly encoded';
|
||||
break;
|
||||
default :
|
||||
$message = 'unknown error';
|
||||
break;
|
||||
}
|
||||
throw new RestException (400, 'Error parsing JSON, ' . $message);
|
||||
} elseif (strlen($data) && $decoded === null || $decoded === $data) {
|
||||
throw new RestException (400, 'Error parsing JSON');
|
||||
|
||||
try {
|
||||
$decoded = json_decode($data, $options);
|
||||
$this->handleJsonError();
|
||||
} catch (\RuntimeException $e) {
|
||||
throw new RestException(400, $e->getMessage());
|
||||
}
|
||||
|
||||
if (strlen($data) && $decoded === null || $decoded === $data) {
|
||||
throw new RestException(400, 'Error parsing JSON');
|
||||
}
|
||||
|
||||
return Object::toArray($decoded);
|
||||
@ -206,5 +211,52 @@ class JsonFormat extends Format
|
||||
|
||||
return $newJson;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws an exception if an error occurred during the last JSON encoding/decoding
|
||||
*
|
||||
* @return void
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
protected function handleJsonError()
|
||||
{
|
||||
if (function_exists('json_last_error_msg') && json_last_error() !== JSON_ERROR_NONE) {
|
||||
|
||||
// PHP >= 5.5.0
|
||||
|
||||
$message = json_last_error_msg();
|
||||
|
||||
} elseif (function_exists('json_last_error')) {
|
||||
|
||||
// PHP >= 5.3.0
|
||||
|
||||
switch (json_last_error()) {
|
||||
case JSON_ERROR_NONE:
|
||||
break;
|
||||
case JSON_ERROR_DEPTH:
|
||||
$message = 'maximum stack depth exceeded';
|
||||
break;
|
||||
case JSON_ERROR_STATE_MISMATCH:
|
||||
$message = 'underflow or the modes mismatch';
|
||||
break;
|
||||
case JSON_ERROR_CTRL_CHAR:
|
||||
$message = 'unexpected control character found';
|
||||
break;
|
||||
case JSON_ERROR_SYNTAX:
|
||||
$message = 'malformed JSON';
|
||||
break;
|
||||
case JSON_ERROR_UTF8:
|
||||
$message = 'malformed UTF-8 characters, possibly ' .
|
||||
'incorrectly encoded';
|
||||
break;
|
||||
default:
|
||||
$message = 'unknown error';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($message)) {
|
||||
throw new \RuntimeException('Error encoding/decoding JSON: '. $message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -9,7 +9,7 @@ namespace Luracast\Restler\Format;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
abstract class MultiFormat implements iFormat
|
||||
{
|
||||
|
||||
@ -18,9 +18,9 @@ use CFPropertyList\CFPropertyList;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
class PlistFormat extends MultiFormat
|
||||
class PlistFormat extends DependentMultiFormat
|
||||
{
|
||||
/**
|
||||
* @var boolean set it to true binary plist is preferred
|
||||
@ -81,11 +81,24 @@ class PlistFormat extends MultiFormat
|
||||
*/
|
||||
public function decode($data)
|
||||
{
|
||||
//require_once 'CFPropertyList.php';
|
||||
$plist = new CFPropertyList ();
|
||||
$plist->parse($data);
|
||||
|
||||
return $plist->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get external class => packagist package name as an associative array
|
||||
*
|
||||
* @return array list of dependencies for the format
|
||||
*
|
||||
* @example return ['Illuminate\\View\\View' => 'illuminate/view:4.2.*']
|
||||
*/
|
||||
public function getDependencyMap()
|
||||
{
|
||||
return array(
|
||||
'CFPropertyList\CFPropertyList' => 'rodneyrehm/plist:dev-master'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -11,7 +11,7 @@ namespace Luracast\Restler\Format;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
class TsvFormat extends CsvFormat
|
||||
{
|
||||
|
||||
@ -13,7 +13,7 @@ use Luracast\Restler\RestException;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
class UploadFormat extends Format
|
||||
{
|
||||
|
||||
@ -11,7 +11,7 @@ namespace Luracast\Restler\Format;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
class UrlEncodedFormat extends Format
|
||||
{
|
||||
|
||||
@ -16,7 +16,7 @@ use XMLWriter;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
class XmlFormat extends Format
|
||||
{
|
||||
@ -110,14 +110,16 @@ class XmlFormat extends Format
|
||||
foreach (static::$namespaces as $prefix => $ns) {
|
||||
if (isset(static::$namespacedProperties[static::$rootName])
|
||||
&& static::$namespacedProperties[static::$rootName] == $prefix
|
||||
)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
$prefix = 'xmlns' . (empty($prefix) ? '' : ':' . $prefix);
|
||||
$xml->writeAttribute($prefix, $ns);
|
||||
}
|
||||
}
|
||||
$this->write($xml, $data, static::$rootName);
|
||||
$xml->endElement();
|
||||
|
||||
return $xml->outputMemory();
|
||||
}
|
||||
|
||||
@ -151,30 +153,15 @@ class XmlFormat extends Format
|
||||
&& !empty(static::$namespacedProperties[$key])
|
||||
&& false === strpos($key, ':');
|
||||
if (is_array($value)) {
|
||||
if ($value == array_values($value)) {
|
||||
//numeric array, create siblings
|
||||
foreach ($value as $v) {
|
||||
$useNS
|
||||
? $xml->startElementNs(
|
||||
static::$namespacedProperties[$key],
|
||||
$key,
|
||||
null
|
||||
)
|
||||
: $xml->startElement($key);
|
||||
$this->write($xml, $v, $key);
|
||||
$xml->endElement();
|
||||
}
|
||||
} else {
|
||||
$useNS
|
||||
? $xml->startElementNs(
|
||||
static::$namespacedProperties[$key],
|
||||
$key,
|
||||
null
|
||||
)
|
||||
: $xml->startElement($key);
|
||||
$this->write($xml, $value, $key);
|
||||
$xml->endElement();
|
||||
}
|
||||
$useNS
|
||||
? $xml->startElementNs(
|
||||
static::$namespacedProperties[$key],
|
||||
$key,
|
||||
null
|
||||
)
|
||||
: $xml->startElement($key);
|
||||
$this->write($xml, $value, $key);
|
||||
$xml->endElement();
|
||||
continue;
|
||||
} elseif (is_bool($value)) {
|
||||
$value = $value ? 'true' : 'false';
|
||||
@ -217,6 +204,7 @@ class XmlFormat extends Format
|
||||
return array();
|
||||
}
|
||||
libxml_use_internal_errors(true);
|
||||
libxml_disable_entity_loader(true);
|
||||
$xml = simplexml_load_string($data,
|
||||
"SimpleXMLElement", LIBXML_NOBLANKS | LIBXML_NOCDATA | LIBXML_COMPACT);
|
||||
if (false === $xml) {
|
||||
@ -241,8 +229,10 @@ class XmlFormat extends Format
|
||||
}
|
||||
}
|
||||
$data = $this->read($xml);
|
||||
if (count($data) == 1 && isset($data[static::$textNodeName]))
|
||||
if (count($data) == 1 && isset($data[static::$textNodeName])) {
|
||||
$data = $data[static::$textNodeName];
|
||||
}
|
||||
|
||||
return $data;
|
||||
} catch (\RuntimeException $e) {
|
||||
throw new RestException(400,
|
||||
@ -268,10 +258,13 @@ class XmlFormat extends Format
|
||||
}
|
||||
$children = $xml->children();
|
||||
foreach ($children as $key => $value) {
|
||||
if (isset($r[$key])) {
|
||||
if ($key == static::$defaultTagName) {
|
||||
$r[] = $this->read($value);
|
||||
} elseif (isset($r[$key])) {
|
||||
if (is_array($r[$key])) {
|
||||
if ($r[$key] != array_values($r[$key]))
|
||||
if ($r[$key] != array_values($r[$key])) {
|
||||
$r[$key] = array($r[$key]);
|
||||
}
|
||||
} else {
|
||||
$r[$key] = array($r[$key]);
|
||||
}
|
||||
@ -282,8 +275,9 @@ class XmlFormat extends Format
|
||||
}
|
||||
|
||||
if (static::$parseNamespaces) {
|
||||
if (is_null($namespaces))
|
||||
if (is_null($namespaces)) {
|
||||
$namespaces = $xml->getDocNamespaces(true);
|
||||
}
|
||||
foreach ($namespaces as $prefix => $ns) {
|
||||
static::$namespaces[$prefix] = $ns;
|
||||
if (static::$parseAttributes) {
|
||||
@ -303,12 +297,14 @@ class XmlFormat extends Format
|
||||
}
|
||||
$children = $xml->children($ns);
|
||||
foreach ($children as $key => $value) {
|
||||
if (static::$importSettingsFromXml)
|
||||
if (static::$importSettingsFromXml) {
|
||||
static::$namespacedProperties[$key] = $prefix;
|
||||
}
|
||||
if (isset($r[$key])) {
|
||||
if (is_array($r[$key])) {
|
||||
if ($r[$key] != array_values($r[$key]))
|
||||
if ($r[$key] != array_values($r[$key])) {
|
||||
$r[$key] = array($r[$key]);
|
||||
}
|
||||
} else {
|
||||
$r[$key] = array($r[$key]);
|
||||
}
|
||||
@ -321,7 +317,9 @@ class XmlFormat extends Format
|
||||
}
|
||||
|
||||
if (empty($text) && $text !== '0') {
|
||||
if (empty($r)) return null;
|
||||
if (empty($r)) {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
empty($r)
|
||||
? $r = static::setType($text)
|
||||
@ -331,18 +329,25 @@ class XmlFormat extends Format
|
||||
: $r[] = static::setType($text)
|
||||
);
|
||||
}
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
||||
public static function setType($value)
|
||||
{
|
||||
if (empty($value) && $value !== '0')
|
||||
if (empty($value) && $value !== '0') {
|
||||
return null;
|
||||
if ($value == 'true')
|
||||
}
|
||||
if ($value == 'true') {
|
||||
return true;
|
||||
if ($value == 'false')
|
||||
}
|
||||
if ($value == 'false') {
|
||||
return true;
|
||||
}
|
||||
if (is_numeric($value)) {
|
||||
return 0 + $value;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -14,22 +14,23 @@ use Luracast\Restler\Data\Object;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
class YamlFormat extends Format
|
||||
class YamlFormat extends DependentFormat
|
||||
{
|
||||
const MIME = 'text/plain';
|
||||
const EXTENSION = 'yaml';
|
||||
|
||||
const PACKAGE_NAME = 'symfony/yaml:*';
|
||||
const EXTERNAL_CLASS = 'Symfony\Component\Yaml\Yaml';
|
||||
|
||||
public function encode($data, $humanReadable = false)
|
||||
{
|
||||
// require_once 'sfyaml.php';
|
||||
return @Yaml::dump(Object::toArray($data));
|
||||
return @Yaml::dump(Object::toArray($data), $humanReadable ? 10 : 4);
|
||||
}
|
||||
|
||||
public function decode($data)
|
||||
{
|
||||
// require_once 'sfyaml.php';
|
||||
return Yaml::parse($data);
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,7 +11,7 @@ namespace Luracast\Restler\Format;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
interface iDecodeStream
|
||||
{
|
||||
|
||||
@ -11,7 +11,7 @@ namespace Luracast\Restler\Format;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
interface iFormat
|
||||
{
|
||||
|
||||
@ -10,7 +10,7 @@ namespace Luracast\Restler;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
class HumanReadableCache implements iCache
|
||||
{
|
||||
|
||||
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
namespace Luracast\Restler;
|
||||
|
||||
/**
|
||||
* Special RestException for forcing the exception even when
|
||||
* in hybrid method
|
||||
*
|
||||
* @category Framework
|
||||
* @package Restler
|
||||
* @subpackage exception
|
||||
* @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/
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
|
||||
|
||||
class InvalidAuthCredentials extends RestException
|
||||
{
|
||||
|
||||
}
|
||||
@ -0,0 +1,140 @@
|
||||
<?php
|
||||
namespace Luracast\Restler;
|
||||
|
||||
/**
|
||||
* Class MemcacheCache provides a memcache based cache for Restler
|
||||
*
|
||||
* @category Framework
|
||||
* @package Restler
|
||||
* @author Dave Drager <ddrager@gmail.com>
|
||||
* @copyright 2014 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
*/
|
||||
class MemcacheCache implements iCache
|
||||
{
|
||||
/**
|
||||
* The namespace that all of the cached entries will be stored under. This allows multiple APIs to run concurrently.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
static public $namespace;
|
||||
|
||||
/**
|
||||
* @var string the memcache server hostname / IP address. For the memcache
|
||||
* cache method.
|
||||
*/
|
||||
static public $memcacheServer = '127.0.0.1';
|
||||
|
||||
/**
|
||||
* @var int the memcache server port. For the memcache cache method.
|
||||
*/
|
||||
static public $memcachePort = 11211;
|
||||
|
||||
|
||||
private $memcache;
|
||||
|
||||
/**
|
||||
* @param string $namespace
|
||||
*/
|
||||
function __construct($namespace = 'restler')
|
||||
{
|
||||
self::$namespace = $namespace;
|
||||
if (function_exists('memcache_connect')) {
|
||||
$this->memcache = new \Memcache;
|
||||
$this->memcache->connect(self::$memcacheServer, self::$memcachePort);
|
||||
} else {
|
||||
$this->memcacheNotAvailable('Memcache is not available for use as Restler Cache. Please make sure the the memcache php extension is installed.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* store data in the cache
|
||||
*
|
||||
*
|
||||
* @param string $name
|
||||
* @param mixed $data
|
||||
*
|
||||
* @return boolean true if successful
|
||||
*/
|
||||
public function set($name, $data)
|
||||
{
|
||||
function_exists('memcache_set') || $this->memcacheNotAvailable();
|
||||
|
||||
try {
|
||||
return $this->memcache->set(self::$namespace . "-" . $name, $data);
|
||||
} catch
|
||||
(\Exception $exception) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private function memcacheNotAvailable($message = 'Memcache is not available.')
|
||||
{
|
||||
throw new \Exception($message);
|
||||
}
|
||||
|
||||
/**
|
||||
* retrieve data from the cache
|
||||
*
|
||||
*
|
||||
* @param string $name
|
||||
* @param bool $ignoreErrors
|
||||
*
|
||||
* @throws \Exception
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($name, $ignoreErrors = false)
|
||||
{
|
||||
function_exists('memcache_get') || $this->memcacheNotAvailable();
|
||||
|
||||
try {
|
||||
return $this->memcache->get(self::$namespace . "-" . $name);
|
||||
} catch (\Exception $exception) {
|
||||
if (!$ignoreErrors) {
|
||||
throw $exception;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* delete data from the cache
|
||||
*
|
||||
*
|
||||
* @param string $name
|
||||
* @param bool $ignoreErrors
|
||||
*
|
||||
* @throws \Exception
|
||||
* @return boolean true if successful
|
||||
*/
|
||||
public function clear($name, $ignoreErrors = false)
|
||||
{
|
||||
function_exists('memcache_delete') || $this->memcacheNotAvailable();
|
||||
|
||||
try {
|
||||
$this->memcache->delete(self::$namespace . "-" . $name);
|
||||
} catch (\Exception $exception) {
|
||||
if (!$ignoreErrors) {
|
||||
throw $exception;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* check if the given name is cached
|
||||
*
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return boolean true if cached
|
||||
*/
|
||||
public function isCached($name)
|
||||
{
|
||||
function_exists('memcache_get') || $this->memcacheNotAvailable();
|
||||
$data = $this->memcache->get(self::$namespace . "-" . $name);
|
||||
return !empty($data);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,91 @@
|
||||
<?php
|
||||
namespace Luracast\Restler;
|
||||
|
||||
/**
|
||||
* Static Class to pass through content outside of web root
|
||||
*
|
||||
* @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/
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
class PassThrough
|
||||
{
|
||||
public static $mimeTypes = array(
|
||||
'js' => 'text/javascript',
|
||||
'css' => 'text/css',
|
||||
'png' => 'image/png',
|
||||
'jpg' => 'image/jpeg',
|
||||
'gif' => 'image/gif',
|
||||
'html' => 'text/html',
|
||||
);
|
||||
|
||||
/**
|
||||
* Serve a file outside web root
|
||||
*
|
||||
* Respond with a file stored outside web accessible path
|
||||
*
|
||||
* @param string $filename full path for the file to be served
|
||||
* @param bool $forceDownload should the we download instead of viewing
|
||||
* @param int $expires cache expiry in number of seconds
|
||||
* @param bool $isPublic cache control, is it public or private
|
||||
*
|
||||
* @throws RestException
|
||||
* @internal param string $pragma
|
||||
*
|
||||
*/
|
||||
public static function file($filename, $forceDownload = false, $expires = 0, $isPublic = true)
|
||||
{
|
||||
if (!is_file($filename))
|
||||
throw new RestException(404);
|
||||
if (!is_readable($filename))
|
||||
throw new RestException(403);
|
||||
$extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
|
||||
if (!$mime = Util::nestedValue(static::$mimeTypes, $extension)) {
|
||||
if (!function_exists('finfo_open')) {
|
||||
throw new RestException(
|
||||
500,
|
||||
'Unable to find media type of ' .
|
||||
basename($filename) .
|
||||
' either enable fileinfo php extension or update ' .
|
||||
'PassThrough::$mimeTypes to include mime type for ' . $extension .
|
||||
' extension'
|
||||
);
|
||||
}
|
||||
$finfo = finfo_open(FILEINFO_MIME_TYPE);
|
||||
$mime = finfo_file($finfo, $filename);
|
||||
}
|
||||
if (!is_array(Defaults::$headerCacheControl))
|
||||
Defaults::$headerCacheControl = array(Defaults::$headerCacheControl);
|
||||
$cacheControl = Defaults::$headerCacheControl[0];
|
||||
if ($expires > 0) {
|
||||
$cacheControl = $isPublic ? 'public' : 'private';
|
||||
$cacheControl .= end(Defaults::$headerCacheControl);
|
||||
$cacheControl = str_replace('{expires}', $expires, $cacheControl);
|
||||
$expires = gmdate('D, d M Y H:i:s \G\M\T', time() + $expires);
|
||||
}
|
||||
header('Cache-Control: ' . $cacheControl);
|
||||
header('Expires: ' . $expires);
|
||||
$lastModified = filemtime($filename);
|
||||
if (
|
||||
isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) &&
|
||||
strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) >= $lastModified
|
||||
) {
|
||||
header("{$_SERVER['SERVER_PROTOCOL']} 304 Not Modified");
|
||||
exit;
|
||||
}
|
||||
header('Last-Modified: ' . date('r', $lastModified));
|
||||
header('X-Powered-By: Luracast Restler v' . Restler::VERSION);
|
||||
header('Content-type: ' . $mime);
|
||||
header("Content-Length: " . filesize($filename));
|
||||
if ($forceDownload) {
|
||||
header("Content-Transfer-Encoding: binary");
|
||||
header('Content-Disposition: attachment; filename="' . $filename . '"');
|
||||
}
|
||||
readfile($filename);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
@ -12,7 +12,7 @@ use Luracast\Restler\Format\JsonFormat;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
class Redirect
|
||||
{
|
||||
@ -32,11 +32,13 @@ class Redirect
|
||||
/** @var $r Restler */
|
||||
$r = Scope::get('Restler');
|
||||
$base = $r->getBaseUrl() . '/';
|
||||
if (0 !== strpos($url, 'http'))
|
||||
if (0 !== strpos($url, 'http')) {
|
||||
$url = $base . $url;
|
||||
}
|
||||
if (!empty($flashData) || $base . $r->url !== $url || Util::getRequestMethod() != 'GET') {
|
||||
if ($r->responseFormat instanceof JsonFormat)
|
||||
if ($r->responseFormat instanceof JsonFormat) {
|
||||
return array('redirect' => $url);
|
||||
}
|
||||
if (!empty($params)) {
|
||||
$url .= '?' . http_build_query($params);
|
||||
}
|
||||
@ -48,6 +50,19 @@ class Redirect
|
||||
header("Location: $url");
|
||||
die('');
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect back to the previous page
|
||||
*
|
||||
* Makes use of http referrer for redirection
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function back()
|
||||
{
|
||||
return static::to($_SERVER['HTTP_REFERER']);
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
<?php
|
||||
namespace Luracast\Restler;
|
||||
|
||||
use Luracast\Restler\Data\String;
|
||||
use Luracast\Restler\Data\Text;
|
||||
use Luracast\Restler\Scope;
|
||||
use stdClass;
|
||||
|
||||
@ -15,7 +15,7 @@ use stdClass;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
class Resources implements iUseAuthentication, iProvideMultiVersionApi
|
||||
{
|
||||
@ -226,14 +226,14 @@ class Resources implements iUseAuthentication, iProvideMultiVersionApi
|
||||
continue;
|
||||
}
|
||||
$fullPath = $route['url'];
|
||||
if ($fullPath !== $target && !String::beginsWith($fullPath, $target)) {
|
||||
if ($fullPath !== $target && !Text::beginsWith($fullPath, $target)) {
|
||||
continue;
|
||||
}
|
||||
$fLen = strlen($fullPath);
|
||||
if ($tSlash) {
|
||||
if ($fLen != $tLen && !String::beginsWith($fullPath, $target . '/'))
|
||||
if ($fLen != $tLen && !Text::beginsWith($fullPath, $target . '/'))
|
||||
continue;
|
||||
} elseif ($fLen > $tLen + 1 && $fullPath{$tLen + 1} != '{' && !String::beginsWith($fullPath, '{')) {
|
||||
} elseif ($fLen > $tLen + 1 && $fullPath{$tLen + 1} != '{' && !Text::beginsWith($fullPath, '{')) {
|
||||
//when mapped to root exclude paths that have static parts
|
||||
//they are listed else where under that static part name
|
||||
continue;
|
||||
@ -246,7 +246,7 @@ class Resources implements iUseAuthentication, iProvideMultiVersionApi
|
||||
if (empty($exclude)) {
|
||||
if ($fullPath == $exclude)
|
||||
continue 2;
|
||||
} elseif (String::beginsWith($fullPath, $exclude)) {
|
||||
} elseif (Text::beginsWith($fullPath, $exclude)) {
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
@ -317,7 +317,7 @@ class Resources implements iUseAuthentication, iProvideMultiVersionApi
|
||||
if (isset($m['throws'])) {
|
||||
foreach ($m['throws'] as $exception) {
|
||||
$operation->errorResponses[] = array(
|
||||
'reason' => $exception['reason'],
|
||||
'reason' => $exception['message'],
|
||||
'code' => $exception['code']);
|
||||
}
|
||||
}
|
||||
@ -370,7 +370,7 @@ class Resources implements iUseAuthentication, iProvideMultiVersionApi
|
||||
|
||||
if (static::$groupOperations) {
|
||||
foreach ($r->apis as $a) {
|
||||
if ($a->path == "/$fullPath") {
|
||||
if ($a->path == "$prefix/$fullPath") {
|
||||
$api = $a;
|
||||
break;
|
||||
}
|
||||
@ -774,14 +774,14 @@ class Resources implements iUseAuthentication, iProvideMultiVersionApi
|
||||
$this->_model($itemType);
|
||||
$itemType = $this->_noNamespace($itemType);
|
||||
}
|
||||
$properties[$key]['item'] = array(
|
||||
$properties[$key]['items'] = array(
|
||||
'type' => $itemType,
|
||||
/*'description' => '' */ //TODO: add description
|
||||
);
|
||||
} else if (preg_match('/^Array\[(.+)\]$/', $type, $matches)) {
|
||||
$itemType = $matches[1];
|
||||
$properties[$key]['type'] = 'Array';
|
||||
$properties[$key]['item']['type'] = $itemType;
|
||||
$properties[$key]['items']['type'] = $this->_noNamespace($itemType);
|
||||
|
||||
if (class_exists($itemType)) {
|
||||
$this->_model($itemType);
|
||||
@ -891,7 +891,7 @@ class Resources implements iUseAuthentication, iProvideMultiVersionApi
|
||||
}
|
||||
$this->_mapResources($allRoutes, $map, $version);
|
||||
foreach ($map as $path => $description) {
|
||||
if (!String::contains($path, '{')) {
|
||||
if (!Text::contains($path, '{')) {
|
||||
//add id
|
||||
$r->apis[] = array(
|
||||
'path' => $path . $this->formatString,
|
||||
@ -934,7 +934,7 @@ class Resources implements iUseAuthentication, iProvideMultiVersionApi
|
||||
foreach ($allRoutes as $fullPath => $routes) {
|
||||
$path = explode('/', $fullPath);
|
||||
$resource = isset($path[0]) ? $path[0] : '';
|
||||
if ($resource == 'resources' || String::endsWith($resource, 'index'))
|
||||
if ($resource == 'resources' || Text::endsWith($resource, 'index'))
|
||||
continue;
|
||||
foreach ($routes as $httpMethod => $route) {
|
||||
if (in_array($httpMethod, static::$excludedHttpMethods)) {
|
||||
@ -948,7 +948,7 @@ class Resources implements iUseAuthentication, iProvideMultiVersionApi
|
||||
if (empty($exclude)) {
|
||||
if ($fullPath == $exclude)
|
||||
continue 2;
|
||||
} elseif (String::beginsWith($fullPath, $exclude)) {
|
||||
} elseif (Text::beginsWith($fullPath, $exclude)) {
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,6 +14,7 @@ use Exception;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
|
||||
class RestException extends Exception
|
||||
|
||||
@ -21,11 +21,37 @@ use Luracast\Restler\Format\UrlEncodedFormat;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*
|
||||
* @method static void onGet() onGet(Callable $function) fired before reading the request details
|
||||
* @method static void onRoute() onRoute(Callable $function) fired before finding the api method
|
||||
* @method static void onNegotiate() onNegotiate(Callable $function) fired before content negotiation
|
||||
* @method static void onPreAuthFilter() onPreAuthFilter(Callable $function) fired before pre auth filtering
|
||||
* @method static void onAuthenticate() onAuthenticate(Callable $function) fired before auth
|
||||
* @method static void onPostAuthFilter() onPostAuthFilter(Callable $function) fired before post auth filtering
|
||||
* @method static void onValidate() onValidate(Callable $function) fired before validation
|
||||
* @method static void onCall() onCall(Callable $function) fired before api method call
|
||||
* @method static void onCompose() onCompose(Callable $function) fired before composing response
|
||||
* @method static void onRespond() onRespond(Callable $function) fired before sending response
|
||||
* @method static void onComplete() onComplete(Callable $function) fired after sending response
|
||||
* @method static void onMessage() onMessage(Callable $function) fired before composing error response
|
||||
*
|
||||
* @method void onGet() onGet(Callable $function) fired before reading the request details
|
||||
* @method void onRoute() onRoute(Callable $function) fired before finding the api method
|
||||
* @method void onNegotiate() onNegotiate(Callable $function) fired before content negotiation
|
||||
* @method void onPreAuthFilter() onPreAuthFilter(Callable $function) fired before pre auth filtering
|
||||
* @method void onAuthenticate() onAuthenticate(Callable $function) fired before auth
|
||||
* @method void onPostAuthFilter() onPostAuthFilter(Callable $function) fired before post auth filtering
|
||||
* @method void onValidate() onValidate(Callable $function) fired before validation
|
||||
* @method void onCall() onCall(Callable $function) fired before api method call
|
||||
* @method void onCompose() onCompose(Callable $function) fired before composing response
|
||||
* @method void onRespond() onRespond(Callable $function) fired before sending response
|
||||
* @method void onComplete() onComplete(Callable $function) fired after sending response
|
||||
* @method void onMessage() onMessage(Callable $function) fired before composing error response
|
||||
*/
|
||||
class Restler extends EventDispatcher
|
||||
{
|
||||
const VERSION = '3.0.0rc5';
|
||||
const VERSION = '3.0.0rc6';
|
||||
|
||||
// ==================================================================
|
||||
//
|
||||
@ -78,9 +104,9 @@ class Restler extends EventDispatcher
|
||||
/**
|
||||
* Http status code
|
||||
*
|
||||
* @var int
|
||||
* @var int|null when specified it will override @status comment
|
||||
*/
|
||||
public $responseCode=200;
|
||||
public $responseCode=null;
|
||||
/**
|
||||
* @var string base url of the api service
|
||||
*/
|
||||
@ -278,11 +304,20 @@ class Restler extends EventDispatcher
|
||||
$this->call();
|
||||
$this->compose();
|
||||
$this->postCall();
|
||||
if (Defaults::$returnResponse) {
|
||||
return $this->respond();
|
||||
}
|
||||
$this->respond();
|
||||
} catch (Exception $e) {
|
||||
try{
|
||||
if (Defaults::$returnResponse) {
|
||||
return $this->message($e);
|
||||
}
|
||||
$this->message($e);
|
||||
} catch (Exception $e2) {
|
||||
if (Defaults::$returnResponse) {
|
||||
return $this->message($e2);
|
||||
}
|
||||
$this->message($e2);
|
||||
}
|
||||
}
|
||||
@ -426,6 +461,31 @@ class Restler extends EventDispatcher
|
||||
$this->formatOverridesMap['extensions'] = array_keys($extensions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set one or more string to be considered as the base url
|
||||
*
|
||||
* When more than one base url is provided, restler will make
|
||||
* use of $_SERVER['HTTP_HOST'] to find the right one
|
||||
*
|
||||
* @param string ,... $url
|
||||
*/
|
||||
public function setBaseUrls($url /*[, $url2...$urlN]*/)
|
||||
{
|
||||
if (func_num_args() > 1) {
|
||||
$urls = func_get_args();
|
||||
usort($urls, function ($a, $b) {
|
||||
return strlen($a) - strlen($b);
|
||||
});
|
||||
foreach ($urls as $u) {
|
||||
if (0 === strpos($_SERVER['HTTP_HOST'], parse_url($u, PHP_URL_HOST))) {
|
||||
$this->baseUrl = $u;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->baseUrl = $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the request url and get the api path
|
||||
*
|
||||
@ -436,35 +496,43 @@ class Restler extends EventDispatcher
|
||||
// fix SCRIPT_NAME for PHP 5.4 built-in web server
|
||||
if (false === strpos($_SERVER['SCRIPT_NAME'], '.php'))
|
||||
$_SERVER['SCRIPT_NAME']
|
||||
= '/' . Util::removeCommonPath($_SERVER['SCRIPT_FILENAME'], $_SERVER['DOCUMENT_ROOT']);
|
||||
= '/' . substr($_SERVER['SCRIPT_FILENAME'], strlen($_SERVER['DOCUMENT_ROOT']) + 1);
|
||||
|
||||
$fullPath = urldecode($_SERVER['REQUEST_URI']);
|
||||
$path = Util::removeCommonPath(
|
||||
$fullPath,
|
||||
list($base, $path) = Util::splitCommonPath(
|
||||
strtok(urldecode($_SERVER['REQUEST_URI']), '?'), //remove query string
|
||||
$_SERVER['SCRIPT_NAME']
|
||||
);
|
||||
$port = isset($_SERVER['SERVER_PORT']) ? $_SERVER['SERVER_PORT'] : '80';
|
||||
$https = $port == '443' ||
|
||||
(isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') || // Amazon ELB
|
||||
(isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on');
|
||||
|
||||
$baseUrl = ($https ? 'https://' : 'http://') . $_SERVER['SERVER_NAME'];
|
||||
if (!$this->baseUrl) {
|
||||
// Fix port number retrieval if port is specified in HOST header.
|
||||
$host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : '';
|
||||
$portPos = strpos($host,":");
|
||||
if ($portPos){
|
||||
$port = substr($host,$portPos+1);
|
||||
} else {
|
||||
$port = isset($_SERVER['SERVER_PORT']) ? $_SERVER['SERVER_PORT'] : '80';
|
||||
$port = isset($_SERVER['HTTP_X_FORWARDED_PORT']) ? $_SERVER['HTTP_X_FORWARDED_PORT'] : $port; // Amazon ELB
|
||||
}
|
||||
$https = $port == '443' ||
|
||||
(isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') || // Amazon ELB
|
||||
(isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on');
|
||||
$baseUrl = ($https ? 'https://' : 'http://') . $_SERVER['SERVER_NAME'];
|
||||
if (!$https && $port != '80' || $https && $port != '443')
|
||||
$baseUrl .= ':' . $port;
|
||||
$this->baseUrl = $baseUrl . $base;
|
||||
} elseif (!empty($base) && false === strpos($this->baseUrl, $base)) {
|
||||
$this->baseUrl .= $base;
|
||||
}
|
||||
|
||||
if (!$https && $port != '80' || $https && $port != '443')
|
||||
$baseUrl .= ':' . $port;
|
||||
|
||||
$this->baseUrl = rtrim($baseUrl
|
||||
. substr($fullPath, 0, strlen($fullPath) - strlen($path)), '/');
|
||||
|
||||
$path = rtrim(strtok($path, '?'), '/'); //remove query string and trailing slash if found any
|
||||
$path = str_replace(
|
||||
array_merge(
|
||||
$this->formatMap['extensions'],
|
||||
$this->formatOverridesMap['extensions']
|
||||
),
|
||||
'',
|
||||
$path
|
||||
rtrim($path, '/') //remove trailing slash if found
|
||||
);
|
||||
|
||||
if (Defaults::$useUrlBasedVersioning && strlen($path) && $path{0} == 'v') {
|
||||
$version = intval(substr($path, 1));
|
||||
if ($version && $version <= $this->apiVersion) {
|
||||
@ -865,23 +933,21 @@ class Restler extends EventDispatcher
|
||||
|
||||
protected function authenticate()
|
||||
{
|
||||
$o = & $this->apiMethodInfo;
|
||||
$accessLevel = max(Defaults::$apiAccessLevel,
|
||||
$o->accessLevel);
|
||||
try {
|
||||
if ($accessLevel || count($this->postAuthFilterClasses)) {
|
||||
$this->dispatch('authenticate');
|
||||
if (!count($this->authClasses)) {
|
||||
throw new RestException(
|
||||
403,
|
||||
'at least one Authentication Class is required'
|
||||
);
|
||||
}
|
||||
foreach ($this->authClasses as $authClass) {
|
||||
$o = &$this->apiMethodInfo;
|
||||
$accessLevel = max(Defaults::$apiAccessLevel, $o->accessLevel);
|
||||
if ($accessLevel || count($this->postAuthFilterClasses)) {
|
||||
$this->dispatch('authenticate');
|
||||
if (!count($this->authClasses) && $accessLevel > 1) {
|
||||
throw new RestException(
|
||||
403,
|
||||
'at least one Authentication Class is required'
|
||||
);
|
||||
}
|
||||
$unauthorized = false;
|
||||
foreach ($this->authClasses as $authClass) {
|
||||
try {
|
||||
$authObj = Scope::get($authClass);
|
||||
if (!method_exists($authObj,
|
||||
Defaults::$authenticationMethod)
|
||||
) {
|
||||
if (!method_exists($authObj, Defaults::$authenticationMethod)) {
|
||||
throw new RestException (
|
||||
500, 'Authentication Class ' .
|
||||
'should implement iAuthenticate');
|
||||
@ -890,16 +956,26 @@ class Restler extends EventDispatcher
|
||||
) {
|
||||
throw new RestException(401);
|
||||
}
|
||||
$unauthorized = false;
|
||||
break;
|
||||
} catch (InvalidAuthCredentials $e) {
|
||||
$this->authenticated = false;
|
||||
throw $e;
|
||||
} catch (RestException $e) {
|
||||
if (!$unauthorized) {
|
||||
$unauthorized = $e;
|
||||
}
|
||||
}
|
||||
$this->authenticated = true;
|
||||
}
|
||||
$this->authVerified = true;
|
||||
} catch (RestException $e) {
|
||||
$this->authVerified = true;
|
||||
if ($accessLevel > 1) { //when it is not a hybrid api
|
||||
throw ($e);
|
||||
if ($unauthorized) {
|
||||
if ($accessLevel > 1) { //when it is not a hybrid api
|
||||
throw $unauthorized;
|
||||
} else {
|
||||
$this->authenticated = false;
|
||||
}
|
||||
} else {
|
||||
$this->authenticated = false;
|
||||
$this->authenticated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -936,6 +1012,8 @@ class Restler extends EventDispatcher
|
||||
}
|
||||
//convert to instance of ValidationInfo
|
||||
$info = new ValidationInfo($param);
|
||||
//initialize validator
|
||||
Scope::get(Defaults::$validatorClass);
|
||||
$validator = Defaults::$validatorClass;
|
||||
//if(!is_subclass_of($validator, 'Luracast\\Restler\\Data\\iValidate')) {
|
||||
//changed the above test to below for addressing this php bug
|
||||
@ -964,6 +1042,8 @@ class Restler extends EventDispatcher
|
||||
$o = & $this->apiMethodInfo;
|
||||
$accessLevel = max(Defaults::$apiAccessLevel,
|
||||
$o->accessLevel);
|
||||
if (function_exists('newrelic_name_transaction'))
|
||||
newrelic_name_transaction("{$o->className}/{$o->methodName}");
|
||||
$object = Scope::get($o->className);
|
||||
switch ($accessLevel) {
|
||||
case 3 : //protected method
|
||||
@ -1057,6 +1137,8 @@ class Restler extends EventDispatcher
|
||||
if (!Defaults::$suppressResponseCode) {
|
||||
if ($e) {
|
||||
$code = $e->getCode();
|
||||
} elseif ($this->responseCode) {
|
||||
$code = $this->responseCode;
|
||||
} elseif (isset($this->apiMethodInfo->metadata['status'])) {
|
||||
$code = $this->apiMethodInfo->metadata['status'];
|
||||
}
|
||||
@ -1084,9 +1166,13 @@ class Restler extends EventDispatcher
|
||||
: 'Unknown';
|
||||
@header('WWW-Authenticate: ' . $authString, false);
|
||||
}
|
||||
echo $this->responseData;
|
||||
$this->dispatch('complete');
|
||||
exit;
|
||||
if (Defaults::$returnResponse) {
|
||||
return $this->responseData;
|
||||
} else {
|
||||
echo $this->responseData;
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
protected function message(Exception $exception)
|
||||
@ -1128,6 +1214,9 @@ class Restler extends EventDispatcher
|
||||
$compose->message($exception),
|
||||
!$this->productionMode
|
||||
);
|
||||
if (Defaults::$returnResponse) {
|
||||
return $this->respond();
|
||||
}
|
||||
$this->respond();
|
||||
}
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
namespace Luracast\Restler;
|
||||
|
||||
use Luracast\Restler\Data\ApiMethodInfo;
|
||||
use Luracast\Restler\Data\String;
|
||||
use Luracast\Restler\Data\Text;
|
||||
use ReflectionClass;
|
||||
use ReflectionMethod;
|
||||
use ReflectionProperty;
|
||||
@ -17,13 +17,32 @@ use Exception;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
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();
|
||||
@ -56,6 +75,7 @@ class Routes
|
||||
* - Do not include it in URL
|
||||
*/
|
||||
$class = new ReflectionClass($className);
|
||||
$dataName = CommentParser::$embeddedDataName;
|
||||
try {
|
||||
$classMetadata = CommentParser::parse($class->getDocComment());
|
||||
} catch (Exception $e) {
|
||||
@ -92,7 +112,7 @@ class Routes
|
||||
= (isset($metadata['smart-auto-routing'])
|
||||
&& $metadata['smart-auto-routing'] != 'true')
|
||||
|| !Defaults::$smartAutoRouting;
|
||||
$metadata['resourcePath'] = $resourcePath;
|
||||
$metadata['resourcePath'] = trim($resourcePath, '/');
|
||||
if (isset($classMetadata['description'])) {
|
||||
$metadata['classDescription'] = $classMetadata['description'];
|
||||
}
|
||||
@ -123,44 +143,51 @@ class Routes
|
||||
}
|
||||
$m = & $metadata ['param'] [$position];
|
||||
$m ['name'] = $param->getName();
|
||||
if (!isset($m[$dataName])) {
|
||||
$m[$dataName] = array();
|
||||
}
|
||||
$p = &$m[$dataName];
|
||||
if (empty($m['label']))
|
||||
$m['label'] = static::label($m['name']);
|
||||
$m['label'] = Text::title($m['name']);
|
||||
if (is_null($type) && isset($m['type'])) {
|
||||
$type = $m['type'];
|
||||
}
|
||||
if ($m['name'] == 'email' && empty($m[CommentParser::$embeddedDataName]['type']) && $type == 'string')
|
||||
$m[CommentParser::$embeddedDataName]['type'] = 'email';
|
||||
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(
|
||||
$m,
|
||||
CommentParser::$embeddedDataName,
|
||||
'type'
|
||||
);
|
||||
if ($contentType && $qualified = Scope::resolve($contentType, $scope)) {
|
||||
list($m[CommentParser::$embeddedDataName]['type'], $children) = static::getTypeAndModel(
|
||||
new ReflectionClass($qualified), $scope
|
||||
$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) = static::getTypeAndModel($type, $scope);
|
||||
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)
|
||||
= static::getTypeAndModel(new ReflectionClass($qualified), $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;
|
||||
|
||||
$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($m[CommentParser::$embeddedDataName]['from'])) {
|
||||
$from = $m[CommentParser::$embeddedDataName]['from'];
|
||||
} elseif (isset($p['from'])) {
|
||||
$from = $p['from'];
|
||||
} else {
|
||||
if ((isset($type) && Util::isObjectOrArray($type))
|
||||
) {
|
||||
@ -174,7 +201,7 @@ class Routes
|
||||
$from = 'body';
|
||||
}
|
||||
}
|
||||
$m[CommentParser::$embeddedDataName]['from'] = $from;
|
||||
$p['from'] = $from;
|
||||
if (!isset($m['type'])) {
|
||||
$type = $m['type'] = static::type($defaults[$position]);
|
||||
}
|
||||
@ -229,21 +256,21 @@ class Routes
|
||||
strpos($url, '{' . $p['name'] . '}') ||
|
||||
strpos($url, ':' . $p['name']);
|
||||
if ($inPath) {
|
||||
$copy['metadata']['param'][$i][CommentParser::$embeddedDataName]['from'] = 'path';
|
||||
$copy['metadata']['param'][$i][$dataName]['from'] = 'path';
|
||||
} elseif ($httpMethod == 'GET' || $httpMethod == 'DELETE') {
|
||||
$copy['metadata']['param'][$i][CommentParser::$embeddedDataName]['from'] = 'query';
|
||||
} elseif ($p[CommentParser::$embeddedDataName]['from'] == 'path') {
|
||||
$copy['metadata']['param'][$i][CommentParser::$embeddedDataName]['from'] = 'body';
|
||||
$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 ($call) {
|
||||
function ($matches) use ($copy) {
|
||||
$match = trim($matches[0], '{}:');
|
||||
$index = $call['arguments'][$match];
|
||||
$index = $copy['arguments'][$match];
|
||||
return '{' .
|
||||
Routes::typeChar(isset(
|
||||
$call['metadata']['param'][$index]['type'])
|
||||
? $call['metadata']['param'][$index]['type']
|
||||
$copy['metadata']['param'][$index]['type'])
|
||||
? $copy['metadata']['param'][$index]['type']
|
||||
: null)
|
||||
. $index . '}';
|
||||
}, $url);
|
||||
@ -269,11 +296,11 @@ class Routes
|
||||
$lastPathParam = array_keys($pathParams);
|
||||
$lastPathParam = end($lastPathParam);
|
||||
for ($position = 0; $position < count($params); $position++) {
|
||||
$from = $metadata['param'][$position][CommentParser::$embeddedDataName]['from'];
|
||||
$from = $metadata['param'][$position][$dataName]['from'];
|
||||
if ($from == 'body' && ($httpMethod == 'GET' ||
|
||||
$httpMethod == 'DELETE')
|
||||
) {
|
||||
$call['metadata']['param'][$position][CommentParser::$embeddedDataName]['from']
|
||||
$call['metadata']['param'][$position][$dataName]['from']
|
||||
= 'query';
|
||||
}
|
||||
}
|
||||
@ -313,7 +340,7 @@ class Routes
|
||||
}
|
||||
|
||||
protected static function addPath($path, array $call,
|
||||
$httpMethod = 'GET', $version = 1)
|
||||
$httpMethod = 'GET', $version = 1)
|
||||
{
|
||||
$call['url'] = preg_replace_callback(
|
||||
"/\{\S(\d+)\}/",
|
||||
@ -347,7 +374,7 @@ class Routes
|
||||
* @return ApiMethodInfo
|
||||
*/
|
||||
public static function find($path, $httpMethod,
|
||||
$version = 1, array $data = array())
|
||||
$version = 1, array $data = array())
|
||||
{
|
||||
$p = Util::nestedValue(static::$routes, "v$version");
|
||||
if (!$p) {
|
||||
@ -431,6 +458,62 @@ class Routes
|
||||
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
|
||||
*
|
||||
@ -445,14 +528,14 @@ class Routes
|
||||
{
|
||||
$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 && 'post' != (string)Util::$restler->requestFormat) {
|
||||
if (Defaults::$smartParameterParsing) {
|
||||
if (
|
||||
count($p) == 1 &&
|
||||
($m = Util::nestedValue($call, 'metadata', 'param', 0)) &&
|
||||
!array_key_exists($m['name'], $data) &&
|
||||
array_key_exists(Defaults::$fullRequestDataName, $data) &&
|
||||
@ -466,7 +549,7 @@ class Routes
|
||||
$lastBodyParamIndex = -1;
|
||||
$lastM = null;
|
||||
foreach ($call['metadata']['param'] as $k => $m) {
|
||||
if ($m[CommentParser::$embeddedDataName]['from'] == 'body') {
|
||||
if ($m[$dataName]['from'] == 'body') {
|
||||
$bodyParamCount++;
|
||||
$lastBodyParamIndex = $k;
|
||||
$lastM = $m;
|
||||
@ -526,6 +609,21 @@ class Routes
|
||||
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
|
||||
*
|
||||
@ -538,62 +636,105 @@ class Routes
|
||||
*
|
||||
* @access protected
|
||||
*/
|
||||
protected static function getTypeAndModel(ReflectionClass $class, array $scope)
|
||||
protected static function getTypeAndModel(ReflectionClass $class, array $scope, $prefix='', array $rules=array())
|
||||
{
|
||||
$className = $class->getName();
|
||||
if (isset(static::$models[$className])) {
|
||||
return static::$models[$className];
|
||||
$dataName = CommentParser::$embeddedDataName;
|
||||
if (isset(static::$models[$prefix.$className])) {
|
||||
return static::$models[$prefix.$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') ?: 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);
|
||||
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;
|
||||
}
|
||||
$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')) {
|
||||
if (Text::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];
|
||||
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];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -625,20 +766,6 @@ class Routes
|
||||
return 'string';
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a label from name of the parameter or property
|
||||
*
|
||||
* Convert `camelCase` style names into proper `Title Case` names
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function label($name)
|
||||
{
|
||||
return ucfirst(preg_replace(array('/(?<=[^A-Z])([A-Z])/', '/(?<=[^0-9])([0-9])/'), ' $0', $name));
|
||||
}
|
||||
|
||||
public static function scope(ReflectionClass $class)
|
||||
{
|
||||
$namespace = $class->getNamespaceName();
|
||||
@ -693,4 +820,4 @@ class Routes
|
||||
}
|
||||
return $imports;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,57 +11,70 @@ namespace Luracast\Restler;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
class Scope
|
||||
{
|
||||
public static $classAliases = array(
|
||||
|
||||
//Core
|
||||
'Restler' => 'Luracast\Restler\Restler',
|
||||
'Restler' => 'Luracast\Restler\Restler',
|
||||
|
||||
//Format classes
|
||||
'AmfFormat' => 'Luracast\Restler\Format\AmfFormat',
|
||||
'JsFormat' => 'Luracast\Restler\Format\JsFormat',
|
||||
'JsonFormat' => 'Luracast\Restler\Format\JsonFormat',
|
||||
'HtmlFormat' => 'Luracast\Restler\Format\HtmlFormat',
|
||||
'PlistFormat' => 'Luracast\Restler\Format\PlistFormat',
|
||||
'UploadFormat' => 'Luracast\Restler\Format\UploadFormat',
|
||||
'UrlEncodedFormat' => 'Luracast\Restler\Format\UrlEncodedFormat',
|
||||
'XmlFormat' => 'Luracast\Restler\Format\XmlFormat',
|
||||
'YamlFormat' => 'Luracast\Restler\Format\YamlFormat',
|
||||
'CsvFormat' => 'Luracast\Restler\Format\CsvFormat',
|
||||
'TsvFormat' => 'Luracast\Restler\Format\TsvFormat',
|
||||
'AmfFormat' => 'Luracast\Restler\Format\AmfFormat',
|
||||
'JsFormat' => 'Luracast\Restler\Format\JsFormat',
|
||||
'JsonFormat' => 'Luracast\Restler\Format\JsonFormat',
|
||||
'HtmlFormat' => 'Luracast\Restler\Format\HtmlFormat',
|
||||
'PlistFormat' => 'Luracast\Restler\Format\PlistFormat',
|
||||
'UploadFormat' => 'Luracast\Restler\Format\UploadFormat',
|
||||
'UrlEncodedFormat' => 'Luracast\Restler\Format\UrlEncodedFormat',
|
||||
'XmlFormat' => 'Luracast\Restler\Format\XmlFormat',
|
||||
'YamlFormat' => 'Luracast\Restler\Format\YamlFormat',
|
||||
'CsvFormat' => 'Luracast\Restler\Format\CsvFormat',
|
||||
'TsvFormat' => 'Luracast\Restler\Format\TsvFormat',
|
||||
|
||||
//Filter classes
|
||||
'RateLimit' => 'Luracast\Restler\Filter\RateLimit',
|
||||
'RateLimit' => 'Luracast\Restler\Filter\RateLimit',
|
||||
|
||||
//UI classes
|
||||
'Forms' => 'Luracast\Restler\UI\Forms',
|
||||
'Nav' => 'Luracast\Restler\UI\Nav',
|
||||
'Emmet' => 'Luracast\Restler\UI\Emmet',
|
||||
'T' => 'Luracast\Restler\UI\Tags',
|
||||
'Forms' => 'Luracast\Restler\UI\Forms',
|
||||
'Nav' => 'Luracast\Restler\UI\Nav',
|
||||
'Emmet' => 'Luracast\Restler\UI\Emmet',
|
||||
'T' => 'Luracast\Restler\UI\Tags',
|
||||
|
||||
//API classes
|
||||
'Resources' => 'Luracast\Restler\Resources',
|
||||
'Resources' => 'Luracast\Restler\Resources',
|
||||
'Explorer' => 'Luracast\Restler\Explorer',
|
||||
|
||||
//Cache classes
|
||||
'HumanReadableCache' => 'Luracast\Restler\HumanReadableCache',
|
||||
'ApcCache' => 'Luracast\Restler\ApcCache',
|
||||
'ApcCache' => 'Luracast\Restler\ApcCache',
|
||||
'MemcacheCache' => 'Luracast\Restler\MemcacheCache',
|
||||
|
||||
//Utility classes
|
||||
'Object' => 'Luracast\Restler\Data\Object',
|
||||
'String' => 'Luracast\Restler\Data\String',
|
||||
'Arr' => 'Luracast\Restler\Data\Arr',
|
||||
'Object' => 'Luracast\Restler\Data\Object',
|
||||
'Text' => 'Luracast\Restler\Data\Text',
|
||||
'Arr' => 'Luracast\Restler\Data\Arr',
|
||||
|
||||
//Exception
|
||||
'RestException' => 'Luracast\Restler\RestException'
|
||||
'RestException' => 'Luracast\Restler\RestException'
|
||||
);
|
||||
/**
|
||||
* @var null|Callable adding a resolver function that accepts
|
||||
* the class name as the parameter and returns an instance of the class
|
||||
* as a singleton. Allows the use of your favourite DI container
|
||||
*/
|
||||
public static $resolver = null;
|
||||
public static $properties = array();
|
||||
protected static $instances = array();
|
||||
protected static $registry = array();
|
||||
|
||||
public static function register($name, Callable $function, $singleton = true)
|
||||
/**
|
||||
* @param string $name
|
||||
* @param callable $function
|
||||
* @param bool $singleton
|
||||
*/
|
||||
public static function register($name, $function, $singleton = true)
|
||||
{
|
||||
static::$registry[$name] = (object)compact('function', 'singleton');
|
||||
}
|
||||
@ -82,8 +95,19 @@ class Scope
|
||||
} elseif (!empty(static::$registry[$name])) {
|
||||
$function = static::$registry[$name]->function;
|
||||
$r = $function();
|
||||
if (static::$registry[$name]->singleton)
|
||||
if (static::$registry[$name]->singleton) {
|
||||
static::$instances[$name] = (object)array('instance' => $r);
|
||||
}
|
||||
} elseif (is_callable(static::$resolver) && false === stristr($name, 'Luracast\Restler')) {
|
||||
$fullName = $name;
|
||||
if (isset(static::$classAliases[$name])) {
|
||||
$fullName = static::$classAliases[$name];
|
||||
}
|
||||
/** @var Callable $function */
|
||||
$function = static::$resolver;
|
||||
$r = $function($fullName);
|
||||
static::$instances[$name] = (object)array('instance' => $r);
|
||||
static::$instances[$name]->initPending = true;
|
||||
} else {
|
||||
$fullName = $name;
|
||||
if (isset(static::$classAliases[$name])) {
|
||||
@ -100,10 +124,10 @@ class Scope
|
||||
$properties = Util::nestedValue(
|
||||
$m, 'class', $fullName,
|
||||
CommentParser::$embeddedDataName
|
||||
) ? : (Util::nestedValue(
|
||||
) ?: (Util::nestedValue(
|
||||
$m, 'class', $shortName,
|
||||
CommentParser::$embeddedDataName
|
||||
) ? : array());
|
||||
) ?: array());
|
||||
} else {
|
||||
static::$instances[$name]->initPending = true;
|
||||
}
|
||||
@ -117,7 +141,7 @@ class Scope
|
||||
) {
|
||||
static::$instances[$name]->authVerified = true;
|
||||
$r->__setAuthenticationStatus
|
||||
(static::get('Restler')->_authenticated);
|
||||
(static::get('Restler')->_authenticated);
|
||||
}
|
||||
if (isset(static::$instances[$name]->initPending)) {
|
||||
$m = Util::nestedValue(static::get('Restler'), 'apiMethodInfo', 'metadata');
|
||||
@ -126,17 +150,18 @@ class Scope
|
||||
$shortName = Util::getShortName($name);
|
||||
} else {
|
||||
$shortName = $name;
|
||||
if (isset(static::$classAliases[$name]))
|
||||
if (isset(static::$classAliases[$name])) {
|
||||
$fullName = static::$classAliases[$name];
|
||||
}
|
||||
}
|
||||
if ($m) {
|
||||
$properties = Util::nestedValue(
|
||||
$m, 'class', $fullName,
|
||||
CommentParser::$embeddedDataName
|
||||
) ? : (Util::nestedValue(
|
||||
) ?: (Util::nestedValue(
|
||||
$m, 'class', $shortName,
|
||||
CommentParser::$embeddedDataName
|
||||
) ? : array());
|
||||
) ?: array());
|
||||
unset(static::$instances[$name]->initPending);
|
||||
$initialized = false;
|
||||
}
|
||||
|
||||
@ -4,6 +4,12 @@ namespace Luracast\Restler\UI;
|
||||
use Luracast\Restler\UI\Tags as T;
|
||||
use Luracast\Restler\Util;
|
||||
|
||||
/**
|
||||
* Class Emmet
|
||||
* @package Luracast\Restler\UI
|
||||
*
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
class Emmet
|
||||
{
|
||||
const DELIMITERS = '.#*>+^[=" ]{$@-#}';
|
||||
|
||||
@ -10,32 +10,32 @@ namespace Luracast\Restler\UI;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
class FormStyles
|
||||
{
|
||||
public static $html = array(
|
||||
'form' => 'form[role=form id=$id# name=$name# method=$method# action=$action# enctype=$enctype#]',
|
||||
'input' => '.row>section>label{$label#}^input[name=$name# value=$value# type=$type# required=$required# autofocus=$autofocus# placeholder=$default# accept=$accept#]',
|
||||
'textarea' => '.row>label{$label#}^textarea[name=$name# required=$required# autofocus=$autofocus# placeholder=$default# rows=3]{$value#}',
|
||||
'radio' => '.row>section>label{$label#}^span>label*options>input[name=$name# value=$value# type=radio checked=$selected# required=$required#]+{ $text#}',
|
||||
'select' => '.row>label{$label#}^select[name=$name# required=$required#]>option[value]+option[value=$value# selected=$selected#]{$text#}*options',
|
||||
'submit' => '.row>label{ }^button[type=submit]{$label#}',
|
||||
'input' => '.row>section>label{$label#}^input[id=$id# name=$name# value=$value# type=$type# required=$required# autofocus=$autofocus# placeholder=$default# accept=$accept# disabled=$disabled#]',
|
||||
'textarea' => '.row>label{$label#}^textarea[id=$id# name=$name# required=$required# autofocus=$autofocus# placeholder=$default# rows=3 disabled=$disabled#]{$value#}',
|
||||
'radio' => '.row>section>label{$label#}^span>label*options>input[id=$id# name=$name# value=$value# type=radio checked=$selected# required=$required# disabled=$disabled#]+{ $text#}',
|
||||
'select' => '.row>label{$label#}^select[id=$id# name=$name# required=$required#]>option[value]+option[value=$value# selected=$selected# disabled=$disabled#]{$text#}*options',
|
||||
'submit' => '.row>label{ }^button[id=$id# type=submit disabled=$disabled#]{$label#}',
|
||||
'fieldset' => 'fieldset>legend{$label#}',
|
||||
'checkbox' => '.row>label>input[name=$name# value=$value# type=checkbox checked=$selected# required=$required# autofocus=$autofocus# accept=$accept#]+{$label#}',
|
||||
'checkbox' => '.row>label>input[id=$id# name=$name# value=$value# type=checkbox checked=$selected# required=$required# autofocus=$autofocus# accept=$accept# disabled=$disabled#]+{$label#}',
|
||||
//------------- TYPE BASED STYLES ---------------------//
|
||||
'checkbox-array' => 'fieldset>legend{$label#}+section*options>label>input[name=$name# value=$value# type=checkbox checked=$selected# required=$required# autofocus=$autofocus# accept=$accept#]+{ $text#}',
|
||||
'select-array' => 'label{$label#}+select[name=$name# required=$required# multiple style="height: auto;background-image: none; outline: inherit;"]>option[value=$value# selected=$selected#]{$text#}*options',
|
||||
);
|
||||
public static $bootstrap3 = array(
|
||||
'form' => 'form[role=form id=$id# name=$name# method=$method# action=$action# enctype=$enctype#]',
|
||||
'input' => '.form-group>label{$label#}+input.form-control[name=$name# value=$value# type=$type# required=$required# autofocus=$autofocus# placeholder=$default# accept=$accept#]',
|
||||
'textarea' => '.form-group>label{$label#}+textarea.form-control[name=$name# required=$required# autofocus=$autofocus# placeholder=$default# rows=3]{$value#}',
|
||||
'radio' => 'fieldset>legend{$label#}>.radio*options>label>input.radio[name=$name# value=$value# type=radio checked=$selected# required=$required#]{$text#}',
|
||||
'select' => '.form-group>label{$label#}+select.form-control[name=$name# multiple=$multiple# required=$required#]>option[value]+option[value=$value# selected=$selected#]{$text#}*options',
|
||||
'submit' => 'button.btn.btn-primary[type=submit]{$label#}',
|
||||
'input' => '.form-group.$error#>label{$label#}+input.form-control[id=$id# name=$name# value=$value# type=$type# required=$required# autofocus=$autofocus# placeholder=$default# accept=$accept# disabled=$disabled#]+small.help-block>{$message#}',
|
||||
'textarea' => '.form-group>label{$label#}+textarea.form-control[id=$id# name=$name# required=$required# autofocus=$autofocus# placeholder=$default# rows=3 disabled=$disabled#]{$value#}+small.help-block>{$message#}',
|
||||
'radio' => 'fieldset>legend{$label#}>.radio*options>label>input.radio[name=$name# value=$value# type=radio checked=$selected# required=$required# disabled=$disabled#]{$text#}+p.help-block>{$message#}',
|
||||
'select' => '.form-group>label{$label#}+select.form-control[id=$id# name=$name# multiple=$multiple# required=$required#]>option[value]+option[value=$value# selected=$selected# disabled=$disabled#]{$text#}*options',
|
||||
'submit' => 'button.btn.btn-primary[id=$id# type=submit]{$label#} disabled=$disabled#',
|
||||
'fieldset' => 'fieldset>legend{$label#}',
|
||||
'checkbox' => '.checkbox>label>input[name=$name# value=$value# type=checkbox checked=$selected# required=$required# autofocus=$autofocus# accept=$accept#]+{$label#}',
|
||||
'checkbox' => '.checkbox>label>input[id=$id# name=$name# value=$value# type=checkbox checked=$selected# required=$required# autofocus=$autofocus# disabled=$disabled#]+{$label#}^p.help-block>{$error#}',
|
||||
//------------- TYPE BASED STYLES ---------------------//
|
||||
'checkbox-array' => 'fieldset>legend{$label#}>.checkbox*options>label>input[name=$name# value=$value# type=checkbox checked=$selected# required=$required#]{$text#}',
|
||||
'select-array' => '.form-group>label{$label#}+select.form-control[name=$name# multiple=$multiple# required=$required#] size=$options#>option[value=$value# selected=$selected#]{$text#}*options',
|
||||
@ -44,15 +44,15 @@ class FormStyles
|
||||
);
|
||||
public static $foundation5 = array(
|
||||
'form' => 'form[id=$id# name=$name# method=$method# action=$action# enctype=$enctype#]',
|
||||
'input' => 'label{$label#}+input[name=$name# value=$value# type=$type# required=$required# autofocus=$autofocus# placeholder=$default# accept=$accept#]',
|
||||
'textarea' => 'label{$label#}+textarea[name=$name# required=$required# autofocus=$autofocus# placeholder=$default# rows=3]{$value#}',
|
||||
'radio' => 'label{$label# : }+label.radio-inline*options>input.radio[name=$name# value=$value# type=radio checked=$selected# required=$required#]+{$text#}',
|
||||
'select' => 'label{$label#}+select[name=$name# required=$required#]>option[value]+option[value=$value# selected=$selected#]{$text#}*options',
|
||||
'submit' => 'button.button[type=submit]{$label#}',
|
||||
'input' => 'label{$label#}+input[id=$id# name=$name# value=$value# type=$type# required=$required# autofocus=$autofocus# placeholder=$default# accept=$accept# disabled=$disabled#]',
|
||||
'textarea' => 'label{$label#}+textarea[id=$id# name=$name# required=$required# autofocus=$autofocus# placeholder=$default# rows=3 disabled=$disabled#]{$value#}',
|
||||
'radio' => 'label{$label# : }+label.radio-inline*options>input.radio[name=$name# value=$value# type=radio checked=$selected# required=$required# disabled=$disabled#]+{$text#}',
|
||||
'select' => 'label{$label#}+select[id=$id# name=$name# required=$required#]>option[value]+option[value=$value# selected=$selected# disabled=$disabled#]{$text#}*options',
|
||||
'submit' => 'button.button[id=$id# type=submit disabled=$disabled#]{$label#}',
|
||||
'fieldset' => 'fieldset>legend{$label#}',
|
||||
'checkbox' => 'label>input[name=$name# value=$value# type=checkbox checked=$selected# required=$required# autofocus=$autofocus# accept=$accept#]+{ $label#}',
|
||||
'checkbox' => 'label>input[id=$id# name=$name# value=$value# type=checkbox checked=$selected# required=$required# autofocus=$autofocus# disabled=$disabled#]+{ $label#}',
|
||||
//------------- TYPE BASED STYLES ---------------------//
|
||||
'checkbox-array' => 'fieldset>legend{$label#}+label*options>input[name=$name# value=$value# type=checkbox checked=$selected# required=$required# autofocus=$autofocus# accept=$accept#]+{ $text#}',
|
||||
'checkbox-array' => 'fieldset>legend{$label#}+label*options>input[name=$name# value=$value# type=checkbox checked=$selected# required=$required# autofocus=$autofocus#]+{ $text#}',
|
||||
'select-array' => 'label{$label#}+select[name=$name# required=$required# multiple style="height: auto;background-image: none; outline: inherit;"]>option[value=$value# selected=$selected#]{$text#}*options',
|
||||
//------------- CUSTOM STYLES ---------------------//
|
||||
);
|
||||
|
||||
@ -3,8 +3,9 @@ namespace Luracast\Restler\UI;
|
||||
|
||||
use Luracast\Restler\CommentParser;
|
||||
use Luracast\Restler\Data\ApiMethodInfo;
|
||||
use Luracast\Restler\Data\String;
|
||||
use Luracast\Restler\Data\Text;
|
||||
use Luracast\Restler\Data\ValidationInfo;
|
||||
use Luracast\Restler\Data\Validator;
|
||||
use Luracast\Restler\Defaults;
|
||||
use Luracast\Restler\Format\UploadFormat;
|
||||
use Luracast\Restler\Format\UrlEncodedFormat;
|
||||
@ -28,7 +29,7 @@ use Luracast\Restler\Util;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
class Forms implements iFilter
|
||||
{
|
||||
@ -190,6 +191,9 @@ class Forms implements iFilter
|
||||
static::$fileUpload = false;
|
||||
$t['enctype'] = 'multipart/form-data';
|
||||
}
|
||||
if (isset($m[CommentParser::$embeddedDataName])) {
|
||||
$t += $m[CommentParser::$embeddedDataName];
|
||||
}
|
||||
if (!$dataOnly) {
|
||||
$t = Emmet::make(static::style('form', $m), $t);
|
||||
$t->prefix = $prefix;
|
||||
@ -292,14 +296,14 @@ class Forms implements iFilter
|
||||
$options[] = $option;
|
||||
}
|
||||
} elseif ($p->type == 'boolean' || $p->type == 'bool') {
|
||||
if (String::beginsWith($type, 'radio')) {
|
||||
if (Text::beginsWith($type, 'radio') || Text::beginsWith($type, 'select')) {
|
||||
$options[] = array('name' => $p->name, 'text' => ' Yes ',
|
||||
'value' => 'true');
|
||||
$options[] = array('name' => $p->name, 'text' => ' No ',
|
||||
'value' => 'false');
|
||||
if ($p->value || $p->default)
|
||||
$options[0]['selected'] = true;
|
||||
} else {
|
||||
} else { //checkbox
|
||||
$r = array(
|
||||
'tag' => $tag,
|
||||
'name' => $name,
|
||||
@ -312,6 +316,9 @@ class Forms implements iFilter
|
||||
if ($p->default) {
|
||||
$r['selected'] = true;
|
||||
}
|
||||
if (isset($p->rules)) {
|
||||
$r += $p->rules;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (empty($r)) {
|
||||
@ -325,16 +332,25 @@ class Forms implements iFilter
|
||||
'options' => & $options,
|
||||
'multiple' => $multiple,
|
||||
);
|
||||
if (isset($p->rules)) {
|
||||
$r += $p->rules;
|
||||
}
|
||||
}
|
||||
if ($type == 'file') {
|
||||
static::$fileUpload = true;
|
||||
$r['accept'] = implode(', ', UploadFormat::$allowedMimeTypes);
|
||||
if (empty($r['accept'])) {
|
||||
$r['accept'] = implode(', ', UploadFormat::$allowedMimeTypes);
|
||||
}
|
||||
}
|
||||
if (!empty(Validator::$exceptions[$name]) && static::$info->url == Scope::get('Restler')->url) {
|
||||
$r['error'] = 'has-error';
|
||||
$r['message'] = Validator::$exceptions[$p->name]->getMessage();
|
||||
}
|
||||
|
||||
if (true === $p->required)
|
||||
$r['required'] = true;
|
||||
$r['required'] = 'required';
|
||||
if (isset($p->rules['autofocus']))
|
||||
$r['autofocus'] = true;
|
||||
$r['autofocus'] = 'autofocus';
|
||||
/*
|
||||
echo "<pre>";
|
||||
print_r($r);
|
||||
@ -411,7 +427,7 @@ class Forms implements iFilter
|
||||
if (empty($exclude)) {
|
||||
if ($url == $exclude)
|
||||
return true;
|
||||
} elseif (String::beginsWith($url, $exclude)) {
|
||||
} elseif (Text::beginsWith($url, $exclude)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
namespace Luracast\Restler\UI;
|
||||
|
||||
use Luracast\Restler\CommentParser;
|
||||
use Luracast\Restler\Defaults;
|
||||
use Luracast\Restler\Data\Text;
|
||||
use Luracast\Restler\Restler;
|
||||
use Luracast\Restler\Routes;
|
||||
use Luracast\Restler\Scope;
|
||||
@ -19,18 +19,13 @@ use Luracast\Restler\Util;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
class Nav
|
||||
{
|
||||
protected static $tree = array();
|
||||
public static $root = 'home';
|
||||
/**
|
||||
* @var null|callable if the api methods are under access control mechanism
|
||||
* you can attach a function here that returns true or false to determine
|
||||
* visibility of a protected api method. this function will receive method
|
||||
* info as the only parameter.
|
||||
*/
|
||||
public static $accessControlFunction = null;
|
||||
|
||||
/**
|
||||
* @var array all paths beginning with any of the following will be excluded
|
||||
* from documentation. if an empty string is given it will exclude the root
|
||||
@ -40,169 +35,188 @@ class Nav
|
||||
* @var array prefix additional menu items with one of the following syntax
|
||||
* [$path => $text]
|
||||
* [$path]
|
||||
* [$path => ['text' => $text, 'url' => $url]]
|
||||
* [$path => ['text' => $text, 'url' => $url, 'trail'=> $trail]]
|
||||
*/
|
||||
public static $prepends = array();
|
||||
/**
|
||||
* @var array suffix additional menu items with one of the following syntax
|
||||
* [$path => $text]
|
||||
* [$path]
|
||||
* [$path => ['text' => $text, 'url' => $url]]
|
||||
* [$path => ['text' => $text, 'url' => $url, 'trail'=> $trail]]
|
||||
*/
|
||||
public static $appends = array();
|
||||
|
||||
public static $addExtension = true;
|
||||
|
||||
protected static $extension = '';
|
||||
protected static $activeTrail = '';
|
||||
protected static $url;
|
||||
|
||||
public static function get($for = '', $activeUrl = null)
|
||||
public static function get($for = '', $activeTrail = 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 (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);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
static::addUrls(static::$appends);
|
||||
} elseif (empty($activeTrail)) {
|
||||
$activeTrail = static::$activeTrail;
|
||||
}
|
||||
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);
|
||||
$tree = static::$tree;
|
||||
$activeTrail = explode('/', $activeTrail);
|
||||
$nested = & static::nested($tree, $activeTrail);
|
||||
if (is_array($nested)) {
|
||||
$nested['active'] = true;
|
||||
}
|
||||
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;
|
||||
$tree = static::nested($tree, $for)['children'];
|
||||
}
|
||||
return $tree;
|
||||
return array_filter($tree);
|
||||
}
|
||||
|
||||
protected static function build(&$tree, $path,
|
||||
$url = null, $text = null, $activeUrl = null)
|
||||
protected static function & nested(array & $tree, array $parts)
|
||||
{
|
||||
$parts = explode('/', $path);
|
||||
if (!empty($parts)) {
|
||||
$part = array_shift($parts);
|
||||
if (empty($tree[$part])) {
|
||||
return $tree[$part];
|
||||
} elseif (empty($parts)) {
|
||||
return static::nested($tree[$part], $parts);
|
||||
} elseif (!empty($tree[$part]['children'])) {
|
||||
return static::nested($tree[$part]['children'], $parts);
|
||||
}
|
||||
} else {
|
||||
return $tree;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static function addUrls(array $urls)
|
||||
{
|
||||
foreach ($urls as $url => $label) {
|
||||
$trail = null;
|
||||
if (is_array($label)) {
|
||||
if (isset($label['trail'])) {
|
||||
$trail = $label['trail'];
|
||||
}
|
||||
if (isset($label['url'])) {
|
||||
$url = $label['url'];
|
||||
$label = isset($label['label']) ? $label['label'] : null;
|
||||
} else {
|
||||
$url = current(array_keys($label));
|
||||
$label = current($label);
|
||||
}
|
||||
|
||||
}
|
||||
if (is_numeric($url)) {
|
||||
$url = $label;
|
||||
$label = null;
|
||||
}
|
||||
static::add($url, $label, $trail);
|
||||
}
|
||||
return static::$tree;
|
||||
}
|
||||
|
||||
public static function add($url, $label = null, $trail = null)
|
||||
{
|
||||
$r = parse_url($url);
|
||||
if (is_null($trail)) {
|
||||
$trail = isset($r['path']) ? $r['path'] : static::$root;
|
||||
}
|
||||
//remove / prefix and / suffixes and any extension
|
||||
$trail = strtok(trim($trail, '/'), '.');
|
||||
$parts = explode('/', $trail);
|
||||
if (count($parts) == 1 && empty($parts[0]))
|
||||
$parts = array(static::$root);
|
||||
$p = & $tree;
|
||||
$end = end($parts);
|
||||
foreach ($parts as $part) {
|
||||
if (!isset($p[$part])) {
|
||||
$p[$part] = array(
|
||||
'href' => '#',
|
||||
'text' => static::title($part)
|
||||
);
|
||||
if ($part == $end) {
|
||||
$p[$part]['class'] = $part;
|
||||
if ($text)
|
||||
$p[$part]['text'] = $text;
|
||||
if (is_null($url)) {
|
||||
if (empty($path) && !empty(static::$extension))
|
||||
$path = 'index';
|
||||
$p[$part]['href'] = Util::$restler->getBaseUrl()
|
||||
. '/' . $path . static::$extension;
|
||||
} else {
|
||||
if (empty($url) && !empty(static::$extension))
|
||||
$url = 'index';
|
||||
$p[$part]['href'] = $url . static::$extension;
|
||||
}
|
||||
if ($path == $activeUrl) {
|
||||
$p[$part]['active'] = true;
|
||||
}
|
||||
}
|
||||
$p[$part]['children'] = array();
|
||||
if (isset($r['fragment'])) {
|
||||
$parts[] = $r['fragment'];
|
||||
if (is_null($label)) {
|
||||
$label = Text::title($r['fragment']);
|
||||
}
|
||||
}
|
||||
if (empty($r['scheme'])) {
|
||||
//relative url found
|
||||
if (empty($url)) {
|
||||
$label = Text::title(static::$root);
|
||||
$url = static::$url;
|
||||
} else {
|
||||
$url = static::$url . '/' . ltrim($url, '/');
|
||||
}
|
||||
}
|
||||
if (is_null($label)) {
|
||||
$label = Text::title(strtok(end($parts), '.'));
|
||||
}
|
||||
$r['url'] = $url;
|
||||
$r['path'] = $trail;
|
||||
$r['parts'] = $parts;
|
||||
$r['label'] = $label;
|
||||
static::build($r);
|
||||
return $r;
|
||||
}
|
||||
|
||||
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'];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected static function title($name)
|
||||
{
|
||||
if (empty($name)) {
|
||||
$name = static::$root;
|
||||
} else {
|
||||
$name = ltrim($name, '#');
|
||||
}
|
||||
return ucfirst(preg_replace(array('/(?<=[^A-Z])([A-Z])/', '/(?<=[^0-9])([0-9])/'), ' $0', $name));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,7 +14,7 @@ use Luracast\Restler\Util;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*
|
||||
* ============================ magic properties ==============================
|
||||
* @property Tags parent parent tag
|
||||
@ -154,10 +154,10 @@ class Tags implements ArrayAccess, Countable
|
||||
*/
|
||||
public function id($value)
|
||||
{
|
||||
$this->attributes['id'] = isset($value)
|
||||
? (string)$value
|
||||
: Util::nestedValue($this->attributes, 'name');
|
||||
static::$instances[$value] = $this;
|
||||
if (!empty($value) && is_string($value)) {
|
||||
$this->attributes['id'] = $value;
|
||||
static::$instances[$value] = $this;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
@ -11,7 +11,7 @@ namespace Luracast\Restler;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
class User implements iIdentifyUser
|
||||
{
|
||||
|
||||
@ -9,7 +9,7 @@ namespace Luracast\Restler;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
class Util
|
||||
{
|
||||
@ -50,8 +50,8 @@ class Util
|
||||
* When the deeply nested property is found its value is returned, otherwise
|
||||
* false is returned.
|
||||
*
|
||||
* @param array $from array to extract the value from
|
||||
* @param string|array $key ... pass more to go deeply inside the array
|
||||
* @param array $from array to extract the value from
|
||||
* @param string|array $key ... pass more to go deeply inside the array
|
||||
* alternatively you can pass a single array
|
||||
*
|
||||
* @return null|mixed null when not found, value otherwise
|
||||
@ -129,6 +129,38 @@ class Util
|
||||
return implode($char, $fromPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two strings and split the common
|
||||
* sub string from the first string and return it as array
|
||||
*
|
||||
* @static
|
||||
*
|
||||
* @param string $fromPath
|
||||
* @param string $usingPath
|
||||
* @param string $char
|
||||
* optional, set it as
|
||||
* blank string for char by char comparison
|
||||
*
|
||||
* @return array with 2 strings first is the common string and second is the remaining in $fromPath
|
||||
*/
|
||||
public static function splitCommonPath($fromPath, $usingPath, $char = '/')
|
||||
{
|
||||
if (empty($fromPath))
|
||||
return array('', '');
|
||||
$fromPath = explode($char, $fromPath);
|
||||
$usingPath = explode($char, $usingPath);
|
||||
$commonPath = array();
|
||||
while (count($usingPath)) {
|
||||
if (count($fromPath) && $fromPath[0] == $usingPath[0]) {
|
||||
$commonPath [] = array_shift($fromPath);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
array_shift($usingPath);
|
||||
}
|
||||
return array(implode($char, $commonPath), implode($char, $fromPath));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the request to figure out the http request type
|
||||
*
|
||||
|
||||
@ -9,10 +9,6 @@
|
||||
{
|
||||
"name":"Luracast",
|
||||
"email":"arul@luracast.com"
|
||||
},
|
||||
{
|
||||
"name":"Nick nickl- Lombard",
|
||||
"email":"github@jigsoft.co.za"
|
||||
}
|
||||
],
|
||||
"extra":{
|
||||
@ -21,41 +17,23 @@
|
||||
}
|
||||
},
|
||||
"suggest":{
|
||||
"luracast/explorer":"Restler's very own api explorer (see require-dev for details)",
|
||||
"rodneyrehm/plist":"Restler supports tho Apple plist xml format (see require-dev for details)",
|
||||
"zendframework/zendamf":"Support for the amf document format (see require-dev for details)",
|
||||
"symfony/yaml":"Restler can produce content in yaml format as well (see require-dev for details)",
|
||||
"twig/twig":"Restler can render HtmlView using twig templates (see require-dev for details)",
|
||||
"mustache/mustache":"Restler can render HtmlView using mustache/handlebar templates (see require-dev for details)",
|
||||
"bshaffer/oauth2-server-php":"Restler can provide OAuth2 authentication using this library (see require-dev for details)"
|
||||
"rodneyrehm/plist":"If you need Apple plist binary/xml format",
|
||||
"zendframework/zendamf":"If you need AMF format",
|
||||
"symfony/yaml":"If you need YAML format",
|
||||
"twig/twig":"If you want to use twig templates with Html format",
|
||||
"mustache/mustache":"If you want to use mustache/handlebar templates with Html format",
|
||||
"illuminate/view":"If you want to use laravel blade templates with Html format",
|
||||
"bshaffer/oauth2-server-php":"If you want to use OAuth2 for authentication"
|
||||
},
|
||||
"require":{
|
||||
"php":">=5.3.0"
|
||||
},
|
||||
"require-dev":{
|
||||
"luracast/explorer":"*",
|
||||
"rodneyrehm/plist":"dev-master",
|
||||
"zendframework/zendamf":"dev-master",
|
||||
"symfony/yaml":"*",
|
||||
"mustache/mustache": "dev-master",
|
||||
"twig/twig": "v1.13.0",
|
||||
"bshaffer/oauth2-server-php":"v1.0"
|
||||
},
|
||||
"repositories":[
|
||||
{
|
||||
"type":"vcs",
|
||||
"url":"https://github.com/zendframework/ZendAmf.git"
|
||||
},
|
||||
{
|
||||
"type":"package",
|
||||
"package":{
|
||||
"name":"luracast/explorer",
|
||||
"version":"v3.0.0",
|
||||
"dist":{
|
||||
"type":"zip",
|
||||
"url":"https://github.com/Luracast/Restler-API-Explorer/zipball/v3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"autoload":{
|
||||
|
||||
@ -0,0 +1,125 @@
|
||||
/* http://meyerweb.com/eric/tools/css/reset/ v2.0 | 20110126 */
|
||||
html,
|
||||
body,
|
||||
div,
|
||||
span,
|
||||
applet,
|
||||
object,
|
||||
iframe,
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6,
|
||||
p,
|
||||
blockquote,
|
||||
pre,
|
||||
a,
|
||||
abbr,
|
||||
acronym,
|
||||
address,
|
||||
big,
|
||||
cite,
|
||||
code,
|
||||
del,
|
||||
dfn,
|
||||
em,
|
||||
img,
|
||||
ins,
|
||||
kbd,
|
||||
q,
|
||||
s,
|
||||
samp,
|
||||
small,
|
||||
strike,
|
||||
strong,
|
||||
sub,
|
||||
sup,
|
||||
tt,
|
||||
var,
|
||||
b,
|
||||
u,
|
||||
i,
|
||||
center,
|
||||
dl,
|
||||
dt,
|
||||
dd,
|
||||
ol,
|
||||
ul,
|
||||
li,
|
||||
fieldset,
|
||||
form,
|
||||
label,
|
||||
legend,
|
||||
table,
|
||||
caption,
|
||||
tbody,
|
||||
tfoot,
|
||||
thead,
|
||||
tr,
|
||||
th,
|
||||
td,
|
||||
article,
|
||||
aside,
|
||||
canvas,
|
||||
details,
|
||||
embed,
|
||||
figure,
|
||||
figcaption,
|
||||
footer,
|
||||
header,
|
||||
hgroup,
|
||||
menu,
|
||||
nav,
|
||||
output,
|
||||
ruby,
|
||||
section,
|
||||
summary,
|
||||
time,
|
||||
mark,
|
||||
audio,
|
||||
video {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
font-size: 100%;
|
||||
font: inherit;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
/* HTML5 display-role reset for older browsers */
|
||||
article,
|
||||
aside,
|
||||
details,
|
||||
figcaption,
|
||||
figure,
|
||||
footer,
|
||||
header,
|
||||
hgroup,
|
||||
menu,
|
||||
nav,
|
||||
section {
|
||||
display: block;
|
||||
}
|
||||
body {
|
||||
line-height: 1;
|
||||
}
|
||||
ol,
|
||||
ul {
|
||||
list-style: none;
|
||||
}
|
||||
blockquote,
|
||||
q {
|
||||
quotes: none;
|
||||
}
|
||||
blockquote:before,
|
||||
blockquote:after,
|
||||
q:before,
|
||||
q:after {
|
||||
content: '';
|
||||
content: none;
|
||||
}
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
After Width: | Height: | Size: 5.6 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.6 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 9.0 KiB |
@ -0,0 +1,82 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Api Explorer</title>
|
||||
<link href='https://fonts.googleapis.com/css?family=Droid+Sans:400,700' rel='stylesheet' type='text/css'/>
|
||||
<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css" rel="stylesheet">
|
||||
<link href='css/reset.css' media='screen' rel='stylesheet' type='text/css'/>
|
||||
<link href='css/screen.css' media='screen' rel='stylesheet' type='text/css'/>
|
||||
<link href='css/reset.css' media='print' rel='stylesheet' type='text/css'/>
|
||||
<link href='css/screen.css' media='print' rel='stylesheet' type='text/css'/>
|
||||
<script type="text/javascript" src="lib/shred.bundle.js"></script>
|
||||
<script src='lib/jquery-1.8.0.min.js' type='text/javascript'></script>
|
||||
<script src='lib/jquery.slideto.min.js' type='text/javascript'></script>
|
||||
<script src='lib/jquery.wiggle.min.js' type='text/javascript'></script>
|
||||
<script src='lib/jquery.ba-bbq.min.js' type='text/javascript'></script>
|
||||
<script src='lib/handlebars-1.0.0.js' type='text/javascript'></script>
|
||||
<script src='lib/underscore-min.js' type='text/javascript'></script>
|
||||
<script src='lib/backbone-min.js' type='text/javascript'></script>
|
||||
<script src='lib/swagger.js' type='text/javascript'></script>
|
||||
<script src='swagger-ui.js' type='text/javascript'></script>
|
||||
<script src='lib/highlight.7.3.pack.js' type='text/javascript'></script>
|
||||
|
||||
<!-- enabling this will enable oauth2 implicit scope support -->
|
||||
<script src='lib/swagger-oauth.js' type='text/javascript'></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
window.swaggerUi = new SwaggerUi({
|
||||
url: "resources.json",
|
||||
dom_id: "swagger-ui-container",
|
||||
supportedSubmitMethods: ['get', 'post', 'put', 'patch', 'delete'],
|
||||
onComplete: function(swaggerApi, swaggerUi){
|
||||
log("Loaded Api Explorer");
|
||||
|
||||
if(typeof initOAuth == "function") {
|
||||
/*
|
||||
initOAuth({
|
||||
clientId: "your-client-id",
|
||||
realm: "your-realms",
|
||||
appName: "your-app-name"
|
||||
});
|
||||
*/
|
||||
}
|
||||
$('pre code').each(function(i, e) {
|
||||
hljs.highlightBlock(e)
|
||||
});
|
||||
},
|
||||
onFailure: function(data) {
|
||||
log("Unable to Load Api Explorer");
|
||||
},
|
||||
docExpansion: "none"
|
||||
});
|
||||
|
||||
$('#input_apiKey').change(function() {
|
||||
var key = $('#input_apiKey')[0].value;
|
||||
log("key: " + key);
|
||||
if(key && key.trim() != "") {
|
||||
log("added key " + key);
|
||||
window.authorizations.add("key", new ApiKeyAuthorization("api_key", key, "query"));
|
||||
}
|
||||
})
|
||||
window.swaggerUi.load();
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body class="swagger-section">
|
||||
<div id='header'>
|
||||
<div class="swagger-ui-wrap">
|
||||
<a id="logo" href="#">API Explorer</a>
|
||||
<form id='api_selector'>
|
||||
<div class='input'><input placeholder="http://example.com/api" id="input_baseUrl" name="baseUrl" type="hidden" value="resources.json"/></div>
|
||||
<div class='input'><input placeholder="api_key" id="input_apiKey" name="apiKey" type="text"/></div>
|
||||
<div class='input'><a id="explore" href="#">Explore</a></div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="message-bar" class="swagger-ui-wrap"> </div>
|
||||
<div id="swagger-ui-container" class="swagger-ui-wrap"></div>
|
||||
</body>
|
||||
</html>
|
||||
38
htdocs/includes/restler/framework/Luracast/Restler/explorer/lib/backbone-min.js
vendored
Normal file
38
htdocs/includes/restler/framework/Luracast/Restler/explorer/lib/backbone-min.js
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
// Backbone.js 0.9.2
|
||||
|
||||
// (c) 2010-2012 Jeremy Ashkenas, DocumentCloud Inc.
|
||||
// Backbone may be freely distributed under the MIT license.
|
||||
// For all details and documentation:
|
||||
// http://backbonejs.org
|
||||
(function(){var l=this,y=l.Backbone,z=Array.prototype.slice,A=Array.prototype.splice,g;g="undefined"!==typeof exports?exports:l.Backbone={};g.VERSION="0.9.2";var f=l._;!f&&"undefined"!==typeof require&&(f=require("underscore"));var i=l.jQuery||l.Zepto||l.ender;g.setDomLibrary=function(a){i=a};g.noConflict=function(){l.Backbone=y;return this};g.emulateHTTP=!1;g.emulateJSON=!1;var p=/\s+/,k=g.Events={on:function(a,b,c){var d,e,f,g,j;if(!b)return this;a=a.split(p);for(d=this._callbacks||(this._callbacks=
|
||||
{});e=a.shift();)f=(j=d[e])?j.tail:{},f.next=g={},f.context=c,f.callback=b,d[e]={tail:g,next:j?j.next:f};return this},off:function(a,b,c){var d,e,h,g,j,q;if(e=this._callbacks){if(!a&&!b&&!c)return delete this._callbacks,this;for(a=a?a.split(p):f.keys(e);d=a.shift();)if(h=e[d],delete e[d],h&&(b||c))for(g=h.tail;(h=h.next)!==g;)if(j=h.callback,q=h.context,b&&j!==b||c&&q!==c)this.on(d,j,q);return this}},trigger:function(a){var b,c,d,e,f,g;if(!(d=this._callbacks))return this;f=d.all;a=a.split(p);for(g=
|
||||
z.call(arguments,1);b=a.shift();){if(c=d[b])for(e=c.tail;(c=c.next)!==e;)c.callback.apply(c.context||this,g);if(c=f){e=c.tail;for(b=[b].concat(g);(c=c.next)!==e;)c.callback.apply(c.context||this,b)}}return this}};k.bind=k.on;k.unbind=k.off;var o=g.Model=function(a,b){var c;a||(a={});b&&b.parse&&(a=this.parse(a));if(c=n(this,"defaults"))a=f.extend({},c,a);b&&b.collection&&(this.collection=b.collection);this.attributes={};this._escapedAttributes={};this.cid=f.uniqueId("c");this.changed={};this._silent=
|
||||
{};this._pending={};this.set(a,{silent:!0});this.changed={};this._silent={};this._pending={};this._previousAttributes=f.clone(this.attributes);this.initialize.apply(this,arguments)};f.extend(o.prototype,k,{changed:null,_silent:null,_pending:null,idAttribute:"id",initialize:function(){},toJSON:function(){return f.clone(this.attributes)},get:function(a){return this.attributes[a]},escape:function(a){var b;if(b=this._escapedAttributes[a])return b;b=this.get(a);return this._escapedAttributes[a]=f.escape(null==
|
||||
b?"":""+b)},has:function(a){return null!=this.get(a)},set:function(a,b,c){var d,e;f.isObject(a)||null==a?(d=a,c=b):(d={},d[a]=b);c||(c={});if(!d)return this;d instanceof o&&(d=d.attributes);if(c.unset)for(e in d)d[e]=void 0;if(!this._validate(d,c))return!1;this.idAttribute in d&&(this.id=d[this.idAttribute]);var b=c.changes={},h=this.attributes,g=this._escapedAttributes,j=this._previousAttributes||{};for(e in d){a=d[e];if(!f.isEqual(h[e],a)||c.unset&&f.has(h,e))delete g[e],(c.silent?this._silent:
|
||||
b)[e]=!0;c.unset?delete h[e]:h[e]=a;!f.isEqual(j[e],a)||f.has(h,e)!=f.has(j,e)?(this.changed[e]=a,c.silent||(this._pending[e]=!0)):(delete this.changed[e],delete this._pending[e])}c.silent||this.change(c);return this},unset:function(a,b){(b||(b={})).unset=!0;return this.set(a,null,b)},clear:function(a){(a||(a={})).unset=!0;return this.set(f.clone(this.attributes),a)},fetch:function(a){var a=a?f.clone(a):{},b=this,c=a.success;a.success=function(d,e,f){if(!b.set(b.parse(d,f),a))return!1;c&&c(b,d)};
|
||||
a.error=g.wrapError(a.error,b,a);return(this.sync||g.sync).call(this,"read",this,a)},save:function(a,b,c){var d,e;f.isObject(a)||null==a?(d=a,c=b):(d={},d[a]=b);c=c?f.clone(c):{};if(c.wait){if(!this._validate(d,c))return!1;e=f.clone(this.attributes)}a=f.extend({},c,{silent:!0});if(d&&!this.set(d,c.wait?a:c))return!1;var h=this,i=c.success;c.success=function(a,b,e){b=h.parse(a,e);if(c.wait){delete c.wait;b=f.extend(d||{},b)}if(!h.set(b,c))return false;i?i(h,a):h.trigger("sync",h,a,c)};c.error=g.wrapError(c.error,
|
||||
h,c);b=this.isNew()?"create":"update";b=(this.sync||g.sync).call(this,b,this,c);c.wait&&this.set(e,a);return b},destroy:function(a){var a=a?f.clone(a):{},b=this,c=a.success,d=function(){b.trigger("destroy",b,b.collection,a)};if(this.isNew())return d(),!1;a.success=function(e){a.wait&&d();c?c(b,e):b.trigger("sync",b,e,a)};a.error=g.wrapError(a.error,b,a);var e=(this.sync||g.sync).call(this,"delete",this,a);a.wait||d();return e},url:function(){var a=n(this,"urlRoot")||n(this.collection,"url")||t();
|
||||
return this.isNew()?a:a+("/"==a.charAt(a.length-1)?"":"/")+encodeURIComponent(this.id)},parse:function(a){return a},clone:function(){return new this.constructor(this.attributes)},isNew:function(){return null==this.id},change:function(a){a||(a={});var b=this._changing;this._changing=!0;for(var c in this._silent)this._pending[c]=!0;var d=f.extend({},a.changes,this._silent);this._silent={};for(c in d)this.trigger("change:"+c,this,this.get(c),a);if(b)return this;for(;!f.isEmpty(this._pending);){this._pending=
|
||||
{};this.trigger("change",this,a);for(c in this.changed)!this._pending[c]&&!this._silent[c]&&delete this.changed[c];this._previousAttributes=f.clone(this.attributes)}this._changing=!1;return this},hasChanged:function(a){return!arguments.length?!f.isEmpty(this.changed):f.has(this.changed,a)},changedAttributes:function(a){if(!a)return this.hasChanged()?f.clone(this.changed):!1;var b,c=!1,d=this._previousAttributes,e;for(e in a)if(!f.isEqual(d[e],b=a[e]))(c||(c={}))[e]=b;return c},previous:function(a){return!arguments.length||
|
||||
!this._previousAttributes?null:this._previousAttributes[a]},previousAttributes:function(){return f.clone(this._previousAttributes)},isValid:function(){return!this.validate(this.attributes)},_validate:function(a,b){if(b.silent||!this.validate)return!0;var a=f.extend({},this.attributes,a),c=this.validate(a,b);if(!c)return!0;b&&b.error?b.error(this,c,b):this.trigger("error",this,c,b);return!1}});var r=g.Collection=function(a,b){b||(b={});b.model&&(this.model=b.model);b.comparator&&(this.comparator=b.comparator);
|
||||
this._reset();this.initialize.apply(this,arguments);a&&this.reset(a,{silent:!0,parse:b.parse})};f.extend(r.prototype,k,{model:o,initialize:function(){},toJSON:function(a){return this.map(function(b){return b.toJSON(a)})},add:function(a,b){var c,d,e,g,i,j={},k={},l=[];b||(b={});a=f.isArray(a)?a.slice():[a];c=0;for(d=a.length;c<d;c++){if(!(e=a[c]=this._prepareModel(a[c],b)))throw Error("Can't add an invalid model to a collection");g=e.cid;i=e.id;j[g]||this._byCid[g]||null!=i&&(k[i]||this._byId[i])?
|
||||
l.push(c):j[g]=k[i]=e}for(c=l.length;c--;)a.splice(l[c],1);c=0;for(d=a.length;c<d;c++)(e=a[c]).on("all",this._onModelEvent,this),this._byCid[e.cid]=e,null!=e.id&&(this._byId[e.id]=e);this.length+=d;A.apply(this.models,[null!=b.at?b.at:this.models.length,0].concat(a));this.comparator&&this.sort({silent:!0});if(b.silent)return this;c=0;for(d=this.models.length;c<d;c++)if(j[(e=this.models[c]).cid])b.index=c,e.trigger("add",e,this,b);return this},remove:function(a,b){var c,d,e,g;b||(b={});a=f.isArray(a)?
|
||||
a.slice():[a];c=0;for(d=a.length;c<d;c++)if(g=this.getByCid(a[c])||this.get(a[c]))delete this._byId[g.id],delete this._byCid[g.cid],e=this.indexOf(g),this.models.splice(e,1),this.length--,b.silent||(b.index=e,g.trigger("remove",g,this,b)),this._removeReference(g);return this},push:function(a,b){a=this._prepareModel(a,b);this.add(a,b);return a},pop:function(a){var b=this.at(this.length-1);this.remove(b,a);return b},unshift:function(a,b){a=this._prepareModel(a,b);this.add(a,f.extend({at:0},b));return a},
|
||||
shift:function(a){var b=this.at(0);this.remove(b,a);return b},get:function(a){return null==a?void 0:this._byId[null!=a.id?a.id:a]},getByCid:function(a){return a&&this._byCid[a.cid||a]},at:function(a){return this.models[a]},where:function(a){return f.isEmpty(a)?[]:this.filter(function(b){for(var c in a)if(a[c]!==b.get(c))return!1;return!0})},sort:function(a){a||(a={});if(!this.comparator)throw Error("Cannot sort a set without a comparator");var b=f.bind(this.comparator,this);1==this.comparator.length?
|
||||
this.models=this.sortBy(b):this.models.sort(b);a.silent||this.trigger("reset",this,a);return this},pluck:function(a){return f.map(this.models,function(b){return b.get(a)})},reset:function(a,b){a||(a=[]);b||(b={});for(var c=0,d=this.models.length;c<d;c++)this._removeReference(this.models[c]);this._reset();this.add(a,f.extend({silent:!0},b));b.silent||this.trigger("reset",this,b);return this},fetch:function(a){a=a?f.clone(a):{};void 0===a.parse&&(a.parse=!0);var b=this,c=a.success;a.success=function(d,
|
||||
e,f){b[a.add?"add":"reset"](b.parse(d,f),a);c&&c(b,d)};a.error=g.wrapError(a.error,b,a);return(this.sync||g.sync).call(this,"read",this,a)},create:function(a,b){var c=this,b=b?f.clone(b):{},a=this._prepareModel(a,b);if(!a)return!1;b.wait||c.add(a,b);var d=b.success;b.success=function(e,f){b.wait&&c.add(e,b);d?d(e,f):e.trigger("sync",a,f,b)};a.save(null,b);return a},parse:function(a){return a},chain:function(){return f(this.models).chain()},_reset:function(){this.length=0;this.models=[];this._byId=
|
||||
{};this._byCid={}},_prepareModel:function(a,b){b||(b={});a instanceof o?a.collection||(a.collection=this):(b.collection=this,a=new this.model(a,b),a._validate(a.attributes,b)||(a=!1));return a},_removeReference:function(a){this==a.collection&&delete a.collection;a.off("all",this._onModelEvent,this)},_onModelEvent:function(a,b,c,d){("add"==a||"remove"==a)&&c!=this||("destroy"==a&&this.remove(b,d),b&&a==="change:"+b.idAttribute&&(delete this._byId[b.previous(b.idAttribute)],this._byId[b.id]=b),this.trigger.apply(this,
|
||||
arguments))}});f.each("forEach,each,map,reduce,reduceRight,find,detect,filter,select,reject,every,all,some,any,include,contains,invoke,max,min,sortBy,sortedIndex,toArray,size,first,initial,rest,last,without,indexOf,shuffle,lastIndexOf,isEmpty,groupBy".split(","),function(a){r.prototype[a]=function(){return f[a].apply(f,[this.models].concat(f.toArray(arguments)))}});var u=g.Router=function(a){a||(a={});a.routes&&(this.routes=a.routes);this._bindRoutes();this.initialize.apply(this,arguments)},B=/:\w+/g,
|
||||
C=/\*\w+/g,D=/[-[\]{}()+?.,\\^$|#\s]/g;f.extend(u.prototype,k,{initialize:function(){},route:function(a,b,c){g.history||(g.history=new m);f.isRegExp(a)||(a=this._routeToRegExp(a));c||(c=this[b]);g.history.route(a,f.bind(function(d){d=this._extractParameters(a,d);c&&c.apply(this,d);this.trigger.apply(this,["route:"+b].concat(d));g.history.trigger("route",this,b,d)},this));return this},navigate:function(a,b){g.history.navigate(a,b)},_bindRoutes:function(){if(this.routes){var a=[],b;for(b in this.routes)a.unshift([b,
|
||||
this.routes[b]]);b=0;for(var c=a.length;b<c;b++)this.route(a[b][0],a[b][1],this[a[b][1]])}},_routeToRegExp:function(a){a=a.replace(D,"\\$&").replace(B,"([^/]+)").replace(C,"(.*?)");return RegExp("^"+a+"$")},_extractParameters:function(a,b){return a.exec(b).slice(1)}});var m=g.History=function(){this.handlers=[];f.bindAll(this,"checkUrl")},s=/^[#\/]/,E=/msie [\w.]+/;m.started=!1;f.extend(m.prototype,k,{interval:50,getHash:function(a){return(a=(a?a.location:window.location).href.match(/#(.*)$/))?a[1]:
|
||||
""},getFragment:function(a,b){if(null==a)if(this._hasPushState||b){var a=window.location.pathname,c=window.location.search;c&&(a+=c)}else a=this.getHash();a.indexOf(this.options.root)||(a=a.substr(this.options.root.length));return a.replace(s,"")},start:function(a){if(m.started)throw Error("Backbone.history has already been started");m.started=!0;this.options=f.extend({},{root:"/"},this.options,a);this._wantsHashChange=!1!==this.options.hashChange;this._wantsPushState=!!this.options.pushState;this._hasPushState=
|
||||
!(!this.options.pushState||!window.history||!window.history.pushState);var a=this.getFragment(),b=document.documentMode;if(b=E.exec(navigator.userAgent.toLowerCase())&&(!b||7>=b))this.iframe=i('<iframe src="javascript:0" tabindex="-1" />').hide().appendTo("body")[0].contentWindow,this.navigate(a);this._hasPushState?i(window).bind("popstate",this.checkUrl):this._wantsHashChange&&"onhashchange"in window&&!b?i(window).bind("hashchange",this.checkUrl):this._wantsHashChange&&(this._checkUrlInterval=setInterval(this.checkUrl,
|
||||
this.interval));this.fragment=a;a=window.location;b=a.pathname==this.options.root;if(this._wantsHashChange&&this._wantsPushState&&!this._hasPushState&&!b)return this.fragment=this.getFragment(null,!0),window.location.replace(this.options.root+"#"+this.fragment),!0;this._wantsPushState&&this._hasPushState&&b&&a.hash&&(this.fragment=this.getHash().replace(s,""),window.history.replaceState({},document.title,a.protocol+"//"+a.host+this.options.root+this.fragment));if(!this.options.silent)return this.loadUrl()},
|
||||
stop:function(){i(window).unbind("popstate",this.checkUrl).unbind("hashchange",this.checkUrl);clearInterval(this._checkUrlInterval);m.started=!1},route:function(a,b){this.handlers.unshift({route:a,callback:b})},checkUrl:function(){var a=this.getFragment();a==this.fragment&&this.iframe&&(a=this.getFragment(this.getHash(this.iframe)));if(a==this.fragment)return!1;this.iframe&&this.navigate(a);this.loadUrl()||this.loadUrl(this.getHash())},loadUrl:function(a){var b=this.fragment=this.getFragment(a);return f.any(this.handlers,
|
||||
function(a){if(a.route.test(b))return a.callback(b),!0})},navigate:function(a,b){if(!m.started)return!1;if(!b||!0===b)b={trigger:b};var c=(a||"").replace(s,"");this.fragment!=c&&(this._hasPushState?(0!=c.indexOf(this.options.root)&&(c=this.options.root+c),this.fragment=c,window.history[b.replace?"replaceState":"pushState"]({},document.title,c)):this._wantsHashChange?(this.fragment=c,this._updateHash(window.location,c,b.replace),this.iframe&&c!=this.getFragment(this.getHash(this.iframe))&&(b.replace||
|
||||
this.iframe.document.open().close(),this._updateHash(this.iframe.location,c,b.replace))):window.location.assign(this.options.root+a),b.trigger&&this.loadUrl(a))},_updateHash:function(a,b,c){c?a.replace(a.toString().replace(/(javascript:|#).*$/,"")+"#"+b):a.hash=b}});var v=g.View=function(a){this.cid=f.uniqueId("view");this._configure(a||{});this._ensureElement();this.initialize.apply(this,arguments);this.delegateEvents()},F=/^(\S+)\s*(.*)$/,w="model,collection,el,id,attributes,className,tagName".split(",");
|
||||
f.extend(v.prototype,k,{tagName:"div",$:function(a){return this.$el.find(a)},initialize:function(){},render:function(){return this},remove:function(){this.$el.remove();return this},make:function(a,b,c){a=document.createElement(a);b&&i(a).attr(b);c&&i(a).html(c);return a},setElement:function(a,b){this.$el&&this.undelegateEvents();this.$el=a instanceof i?a:i(a);this.el=this.$el[0];!1!==b&&this.delegateEvents();return this},delegateEvents:function(a){if(a||(a=n(this,"events"))){this.undelegateEvents();
|
||||
for(var b in a){var c=a[b];f.isFunction(c)||(c=this[a[b]]);if(!c)throw Error('Method "'+a[b]+'" does not exist');var d=b.match(F),e=d[1],d=d[2],c=f.bind(c,this),e=e+(".delegateEvents"+this.cid);""===d?this.$el.bind(e,c):this.$el.delegate(d,e,c)}}},undelegateEvents:function(){this.$el.unbind(".delegateEvents"+this.cid)},_configure:function(a){this.options&&(a=f.extend({},this.options,a));for(var b=0,c=w.length;b<c;b++){var d=w[b];a[d]&&(this[d]=a[d])}this.options=a},_ensureElement:function(){if(this.el)this.setElement(this.el,
|
||||
!1);else{var a=n(this,"attributes")||{};this.id&&(a.id=this.id);this.className&&(a["class"]=this.className);this.setElement(this.make(this.tagName,a),!1)}}});o.extend=r.extend=u.extend=v.extend=function(a,b){var c=G(this,a,b);c.extend=this.extend;return c};var H={create:"POST",update:"PUT","delete":"DELETE",read:"GET"};g.sync=function(a,b,c){var d=H[a];c||(c={});var e={type:d,dataType:"json"};c.url||(e.url=n(b,"url")||t());if(!c.data&&b&&("create"==a||"update"==a))e.contentType="application/json",
|
||||
e.data=JSON.stringify(b.toJSON());g.emulateJSON&&(e.contentType="application/x-www-form-urlencoded",e.data=e.data?{model:e.data}:{});if(g.emulateHTTP&&("PUT"===d||"DELETE"===d))g.emulateJSON&&(e.data._method=d),e.type="POST",e.beforeSend=function(a){a.setRequestHeader("X-HTTP-Method-Override",d)};"GET"!==e.type&&!g.emulateJSON&&(e.processData=!1);return i.ajax(f.extend(e,c))};g.wrapError=function(a,b,c){return function(d,e){e=d===b?e:d;a?a(b,e,c):b.trigger("error",b,e,c)}};var x=function(){},G=function(a,
|
||||
b,c){var d;d=b&&b.hasOwnProperty("constructor")?b.constructor:function(){a.apply(this,arguments)};f.extend(d,a);x.prototype=a.prototype;d.prototype=new x;b&&f.extend(d.prototype,b);c&&f.extend(d,c);d.prototype.constructor=d;d.__super__=a.prototype;return d},n=function(a,b){return!a||!a[b]?null:f.isFunction(a[b])?a[b]():a[b]},t=function(){throw Error('A "url" property or function must be specified');}}).call(this);
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
2
htdocs/includes/restler/framework/Luracast/Restler/explorer/lib/jquery-1.8.0.min.js
vendored
Normal file
2
htdocs/includes/restler/framework/Luracast/Restler/explorer/lib/jquery-1.8.0.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
18
htdocs/includes/restler/framework/Luracast/Restler/explorer/lib/jquery.ba-bbq.min.js
vendored
Normal file
18
htdocs/includes/restler/framework/Luracast/Restler/explorer/lib/jquery.ba-bbq.min.js
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* jQuery BBQ: Back Button & Query Library - v1.2.1 - 2/17/2010
|
||||
* http://benalman.com/projects/jquery-bbq-plugin/
|
||||
*
|
||||
* Copyright (c) 2010 "Cowboy" Ben Alman
|
||||
* Dual licensed under the MIT and GPL licenses.
|
||||
* http://benalman.com/about/license/
|
||||
*/
|
||||
(function($,p){var i,m=Array.prototype.slice,r=decodeURIComponent,a=$.param,c,l,v,b=$.bbq=$.bbq||{},q,u,j,e=$.event.special,d="hashchange",A="querystring",D="fragment",y="elemUrlAttr",g="location",k="href",t="src",x=/^.*\?|#.*$/g,w=/^.*\#/,h,C={};function E(F){return typeof F==="string"}function B(G){var F=m.call(arguments,1);return function(){return G.apply(this,F.concat(m.call(arguments)))}}function n(F){return F.replace(/^[^#]*#?(.*)$/,"$1")}function o(F){return F.replace(/(?:^[^?#]*\?([^#]*).*$)?.*/,"$1")}function f(H,M,F,I,G){var O,L,K,N,J;if(I!==i){K=F.match(H?/^([^#]*)\#?(.*)$/:/^([^#?]*)\??([^#]*)(#?.*)/);J=K[3]||"";if(G===2&&E(I)){L=I.replace(H?w:x,"")}else{N=l(K[2]);I=E(I)?l[H?D:A](I):I;L=G===2?I:G===1?$.extend({},I,N):$.extend({},N,I);L=a(L);if(H){L=L.replace(h,r)}}O=K[1]+(H?"#":L||!K[1]?"?":"")+L+J}else{O=M(F!==i?F:p[g][k])}return O}a[A]=B(f,0,o);a[D]=c=B(f,1,n);c.noEscape=function(G){G=G||"";var F=$.map(G.split(""),encodeURIComponent);h=new RegExp(F.join("|"),"g")};c.noEscape(",/");$.deparam=l=function(I,F){var H={},G={"true":!0,"false":!1,"null":null};$.each(I.replace(/\+/g," ").split("&"),function(L,Q){var K=Q.split("="),P=r(K[0]),J,O=H,M=0,R=P.split("]["),N=R.length-1;if(/\[/.test(R[0])&&/\]$/.test(R[N])){R[N]=R[N].replace(/\]$/,"");R=R.shift().split("[").concat(R);N=R.length-1}else{N=0}if(K.length===2){J=r(K[1]);if(F){J=J&&!isNaN(J)?+J:J==="undefined"?i:G[J]!==i?G[J]:J}if(N){for(;M<=N;M++){P=R[M]===""?O.length:R[M];O=O[P]=M<N?O[P]||(R[M+1]&&isNaN(R[M+1])?{}:[]):J}}else{if($.isArray(H[P])){H[P].push(J)}else{if(H[P]!==i){H[P]=[H[P],J]}else{H[P]=J}}}}else{if(P){H[P]=F?i:""}}});return H};function z(H,F,G){if(F===i||typeof F==="boolean"){G=F;F=a[H?D:A]()}else{F=E(F)?F.replace(H?w:x,""):F}return l(F,G)}l[A]=B(z,0);l[D]=v=B(z,1);$[y]||($[y]=function(F){return $.extend(C,F)})({a:k,base:k,iframe:t,img:t,input:t,form:"action",link:k,script:t});j=$[y];function s(I,G,H,F){if(!E(H)&&typeof H!=="object"){F=H;H=G;G=i}return this.each(function(){var L=$(this),J=G||j()[(this.nodeName||"").toLowerCase()]||"",K=J&&L.attr(J)||"";L.attr(J,a[I](K,H,F))})}$.fn[A]=B(s,A);$.fn[D]=B(s,D);b.pushState=q=function(I,F){if(E(I)&&/^#/.test(I)&&F===i){F=2}var H=I!==i,G=c(p[g][k],H?I:{},H?F:2);p[g][k]=G+(/#/.test(G)?"":"#")};b.getState=u=function(F,G){return F===i||typeof F==="boolean"?v(F):v(G)[F]};b.removeState=function(F){var G={};if(F!==i){G=u();$.each($.isArray(F)?F:arguments,function(I,H){delete G[H]})}q(G,2)};e[d]=$.extend(e[d],{add:function(F){var H;function G(J){var I=J[D]=c();J.getState=function(K,L){return K===i||typeof K==="boolean"?l(I,K):l(I,L)[K]};H.apply(this,arguments)}if($.isFunction(F)){H=F;return G}else{H=F.handler;F.handler=G}}})})(jQuery,this);
|
||||
/*
|
||||
* jQuery hashchange event - v1.2 - 2/11/2010
|
||||
* http://benalman.com/projects/jquery-hashchange-plugin/
|
||||
*
|
||||
* Copyright (c) 2010 "Cowboy" Ben Alman
|
||||
* Dual licensed under the MIT and GPL licenses.
|
||||
* http://benalman.com/about/license/
|
||||
*/
|
||||
(function($,i,b){var j,k=$.event.special,c="location",d="hashchange",l="href",f=$.browser,g=document.documentMode,h=f.msie&&(g===b||g<8),e="on"+d in i&&!h;function a(m){m=m||i[c][l];return m.replace(/^[^#]*#?(.*)$/,"$1")}$[d+"Delay"]=100;k[d]=$.extend(k[d],{setup:function(){if(e){return false}$(j.start)},teardown:function(){if(e){return false}$(j.stop)}});j=(function(){var m={},r,n,o,q;function p(){o=q=function(s){return s};if(h){n=$('<iframe src="javascript:0"/>').hide().insertAfter("body")[0].contentWindow;q=function(){return a(n.document[c][l])};o=function(u,s){if(u!==s){var t=n.document;t.open().close();t[c].hash="#"+u}};o(a())}}m.start=function(){if(r){return}var t=a();o||p();(function s(){var v=a(),u=q(t);if(v!==t){o(t=v,u);$(i).trigger(d)}else{if(u!==t){i[c][l]=i[c][l].replace(/#.*/,"")+"#"+u}}r=setTimeout(s,$[d+"Delay"])})()};m.stop=function(){if(!n){r&&clearTimeout(r);r=0}};return m})()})(jQuery,this);
|
||||
1
htdocs/includes/restler/framework/Luracast/Restler/explorer/lib/jquery.slideto.min.js
vendored
Normal file
1
htdocs/includes/restler/framework/Luracast/Restler/explorer/lib/jquery.slideto.min.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
(function(b){b.fn.slideto=function(a){a=b.extend({slide_duration:"slow",highlight_duration:3E3,highlight:true,highlight_color:"#FFFF99"},a);return this.each(function(){obj=b(this);b("body").animate({scrollTop:obj.offset().top},a.slide_duration,function(){a.highlight&&b.ui.version&&obj.effect("highlight",{color:a.highlight_color},a.highlight_duration)})})}})(jQuery);
|
||||
8
htdocs/includes/restler/framework/Luracast/Restler/explorer/lib/jquery.wiggle.min.js
vendored
Normal file
8
htdocs/includes/restler/framework/Luracast/Restler/explorer/lib/jquery.wiggle.min.js
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
/*
|
||||
jQuery Wiggle
|
||||
Author: WonderGroup, Jordan Thomas
|
||||
URL: http://labs.wondergroup.com/demos/mini-ui/index.html
|
||||
License: MIT (http://en.wikipedia.org/wiki/MIT_License)
|
||||
*/
|
||||
jQuery.fn.wiggle=function(o){var d={speed:50,wiggles:3,travel:5,callback:null};var o=jQuery.extend(d,o);return this.each(function(){var cache=this;var wrap=jQuery(this).wrap('<div class="wiggle-wrap"></div>').css("position","relative");var calls=0;for(i=1;i<=o.wiggles;i++){jQuery(this).animate({left:"-="+o.travel},o.speed).animate({left:"+="+o.travel*2},o.speed*2).animate({left:"-="+o.travel},o.speed,function(){calls++;if(jQuery(cache).parent().hasClass('wiggle-wrap')){jQuery(cache).parent().replaceWith(cache);}
|
||||
if(calls==o.wiggles&&jQuery.isFunction(o.callback)){o.callback();}});}});};
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,193 @@
|
||||
|
||||
// The purpose of the `Content` object is to abstract away the data conversions
|
||||
// to and from raw content entities as strings. For example, you want to be able
|
||||
// to pass in a Javascript object and have it be automatically converted into a
|
||||
// JSON string if the `content-type` is set to a JSON-based media type.
|
||||
// Conversely, you want to be able to transparently get back a Javascript object
|
||||
// in the response if the `content-type` is a JSON-based media-type.
|
||||
|
||||
// One limitation of the current implementation is that it [assumes the `charset` is UTF-8](https://github.com/spire-io/shred/issues/5).
|
||||
|
||||
// The `Content` constructor takes an options object, which *must* have either a
|
||||
// `body` or `data` property and *may* have a `type` property indicating the
|
||||
// media type. If there is no `type` attribute, a default will be inferred.
|
||||
var Content = function(options) {
|
||||
this.body = options.body;
|
||||
this.data = options.data;
|
||||
this.type = options.type;
|
||||
};
|
||||
|
||||
Content.prototype = {
|
||||
// Treat `toString()` as asking for the `content.body`. That is, the raw content entity.
|
||||
//
|
||||
// toString: function() { return this.body; }
|
||||
//
|
||||
// Commented out, but I've forgotten why. :/
|
||||
};
|
||||
|
||||
|
||||
// `Content` objects have the following attributes:
|
||||
Object.defineProperties(Content.prototype,{
|
||||
|
||||
// - **type**. Typically accessed as `content.type`, reflects the `content-type`
|
||||
// header associated with the request or response. If not passed as an options
|
||||
// to the constructor or set explicitly, it will infer the type the `data`
|
||||
// attribute, if possible, and, failing that, will default to `text/plain`.
|
||||
type: {
|
||||
get: function() {
|
||||
if (this._type) {
|
||||
return this._type;
|
||||
} else {
|
||||
if (this._data) {
|
||||
switch(typeof this._data) {
|
||||
case "string": return "text/plain";
|
||||
case "object": return "application/json";
|
||||
}
|
||||
}
|
||||
}
|
||||
return "text/plain";
|
||||
},
|
||||
set: function(value) {
|
||||
this._type = value;
|
||||
return this;
|
||||
},
|
||||
enumerable: true
|
||||
},
|
||||
|
||||
// - **data**. Typically accessed as `content.data`, reflects the content entity
|
||||
// converted into Javascript data. This can be a string, if the `type` is, say,
|
||||
// `text/plain`, but can also be a Javascript object. The conversion applied is
|
||||
// based on the `processor` attribute. The `data` attribute can also be set
|
||||
// directly, in which case the conversion will be done the other way, to infer
|
||||
// the `body` attribute.
|
||||
data: {
|
||||
get: function() {
|
||||
if (this._body) {
|
||||
return this.processor.parser(this._body);
|
||||
} else {
|
||||
return this._data;
|
||||
}
|
||||
},
|
||||
set: function(data) {
|
||||
if (this._body&&data) Errors.setDataWithBody(this);
|
||||
this._data = data;
|
||||
return this;
|
||||
},
|
||||
enumerable: true
|
||||
},
|
||||
|
||||
// - **body**. Typically accessed as `content.body`, reflects the content entity
|
||||
// as a UTF-8 string. It is the mirror of the `data` attribute. If you set the
|
||||
// `data` attribute, the `body` attribute will be inferred and vice-versa. If
|
||||
// you attempt to set both, an exception is raised.
|
||||
body: {
|
||||
get: function() {
|
||||
if (this._data) {
|
||||
return this.processor.stringify(this._data);
|
||||
} else {
|
||||
return this._body.toString();
|
||||
}
|
||||
},
|
||||
set: function(body) {
|
||||
if (this._data&&body) Errors.setBodyWithData(this);
|
||||
this._body = body;
|
||||
return this;
|
||||
},
|
||||
enumerable: true
|
||||
},
|
||||
|
||||
// - **processor**. The functions that will be used to convert to/from `data` and
|
||||
// `body` attributes. You can add processors. The two that are built-in are for
|
||||
// `text/plain`, which is basically an identity transformation and
|
||||
// `application/json` and other JSON-based media types (including custom media
|
||||
// types with `+json`). You can add your own processors. See below.
|
||||
processor: {
|
||||
get: function() {
|
||||
var processor = Content.processors[this.type];
|
||||
if (processor) {
|
||||
return processor;
|
||||
} else {
|
||||
// Return the first processor that matches any part of the
|
||||
// content type. ex: application/vnd.foobar.baz+json will match json.
|
||||
var main = this.type.split(";")[0];
|
||||
var parts = main.split(/\+|\//);
|
||||
for (var i=0, l=parts.length; i < l; i++) {
|
||||
processor = Content.processors[parts[i]]
|
||||
}
|
||||
return processor || {parser:identity,stringify:toString};
|
||||
}
|
||||
},
|
||||
enumerable: true
|
||||
},
|
||||
|
||||
// - **length**. Typically accessed as `content.length`, returns the length in
|
||||
// bytes of the raw content entity.
|
||||
length: {
|
||||
get: function() {
|
||||
if (typeof Buffer !== 'undefined') {
|
||||
return Buffer.byteLength(this.body);
|
||||
}
|
||||
return this.body.length;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Content.processors = {};
|
||||
|
||||
// The `registerProcessor` function allows you to add your own processors to
|
||||
// convert content entities. Each processor consists of a Javascript object with
|
||||
// two properties:
|
||||
// - **parser**. The function used to parse a raw content entity and convert it
|
||||
// into a Javascript data type.
|
||||
// - **stringify**. The function used to convert a Javascript data type into a
|
||||
// raw content entity.
|
||||
Content.registerProcessor = function(types,processor) {
|
||||
|
||||
// You can pass an array of types that will trigger this processor, or just one.
|
||||
// We determine the array via duck-typing here.
|
||||
if (types.forEach) {
|
||||
types.forEach(function(type) {
|
||||
Content.processors[type] = processor;
|
||||
});
|
||||
} else {
|
||||
// If you didn't pass an array, we just use what you pass in.
|
||||
Content.processors[types] = processor;
|
||||
}
|
||||
};
|
||||
|
||||
// Register the identity processor, which is used for text-based media types.
|
||||
var identity = function(x) { return x; }
|
||||
, toString = function(x) { return x.toString(); }
|
||||
Content.registerProcessor(
|
||||
["text/html","text/plain","text"],
|
||||
{ parser: identity, stringify: toString });
|
||||
|
||||
// Register the JSON processor, which is used for JSON-based media types.
|
||||
Content.registerProcessor(
|
||||
["application/json; charset=utf-8","application/json","json"],
|
||||
{
|
||||
parser: function(string) {
|
||||
return JSON.parse(string);
|
||||
},
|
||||
stringify: function(data) {
|
||||
return JSON.stringify(data); }});
|
||||
|
||||
var qs = require('querystring');
|
||||
// Register the post processor, which is used for JSON-based media types.
|
||||
Content.registerProcessor(
|
||||
["application/x-www-form-urlencoded"],
|
||||
{ parser : qs.parse, stringify : qs.stringify });
|
||||
|
||||
// Error functions are defined separately here in an attempt to make the code
|
||||
// easier to read.
|
||||
var Errors = {
|
||||
setDataWithBody: function(object) {
|
||||
throw new Error("Attempt to set data attribute of a content object " +
|
||||
"when the body attributes was already set.");
|
||||
},
|
||||
setBodyWithData: function(object) {
|
||||
throw new Error("Attempt to set body attribute of a content object " +
|
||||
"when the data attributes was already set.");
|
||||
}
|
||||
}
|
||||
module.exports = Content;
|
||||
@ -0,0 +1,218 @@
|
||||
var appName;
|
||||
var popupMask;
|
||||
var popupDialog;
|
||||
var clientId;
|
||||
var realm;
|
||||
|
||||
function handleLogin() {
|
||||
var scopes = [];
|
||||
|
||||
if(window.swaggerUi.api.authSchemes
|
||||
&& window.swaggerUi.api.authSchemes.oauth2
|
||||
&& window.swaggerUi.api.authSchemes.oauth2.scopes) {
|
||||
scopes = window.swaggerUi.api.authSchemes.oauth2.scopes;
|
||||
}
|
||||
|
||||
if(window.swaggerUi.api
|
||||
&& window.swaggerUi.api.info) {
|
||||
appName = window.swaggerUi.api.info.title;
|
||||
}
|
||||
|
||||
if(popupDialog.length > 0)
|
||||
popupDialog = popupDialog.last();
|
||||
else {
|
||||
popupDialog = $(
|
||||
[
|
||||
'<div class="api-popup-dialog">',
|
||||
'<div class="api-popup-title">Select OAuth2.0 Scopes</div>',
|
||||
'<div class="api-popup-content">',
|
||||
'<p>Scopes are used to grant an application different levels of access to data on behalf of the end user. Each API may declare one or more scopes.',
|
||||
'<a href="#">Learn how to use</a>',
|
||||
'</p>',
|
||||
'<p><strong>' + appName + '</strong> API requires the following scopes. Select which ones you want to grant to Swagger UI.</p>',
|
||||
'<ul class="api-popup-scopes">',
|
||||
'</ul>',
|
||||
'<p class="error-msg"></p>',
|
||||
'<div class="api-popup-actions"><button class="api-popup-authbtn api-button green" type="button">Authorize</button><button class="api-popup-cancel api-button gray" type="button">Cancel</button></div>',
|
||||
'</div>',
|
||||
'</div>'].join(''));
|
||||
$(document.body).append(popupDialog);
|
||||
|
||||
popup = popupDialog.find('ul.api-popup-scopes').empty();
|
||||
for (i = 0; i < scopes.length; i ++) {
|
||||
scope = scopes[i];
|
||||
str = '<li><input type="checkbox" id="scope_' + i + '" scope="' + scope.scope + '"/>' + '<label for="scope_' + i + '">' + scope.scope;
|
||||
if (scope.description) {
|
||||
str += '<br/><span class="api-scope-desc">' + scope.description + '</span>';
|
||||
}
|
||||
str += '</label></li>';
|
||||
popup.append(str);
|
||||
}
|
||||
|
||||
|
||||
var $win = $(window),
|
||||
dw = $win.width(),
|
||||
dh = $win.height(),
|
||||
st = $win.scrollTop(),
|
||||
dlgWd = popupDialog.outerWidth(),
|
||||
dlgHt = popupDialog.outerHeight(),
|
||||
top = (dh -dlgHt)/2 + st,
|
||||
left = (dw - dlgWd)/2;
|
||||
|
||||
popupDialog.css({
|
||||
top: (top < 0? 0 : top) + 'px',
|
||||
left: (left < 0? 0 : left) + 'px'
|
||||
});
|
||||
|
||||
popupDialog.find('button.api-popup-cancel').click(function() {
|
||||
popupMask.hide();
|
||||
popupDialog.hide();
|
||||
});
|
||||
popupDialog.find('button.api-popup-authbtn').click(function() {
|
||||
popupMask.hide();
|
||||
popupDialog.hide();
|
||||
|
||||
var authSchemes = window.swaggerUi.api.authSchemes;
|
||||
var location = window.location;
|
||||
var locationUrl = location.protocol + '//' + location.host + location.pathname;
|
||||
var redirectUrl = locationUrl.replace("index.html","").concat("/o2c.html").replace("//o2c.html","/o2c.html");
|
||||
var url = null;
|
||||
|
||||
var p = window.swaggerUi.api.authSchemes;
|
||||
for (var key in p) {
|
||||
if (p.hasOwnProperty(key)) {
|
||||
var o = p[key].grantTypes;
|
||||
for(var t in o) {
|
||||
if(o.hasOwnProperty(t) && t === 'implicit') {
|
||||
var dets = o[t];
|
||||
url = dets.loginEndpoint.url + "?response_type=token";
|
||||
window.swaggerUi.tokenName = dets.tokenName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var scopes = [];
|
||||
var scopeForUrl='';
|
||||
var o = $('.api-popup-scopes').find('input:checked');
|
||||
|
||||
for(var k =0; k < o.length; k++) {
|
||||
scopes.push($(o[k]).attr("scope"));
|
||||
if(k > 0){
|
||||
scopeForUrl+=' ';
|
||||
}
|
||||
scopeForUrl+=$(o[k]).attr("scope");
|
||||
}
|
||||
|
||||
window.enabledScopes=scopes;
|
||||
|
||||
|
||||
url += '&redirect_uri=' + encodeURIComponent(redirectUrl);
|
||||
url += '&realm=' + encodeURIComponent(realm);
|
||||
url += '&client_id=' + encodeURIComponent(clientId);
|
||||
url += '&scope=' + encodeURIComponent(scopeForUrl);
|
||||
|
||||
window.open(url);
|
||||
});
|
||||
}
|
||||
popupMask.show();
|
||||
popupDialog.show();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
function handleLogout() {
|
||||
for(key in window.authorizations.authz){
|
||||
window.authorizations.remove(key)
|
||||
}
|
||||
window.enabledScopes = null;
|
||||
$('.api-ic.ic-on').addClass('ic-off');
|
||||
$('.api-ic.ic-on').removeClass('ic-on');
|
||||
|
||||
// set the info box
|
||||
$('.api-ic.ic-warning').addClass('ic-error');
|
||||
$('.api-ic.ic-warning').removeClass('ic-warning');
|
||||
}
|
||||
|
||||
function initOAuth(opts) {
|
||||
var o = (opts||{});
|
||||
var errors = [];
|
||||
|
||||
appName = (o.appName||errors.push("missing appName"));
|
||||
popupMask = (o.popupMask||$('#api-common-mask'));
|
||||
popupDialog = (o.popupDialog||$('.api-popup-dialog'));
|
||||
clientId = (o.clientId||errors.push("missing client id"));
|
||||
realm = (o.realm||errors.push("missing realm"));
|
||||
|
||||
if(errors.length > 0){
|
||||
log("auth unable initialize oauth: " + errors);
|
||||
return;
|
||||
}
|
||||
|
||||
$('pre code').each(function(i, e) {hljs.highlightBlock(e)});
|
||||
$('.api-ic').click(function(s) {
|
||||
if($(s.target).hasClass('ic-off'))
|
||||
handleLogin();
|
||||
else {
|
||||
handleLogout();
|
||||
}
|
||||
false;
|
||||
});
|
||||
}
|
||||
|
||||
function onOAuthComplete(token) {
|
||||
if(token) {
|
||||
if(token.error) {
|
||||
var checkbox = $('input[type=checkbox],.secured')
|
||||
checkbox.each(function(pos){
|
||||
checkbox[pos].checked = false;
|
||||
});
|
||||
alert(token.error);
|
||||
}
|
||||
else {
|
||||
var b = token[window.swaggerUi.tokenName];
|
||||
if(b){
|
||||
// if all roles are satisfied
|
||||
var o = null;
|
||||
$.each($('.auth #api_information_panel'), function(k, v) {
|
||||
var children = v;
|
||||
if(children && children.childNodes) {
|
||||
var requiredScopes = [];
|
||||
$.each((children.childNodes), function (k1, v1){
|
||||
var inner = v1.innerHTML;
|
||||
if(inner)
|
||||
requiredScopes.push(inner);
|
||||
});
|
||||
var diff = [];
|
||||
for(var i=0; i < requiredScopes.length; i++) {
|
||||
var s = requiredScopes[i];
|
||||
if(window.enabledScopes && window.enabledScopes.indexOf(s) == -1) {
|
||||
diff.push(s);
|
||||
}
|
||||
}
|
||||
if(diff.length > 0){
|
||||
o = v.parentNode;
|
||||
$(o.parentNode).find('.api-ic.ic-on').addClass('ic-off');
|
||||
$(o.parentNode).find('.api-ic.ic-on').removeClass('ic-on');
|
||||
|
||||
// sorry, not all scopes are satisfied
|
||||
$(o).find('.api-ic').addClass('ic-warning');
|
||||
$(o).find('.api-ic').removeClass('ic-error');
|
||||
}
|
||||
else {
|
||||
o = v.parentNode;
|
||||
$(o.parentNode).find('.api-ic.ic-off').addClass('ic-on');
|
||||
$(o.parentNode).find('.api-ic.ic-off').removeClass('ic-off');
|
||||
|
||||
// all scopes are satisfied
|
||||
$(o).find('.api-ic').addClass('ic-info');
|
||||
$(o).find('.api-ic').removeClass('ic-warning');
|
||||
$(o).find('.api-ic').removeClass('ic-error');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
window.authorizations.add("key", new ApiKeyAuthorization("Authorization", "Bearer " + b, "header"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
32
htdocs/includes/restler/framework/Luracast/Restler/explorer/lib/underscore-min.js
vendored
Normal file
32
htdocs/includes/restler/framework/Luracast/Restler/explorer/lib/underscore-min.js
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
// Underscore.js 1.3.3
|
||||
// (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
|
||||
// Underscore is freely distributable under the MIT license.
|
||||
// Portions of Underscore are inspired or borrowed from Prototype,
|
||||
// Oliver Steele's Functional, and John Resig's Micro-Templating.
|
||||
// For all details and documentation:
|
||||
// http://documentcloud.github.com/underscore
|
||||
(function(){function r(a,c,d){if(a===c)return 0!==a||1/a==1/c;if(null==a||null==c)return a===c;a._chain&&(a=a._wrapped);c._chain&&(c=c._wrapped);if(a.isEqual&&b.isFunction(a.isEqual))return a.isEqual(c);if(c.isEqual&&b.isFunction(c.isEqual))return c.isEqual(a);var e=l.call(a);if(e!=l.call(c))return!1;switch(e){case "[object String]":return a==""+c;case "[object Number]":return a!=+a?c!=+c:0==a?1/a==1/c:a==+c;case "[object Date]":case "[object Boolean]":return+a==+c;case "[object RegExp]":return a.source==
|
||||
c.source&&a.global==c.global&&a.multiline==c.multiline&&a.ignoreCase==c.ignoreCase}if("object"!=typeof a||"object"!=typeof c)return!1;for(var f=d.length;f--;)if(d[f]==a)return!0;d.push(a);var f=0,g=!0;if("[object Array]"==e){if(f=a.length,g=f==c.length)for(;f--&&(g=f in a==f in c&&r(a[f],c[f],d)););}else{if("constructor"in a!="constructor"in c||a.constructor!=c.constructor)return!1;for(var h in a)if(b.has(a,h)&&(f++,!(g=b.has(c,h)&&r(a[h],c[h],d))))break;if(g){for(h in c)if(b.has(c,h)&&!f--)break;
|
||||
g=!f}}d.pop();return g}var s=this,I=s._,o={},k=Array.prototype,p=Object.prototype,i=k.slice,J=k.unshift,l=p.toString,K=p.hasOwnProperty,y=k.forEach,z=k.map,A=k.reduce,B=k.reduceRight,C=k.filter,D=k.every,E=k.some,q=k.indexOf,F=k.lastIndexOf,p=Array.isArray,L=Object.keys,t=Function.prototype.bind,b=function(a){return new m(a)};"undefined"!==typeof exports?("undefined"!==typeof module&&module.exports&&(exports=module.exports=b),exports._=b):s._=b;b.VERSION="1.3.3";var j=b.each=b.forEach=function(a,
|
||||
c,d){if(a!=null)if(y&&a.forEach===y)a.forEach(c,d);else if(a.length===+a.length)for(var e=0,f=a.length;e<f;e++){if(e in a&&c.call(d,a[e],e,a)===o)break}else for(e in a)if(b.has(a,e)&&c.call(d,a[e],e,a)===o)break};b.map=b.collect=function(a,c,b){var e=[];if(a==null)return e;if(z&&a.map===z)return a.map(c,b);j(a,function(a,g,h){e[e.length]=c.call(b,a,g,h)});if(a.length===+a.length)e.length=a.length;return e};b.reduce=b.foldl=b.inject=function(a,c,d,e){var f=arguments.length>2;a==null&&(a=[]);if(A&&
|
||||
a.reduce===A){e&&(c=b.bind(c,e));return f?a.reduce(c,d):a.reduce(c)}j(a,function(a,b,i){if(f)d=c.call(e,d,a,b,i);else{d=a;f=true}});if(!f)throw new TypeError("Reduce of empty array with no initial value");return d};b.reduceRight=b.foldr=function(a,c,d,e){var f=arguments.length>2;a==null&&(a=[]);if(B&&a.reduceRight===B){e&&(c=b.bind(c,e));return f?a.reduceRight(c,d):a.reduceRight(c)}var g=b.toArray(a).reverse();e&&!f&&(c=b.bind(c,e));return f?b.reduce(g,c,d,e):b.reduce(g,c)};b.find=b.detect=function(a,
|
||||
c,b){var e;G(a,function(a,g,h){if(c.call(b,a,g,h)){e=a;return true}});return e};b.filter=b.select=function(a,c,b){var e=[];if(a==null)return e;if(C&&a.filter===C)return a.filter(c,b);j(a,function(a,g,h){c.call(b,a,g,h)&&(e[e.length]=a)});return e};b.reject=function(a,c,b){var e=[];if(a==null)return e;j(a,function(a,g,h){c.call(b,a,g,h)||(e[e.length]=a)});return e};b.every=b.all=function(a,c,b){var e=true;if(a==null)return e;if(D&&a.every===D)return a.every(c,b);j(a,function(a,g,h){if(!(e=e&&c.call(b,
|
||||
a,g,h)))return o});return!!e};var G=b.some=b.any=function(a,c,d){c||(c=b.identity);var e=false;if(a==null)return e;if(E&&a.some===E)return a.some(c,d);j(a,function(a,b,h){if(e||(e=c.call(d,a,b,h)))return o});return!!e};b.include=b.contains=function(a,c){var b=false;if(a==null)return b;if(q&&a.indexOf===q)return a.indexOf(c)!=-1;return b=G(a,function(a){return a===c})};b.invoke=function(a,c){var d=i.call(arguments,2);return b.map(a,function(a){return(b.isFunction(c)?c||a:a[c]).apply(a,d)})};b.pluck=
|
||||
function(a,c){return b.map(a,function(a){return a[c]})};b.max=function(a,c,d){if(!c&&b.isArray(a)&&a[0]===+a[0])return Math.max.apply(Math,a);if(!c&&b.isEmpty(a))return-Infinity;var e={computed:-Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b>=e.computed&&(e={value:a,computed:b})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a)&&a[0]===+a[0])return Math.min.apply(Math,a);if(!c&&b.isEmpty(a))return Infinity;var e={computed:Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b<e.computed&&
|
||||
(e={value:a,computed:b})});return e.value};b.shuffle=function(a){var b=[],d;j(a,function(a,f){d=Math.floor(Math.random()*(f+1));b[f]=b[d];b[d]=a});return b};b.sortBy=function(a,c,d){var e=b.isFunction(c)?c:function(a){return a[c]};return b.pluck(b.map(a,function(a,b,c){return{value:a,criteria:e.call(d,a,b,c)}}).sort(function(a,b){var c=a.criteria,d=b.criteria;return c===void 0?1:d===void 0?-1:c<d?-1:c>d?1:0}),"value")};b.groupBy=function(a,c){var d={},e=b.isFunction(c)?c:function(a){return a[c]};
|
||||
j(a,function(a,b){var c=e(a,b);(d[c]||(d[c]=[])).push(a)});return d};b.sortedIndex=function(a,c,d){d||(d=b.identity);for(var e=0,f=a.length;e<f;){var g=e+f>>1;d(a[g])<d(c)?e=g+1:f=g}return e};b.toArray=function(a){return!a?[]:b.isArray(a)||b.isArguments(a)?i.call(a):a.toArray&&b.isFunction(a.toArray)?a.toArray():b.values(a)};b.size=function(a){return b.isArray(a)?a.length:b.keys(a).length};b.first=b.head=b.take=function(a,b,d){return b!=null&&!d?i.call(a,0,b):a[0]};b.initial=function(a,b,d){return i.call(a,
|
||||
0,a.length-(b==null||d?1:b))};b.last=function(a,b,d){return b!=null&&!d?i.call(a,Math.max(a.length-b,0)):a[a.length-1]};b.rest=b.tail=function(a,b,d){return i.call(a,b==null||d?1:b)};b.compact=function(a){return b.filter(a,function(a){return!!a})};b.flatten=function(a,c){return b.reduce(a,function(a,e){if(b.isArray(e))return a.concat(c?e:b.flatten(e));a[a.length]=e;return a},[])};b.without=function(a){return b.difference(a,i.call(arguments,1))};b.uniq=b.unique=function(a,c,d){var d=d?b.map(a,d):a,
|
||||
e=[];a.length<3&&(c=true);b.reduce(d,function(d,g,h){if(c?b.last(d)!==g||!d.length:!b.include(d,g)){d.push(g);e.push(a[h])}return d},[]);return e};b.union=function(){return b.uniq(b.flatten(arguments,true))};b.intersection=b.intersect=function(a){var c=i.call(arguments,1);return b.filter(b.uniq(a),function(a){return b.every(c,function(c){return b.indexOf(c,a)>=0})})};b.difference=function(a){var c=b.flatten(i.call(arguments,1),true);return b.filter(a,function(a){return!b.include(c,a)})};b.zip=function(){for(var a=
|
||||
i.call(arguments),c=b.max(b.pluck(a,"length")),d=Array(c),e=0;e<c;e++)d[e]=b.pluck(a,""+e);return d};b.indexOf=function(a,c,d){if(a==null)return-1;var e;if(d){d=b.sortedIndex(a,c);return a[d]===c?d:-1}if(q&&a.indexOf===q)return a.indexOf(c);d=0;for(e=a.length;d<e;d++)if(d in a&&a[d]===c)return d;return-1};b.lastIndexOf=function(a,b){if(a==null)return-1;if(F&&a.lastIndexOf===F)return a.lastIndexOf(b);for(var d=a.length;d--;)if(d in a&&a[d]===b)return d;return-1};b.range=function(a,b,d){if(arguments.length<=
|
||||
1){b=a||0;a=0}for(var d=arguments[2]||1,e=Math.max(Math.ceil((b-a)/d),0),f=0,g=Array(e);f<e;){g[f++]=a;a=a+d}return g};var H=function(){};b.bind=function(a,c){var d,e;if(a.bind===t&&t)return t.apply(a,i.call(arguments,1));if(!b.isFunction(a))throw new TypeError;e=i.call(arguments,2);return d=function(){if(!(this instanceof d))return a.apply(c,e.concat(i.call(arguments)));H.prototype=a.prototype;var b=new H,g=a.apply(b,e.concat(i.call(arguments)));return Object(g)===g?g:b}};b.bindAll=function(a){var c=
|
||||
i.call(arguments,1);c.length==0&&(c=b.functions(a));j(c,function(c){a[c]=b.bind(a[c],a)});return a};b.memoize=function(a,c){var d={};c||(c=b.identity);return function(){var e=c.apply(this,arguments);return b.has(d,e)?d[e]:d[e]=a.apply(this,arguments)}};b.delay=function(a,b){var d=i.call(arguments,2);return setTimeout(function(){return a.apply(null,d)},b)};b.defer=function(a){return b.delay.apply(b,[a,1].concat(i.call(arguments,1)))};b.throttle=function(a,c){var d,e,f,g,h,i,j=b.debounce(function(){h=
|
||||
g=false},c);return function(){d=this;e=arguments;f||(f=setTimeout(function(){f=null;h&&a.apply(d,e);j()},c));g?h=true:i=a.apply(d,e);j();g=true;return i}};b.debounce=function(a,b,d){var e;return function(){var f=this,g=arguments;d&&!e&&a.apply(f,g);clearTimeout(e);e=setTimeout(function(){e=null;d||a.apply(f,g)},b)}};b.once=function(a){var b=false,d;return function(){if(b)return d;b=true;return d=a.apply(this,arguments)}};b.wrap=function(a,b){return function(){var d=[a].concat(i.call(arguments,0));
|
||||
return b.apply(this,d)}};b.compose=function(){var a=arguments;return function(){for(var b=arguments,d=a.length-1;d>=0;d--)b=[a[d].apply(this,b)];return b[0]}};b.after=function(a,b){return a<=0?b():function(){if(--a<1)return b.apply(this,arguments)}};b.keys=L||function(a){if(a!==Object(a))throw new TypeError("Invalid object");var c=[],d;for(d in a)b.has(a,d)&&(c[c.length]=d);return c};b.values=function(a){return b.map(a,b.identity)};b.functions=b.methods=function(a){var c=[],d;for(d in a)b.isFunction(a[d])&&
|
||||
c.push(d);return c.sort()};b.extend=function(a){j(i.call(arguments,1),function(b){for(var d in b)a[d]=b[d]});return a};b.pick=function(a){var c={};j(b.flatten(i.call(arguments,1)),function(b){b in a&&(c[b]=a[b])});return c};b.defaults=function(a){j(i.call(arguments,1),function(b){for(var d in b)a[d]==null&&(a[d]=b[d])});return a};b.clone=function(a){return!b.isObject(a)?a:b.isArray(a)?a.slice():b.extend({},a)};b.tap=function(a,b){b(a);return a};b.isEqual=function(a,b){return r(a,b,[])};b.isEmpty=
|
||||
function(a){if(a==null)return true;if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(b.has(a,c))return false;return true};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=p||function(a){return l.call(a)=="[object Array]"};b.isObject=function(a){return a===Object(a)};b.isArguments=function(a){return l.call(a)=="[object Arguments]"};b.isArguments(arguments)||(b.isArguments=function(a){return!(!a||!b.has(a,"callee"))});b.isFunction=function(a){return l.call(a)=="[object Function]"};
|
||||
b.isString=function(a){return l.call(a)=="[object String]"};b.isNumber=function(a){return l.call(a)=="[object Number]"};b.isFinite=function(a){return b.isNumber(a)&&isFinite(a)};b.isNaN=function(a){return a!==a};b.isBoolean=function(a){return a===true||a===false||l.call(a)=="[object Boolean]"};b.isDate=function(a){return l.call(a)=="[object Date]"};b.isRegExp=function(a){return l.call(a)=="[object RegExp]"};b.isNull=function(a){return a===null};b.isUndefined=function(a){return a===void 0};b.has=function(a,
|
||||
b){return K.call(a,b)};b.noConflict=function(){s._=I;return this};b.identity=function(a){return a};b.times=function(a,b,d){for(var e=0;e<a;e++)b.call(d,e)};b.escape=function(a){return(""+a).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'").replace(/\//g,"/")};b.result=function(a,c){if(a==null)return null;var d=a[c];return b.isFunction(d)?d.call(a):d};b.mixin=function(a){j(b.functions(a),function(c){M(c,b[c]=a[c])})};var N=0;b.uniqueId=
|
||||
function(a){var b=N++;return a?a+b:b};b.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var u=/.^/,n={"\\":"\\","'":"'",r:"\r",n:"\n",t:"\t",u2028:"\u2028",u2029:"\u2029"},v;for(v in n)n[n[v]]=v;var O=/\\|'|\r|\n|\t|\u2028|\u2029/g,P=/\\(\\|'|r|n|t|u2028|u2029)/g,w=function(a){return a.replace(P,function(a,b){return n[b]})};b.template=function(a,c,d){d=b.defaults(d||{},b.templateSettings);a="__p+='"+a.replace(O,function(a){return"\\"+n[a]}).replace(d.escape||
|
||||
u,function(a,b){return"'+\n_.escape("+w(b)+")+\n'"}).replace(d.interpolate||u,function(a,b){return"'+\n("+w(b)+")+\n'"}).replace(d.evaluate||u,function(a,b){return"';\n"+w(b)+"\n;__p+='"})+"';\n";d.variable||(a="with(obj||{}){\n"+a+"}\n");var a="var __p='';var print=function(){__p+=Array.prototype.join.call(arguments, '')};\n"+a+"return __p;\n",e=new Function(d.variable||"obj","_",a);if(c)return e(c,b);c=function(a){return e.call(this,a,b)};c.source="function("+(d.variable||"obj")+"){\n"+a+"}";return c};
|
||||
b.chain=function(a){return b(a).chain()};var m=function(a){this._wrapped=a};b.prototype=m.prototype;var x=function(a,c){return c?b(a).chain():a},M=function(a,c){m.prototype[a]=function(){var a=i.call(arguments);J.call(a,this._wrapped);return x(c.apply(b,a),this._chain)}};b.mixin(b);j("pop,push,reverse,shift,sort,splice,unshift".split(","),function(a){var b=k[a];m.prototype[a]=function(){var d=this._wrapped;b.apply(d,arguments);var e=d.length;(a=="shift"||a=="splice")&&e===0&&delete d[0];return x(d,
|
||||
this._chain)}});j(["concat","join","slice"],function(a){var b=k[a];m.prototype[a]=function(){return x(b.apply(this._wrapped,arguments),this._chain)}});m.prototype.chain=function(){this._chain=true;return this};m.prototype.value=function(){return this._wrapped}}).call(this);
|
||||
@ -0,0 +1,15 @@
|
||||
<script>
|
||||
var qp = null;
|
||||
if(window.location.hash) {
|
||||
qp = location.hash.substring(1);
|
||||
}
|
||||
else {
|
||||
qp = location.search.substring(1);
|
||||
}
|
||||
qp = qp ? JSON.parse('{"' + qp.replace(/&/g, '","').replace(/=/g,'":"') + '"}',
|
||||
function(key, value) {
|
||||
return key===""?value:decodeURIComponent(value) }
|
||||
):{}
|
||||
window.opener.onOAuthComplete(qp);
|
||||
window.close();
|
||||
</script>
|
||||
File diff suppressed because it is too large
Load Diff
1
htdocs/includes/restler/framework/Luracast/Restler/explorer/swagger-ui.min.js
vendored
Normal file
1
htdocs/includes/restler/framework/Luracast/Restler/explorer/swagger-ui.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -11,7 +11,7 @@ namespace Luracast\Restler;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
interface iAuthenticate extends iFilter
|
||||
{
|
||||
|
||||
@ -9,7 +9,7 @@ namespace Luracast\Restler;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
interface iCache
|
||||
{
|
||||
|
||||
@ -13,7 +13,7 @@ use Exception;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
interface iCompose {
|
||||
/**
|
||||
|
||||
@ -12,7 +12,7 @@ namespace Luracast\Restler;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
interface iFilter
|
||||
{
|
||||
|
||||
@ -12,7 +12,7 @@ namespace Luracast\Restler;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
interface iIdentifyUser
|
||||
{
|
||||
|
||||
@ -1,8 +1,14 @@
|
||||
<?php
|
||||
namespace Luracast\Restler;
|
||||
|
||||
|
||||
interface iProvideMultiVersionApi {
|
||||
/**
|
||||
* Interface iProvideMultiVersionApi
|
||||
* @package Luracast\Restler
|
||||
*
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
interface iProvideMultiVersionApi
|
||||
{
|
||||
/**
|
||||
* Maximum api version supported by the api class
|
||||
* @return int
|
||||
|
||||
@ -11,7 +11,7 @@ namespace Luracast\Restler;
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
* @version 3.0.0rc6
|
||||
*/
|
||||
interface iUseAuthentication
|
||||
{
|
||||
|
||||
@ -64,7 +64,7 @@ if ($success && isset($api)) {
|
||||
} else {
|
||||
if (isset($response['error']['message'])) {
|
||||
$icon = '<icon class="denied"></icon>';
|
||||
$title = end(explode(':',$response['error']['message']));
|
||||
$title = end(explode(':',$response['error']['message'],2));
|
||||
} else {
|
||||
$icon = '<icon class="warning"></icon>';
|
||||
$title = 'No Matching Resource';
|
||||
|
||||
Loading…
Reference in New Issue
Block a user