Skip to content

Commit

Permalink
added http statuses; added ability to add methods to classes with exp…
Browse files Browse the repository at this point in the history
…licit class name, extends and implements
  • Loading branch information
Boris Gurvich committed May 7, 2012
1 parent f06967c commit e7d7da3
Show file tree
Hide file tree
Showing 2 changed files with 141 additions and 43 deletions.
85 changes: 69 additions & 16 deletions com/controller.php
Expand Up @@ -87,6 +87,20 @@ public static function https()
return !empty($_SERVER['HTTPS']);
}

/**
* Server protocol (HTTP/1.0 or HTTP/1.1)
*
* @return string
*/
public static function serverProtocol()
{
$protocol = "HTTP/1.0";
if(isset($_SERVER['SERVER_PROTOCOL']) && stripos($_SERVER['SERVER_PROTOCOL'],"HTTP") >= 0){
$protocol = $_SERVER['SERVER_PROTOCOL'];
}
return $protocol;
}

public static function scheme()
{
return static::https() ? 'https' : 'http';
Expand Down Expand Up @@ -586,6 +600,47 @@ public static function modRewriteEnabled()
*/
class BResponse extends BClass
{
protected static $_httpStatuses = array(
100 => 'Continue',
101 => 'Switching Protocols',
200 => 'OK',
201 => 'Created',
202 => 'Accepted',
203 => 'Non-Authorative Information',
204 => 'No Content',
205 => 'Reset Content',
206 => 'Partial Content',
300 => 'Multiple Choices',
301 => 'Moved Permanently',
302 => 'Found',
303 => 'See Other',
304 => 'Not Modified',
307 => 'Temporary Redirect',
400 => 'Bad Request',
401 => 'Unauthorized',
402 => 'Payment Required',
403 => 'Forbidden',
404 => 'Not Found',
405 => 'Method Not Allowed',
406 => 'Not Acceptable',
407 => 'Proxy Authentication Required',
408 => 'Request Time-out',
409 => 'Conflict',
410 => 'Gone',
411 => 'Length Required',
412 => 'Precondition Failed',
413 => 'Request Entity Too Large',
414 => 'Request-URI Too Large',
415 => 'Unsupported Media Type',
416 => 'Requested Range Not Satisfiable',
417 => 'Expectation Failed',
500 => 'Internal Server Error',
501 => 'Not Implemented',
502 => 'Bad Gateway',
503 => 'Service Unavailable',
504 => 'Gateway Time-out',
505 => 'HTTP Version Not Supported',
);
/**
* Response content MIME type
*
Expand Down Expand Up @@ -676,7 +731,7 @@ public function add($content)
* Set or retrieve response content MIME type
*
* @deprecated
* @param string $type 'json' will expand to 'application/json'
* @param string $type
* @return BResponse|string
*/
public function contentType($type=BNULL)
Expand Down Expand Up @@ -835,17 +890,14 @@ public function sendContent($content, $fileName='download.txt', $disposition='at
public function status($status, $message=null, $output=true)
{
if (is_null($message)) {
switch ((int)$status) {
case 301: $message = 'Moved Permanently'; break;
case 302: $message = 'Moved Temporarily'; break;
case 303: $message = 'See Other'; break;
case 401: $message = 'Unauthorized'; break;
case 404: $message = 'Not Found'; break;
case 503: $message = 'Service Unavailable'; break;
default: $message = 'Unknown';
if (!empty(static::$_httpStatuses[$status])) {
$message = static::$_httpStatuses[$status];
} else {
$message = 'Unknown';
}
}
header("HTTP/1.0 {$status} {$message}");
$protocol = BRequest::i()->serverProtocol();
header("{$protocol} {$status} {$message}");
header("Status: {$status} {$message}");
if (is_string($output)) {
echo $output;
Expand Down Expand Up @@ -1006,7 +1058,7 @@ public function __construct()
*/
public function changeRoute($from, $opt)
{
if (is_array($opt)) {
if (!is_array($opt)) {
$opt = array('to'=>$opt);
}
$type = !empty($opt['type']) ? $opt['type'] : 'first';
Expand Down Expand Up @@ -1189,8 +1241,8 @@ public function dispatch($requestRoute=null)
}

if ($attempts>=100) {
echo "<pre>"; print_r($node); echo "</pre>";
BDebug::error(BLocale::_('BFrontController: Reached 100 route iterations: %s', print_r($node,1)));
echo "<pre>"; print_r($route); echo "</pre>";
BDebug::error(BLocale::_('BFrontController: Reached 100 route iterations: %s', print_r($route,1)));
}
}

Expand Down Expand Up @@ -1448,8 +1500,8 @@ public function dispatch()
$controllerName = $this->callback[0];
$node->controller_name = $controllerName;
$actionName = $this->callback[1];
/** @var BActionController */
$controller = BClassRegistry::i()->instance($controllerName, array(), true);
#echo "<pre>"; print_r($this); exit;
return $controller->dispatch($actionName, $this->args);
}

Expand Down Expand Up @@ -1524,6 +1576,7 @@ public function dispatch($actionName, $args=array())
$this->forward('unauthenticated');
return $this->_forward;
}

if ($authenticated && !$this->authorize($args) && $actionName!=='unauthorized') {
$this->forward('unauthorized');
return $this->_forward;
Expand Down Expand Up @@ -1557,11 +1610,11 @@ public function tryDispatch($actionName, $args)
$actionMethod = $this->_actionMethodPrefix.$actionName;
if (($reqMethod = BRequest::i()->method())!=='GET') {
$tmpMethod = $actionMethod.'__'.$reqMethod;
if (is_callable(array($this, $tmpMethod))) {
if (method_exists($this, $tmpMethod)) {
$actionMethod = $tmpMethod;
}
}
if (!is_callable(array($this, $actionMethod))) {
if (!method_exists($this, $actionMethod)) {
$this->forward(true);
return $this;
}
Expand Down
99 changes: 72 additions & 27 deletions com/core.php
Expand Up @@ -543,6 +543,13 @@ class BClassRegistry extends BClass
*/
protected $_methods = array();

/**
* Cache for method callbacks
*
* @var array
*/
protected $_methodOverrideCache = array();

/**
* Classes that require decoration because of overridden methods
*
Expand Down Expand Up @@ -613,14 +620,24 @@ public function overrideClass($class, $newClass, $replaceSingleton=false)
/**
* Dynamically add a class method
*
* @param string $class if '*' will add method to all classes
* @param string $class
* - '*' - will add method to all classes
* - 'extends AbstractClass' - will add method to all classes extending AbstractClass
* - 'implements Interface' - will add method to all classes implementing Interface
* @param string $name
* @param callback $callback
* @return BClassRegistry
*/
public function addMethod($class, $name, $callback, $static=false)
public function addMethod($class, $method, $callback, $static=false)
{
$this->_methods[$class][$static ? 1 : 0][$method]['override'] = array(
$arr = explode(' ', $class);
if (!empty($arr[1])) {
$rel = $arr[0];
$class = $arr[1];
} else {
$rel = 'is';
}
$this->_methods[$method][$static ? 1 : 0]['override'][$rel][$class] = array(
'module_name' => BModuleRegistry::currentModuleName(),
'callback' => $callback,
);
Expand Down Expand Up @@ -655,8 +672,6 @@ public function addMethod($class, $name, $callback, $static=false)
*
* Remembering the module that overrode the method for debugging
*
* @todo decide whether static overrides are needed
*
* @param string $class Class to be overridden
* @param string $method Method to be overridden
* @param mixed $callback Callback to invoke on method call
Expand All @@ -665,10 +680,7 @@ public function addMethod($class, $name, $callback, $static=false)
*/
public function overrideMethod($class, $method, $callback, $static=false)
{
$this->_methods[$class][$static ? 1 : 0][$method]['override'] = array(
'module_name' => BModuleRegistry::currentModuleName(),
'callback' => $callback,
);
$this->addMethod($class, $method, $callback, $static);
$this->_decoratedClasses[$class] = true;
return $this;
}
Expand Down Expand Up @@ -705,7 +717,7 @@ public function overrideMethod($class, $method, $callback, $static=false)
*/
public function augmentMethod($class, $method, $callback, $static=false)
{
$this->_methods[$class][$static ? 1 : 0][$method]['augment'][] = array(
$this->_methods[$method][$static ? 1 : 0]['augment']['is'][$class][] = array(
'module_name' => BModuleRegistry::currentModuleName(),
'callback' => $callback,
);
Expand Down Expand Up @@ -758,6 +770,42 @@ public function augmentProperty($class, $property, $op, $type, $callback)
return $this;
}

public function findMethodInfo($class, $method, $static=0, $type='override')
{
//$this->_methods[$method][$static ? 1 : 0]['override'][$rel][$class]
if (!empty($this->_methods[$method][$static][$type]['is'][$class])) {
return $class;
}
$cacheKey = $class.'|'.$method.'|'.$static.'|'.$type;
if (!empty($this->_methodOverrideCache[$cacheKey])) {
return $this->_methodOverrideCache[$cacheKey];
}
if (!empty($this->_methods[$method][$static][$type]['extends'])) {
$parents = array_flip(class_parents($class));
foreach ($this->_methods[$method][$static][$type]['extends'] as $c=>$v) {
if (isset($parents[$c])) {
$this->_methodOverrideCache[$cacheKey] = $v;
return $v;
}
}
}
if (!empty($this->_methods[$method][$static][$type]['implements'])) {
$implements = array_flip(class_implements($class));
foreach ($this->_methods[$method][$static][$type]['implements'] as $i) {
if (isset($implements[$p])) {
$this->_methodOverrideCache[$cacheKey] = $v;
return $v;
}
}
}
if (!empty($this->_methods[$method][$static][$type]['is']['*'])) {
$v = $this->_methods[$method][$static][$type]['is']['*'];
$this->_methodOverrideCache[$cacheKey] = $v;
return $v;
}
return null;
}

/**
* Call overridden method
*
Expand All @@ -770,27 +818,26 @@ public function callMethod($origObject, $method, array $args=array(), $origClass
{
$class = $origClass ? $origClass : get_class($origObject);

if (!empty($this->_methods[$class][0][$method]['override'])) {
$overridden = true;
$callback = $this->_methods[$class][0][$method]['override']['callback'];
if (($info = $this->findMethodInfo($class, $method, 0, 'override'))) {
$callback = $info['callback'];
array_unshift($args, $origObject);
} elseif (!empty($this->_methods['*'][0][$method]['override'])) {
$overridden = true;
$callback = $this->_methods['*'][0][$method]['override']['callback'];
array_unshift($args, $origObject);
} else {
$overridden = false;
} elseif (method_exists($origObject, $method)) {
$callback = array($origObject, $method);
$overridden = false;
} else {
BDebug::error('Invalid method: '.get_class($origObject).'::'.$method);
return null;
}

$result = call_user_func_array($callback, $args);

if (!empty($this->_methods[$class][0][$method]['augment'])) {
if (($info = $this->findMethodInfo($class, $method, 0, 'augment'))) {
if (!$overridden) {
array_unshift($args, $origObject);
}
array_unshift($args, $result);
foreach ($this->_methods[$class][0][$method]['augment'] as $augment) {
foreach ($info as $augment) {
$result = call_user_func_array($augment['callback'], $args);
$args[0] = $result;
}
Expand All @@ -814,19 +861,17 @@ public function callStaticMethod($class, $method, array $args=array(), $origClas
{
$class = $origClass ? $origClass : $class;

if (!empty($this->_methods[$class][1][$method]['override'])) {
$callback = $this->_methods[$class][1][$method]['override']['callback'];
} elseif (!empty($this->_methods['*'][1][$method]['override'])) {
$callback = $this->_methods['*'][1][$method]['override']['callback'];
if (($info = $this->findMethodInfo($class, $method, 1, 'override'))) {
$callback = $info['callback'];
} else {
$callback = array($class, $method);
}

$result = call_user_func_array($callback, $args);

if (!empty($this->_methods[$class][1][$method]['augment'])) {
if (($info = $this->findMethodInfo($class, $method, 1, 'augment'))) {
array_unshift($args, $result);
foreach ($this->_methods[$class][1][$method]['augment'] as $augment) {
foreach ($info as $augment) {
$result = call_user_func_array($augment['callback'], $args);
$args[0] = $result;
}
Expand Down Expand Up @@ -1261,7 +1306,7 @@ public function fire($eventName, $args=array())

// For cases like BView
if (is_object($cb) && !$cb instanceof Closure) {
if (is_callable(array($cb, 'set'))) {
if (method_exists($cb, 'set')) {
$cb->set($args);
}
$result[] = (string)$cb;
Expand Down

0 comments on commit e7d7da3

Please sign in to comment.