<?php
/**
* AjaxActionsResponse V3.0
* @author Joel Cox
* @date 16-04-2011
*/
class AjaxResponse extends AjaxActionList {
// Set-up / Initialization
public static $autoOutputOnShutdown = true;
private static $_isShutdownFunctionSet = false;
private static $_autoOutputInstance = null;
private static
$_instances = array();
private static $_errorHandlerInstance = null;
protected $_namespace = null;
protected $_previousErrorHandler = null;
protected $_previousExceptionHandler = null;
protected $_previousErrorReporting = null;
protected static $_iframeSubmit = false;
/**
* Initialize an instance of AjaxActionsResponse object.
* @param string $namespace Response Namespace. all calls to init() function with the same namespace specified will return the same object.
* @param boolean $setErrorHandler whether or not to set the ajax actions error handler. defaults to true only with the default namespace, and no other instance has already set an error handler.
* @return AjaxActionList
*/
public static function init($namespace = null, $setErrorHandler = null) {
$iframeSubmitIndicator = 'ajax-actions-iframe-submit-indicator';
if (isset($_REQUEST[$iframeSubmitIndicator])) {
self::$_iframeSubmit = true;
unset($_REQUEST[$iframeSubmitIndicator]);
if (isset($_GET[$iframeSubmitIndicator])) unset($_GET[$iframeSubmitIndicator]);
if (isset($_POST[$iframeSubmitIndicator])) unset($_POST[$iframeSubmitIndicator]);
}
$setErrorHandler = is_null($setErrorHandler) && is_null($namespace) ?
true : false;
$namespace = is_null($namespace) ?
'global' : $namespace;
if (!isset(self::$_instances[$namespace])) {
self::$_instances[$namespace] = new self();
}
if ($setErrorHandler && self::$_errorHandlerInstance == null) {
self::$_instances[$namespace]->setPhpErrorHandler();
}
return self::$_instances[$namespace];
}
public static function isIframeSubmit() {
return self::$_iframeSubmit;
}
public static function isAjaxActionsRequest() {
if (self::$_iframeSubmit) return true;
if(!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
return true;
}
return false;
}
/**
* Sets PHP error and exception handlers - so errors will be output as valid
* ajax actions responses in order to give useful feedback to the user
*/
public function setPhpErrorHandler() {
self::$_errorHandlerInstance = $this;
$this->_previousExceptionHandler
= set_exception_handler
(array($this, '__phpExceptionHandler'));
$this->_previousErrorReporting
= ini_get('error_reporting');
}
/**
* Restore previous PHP error and exception handlers.
*/
public function unsetPhpErrorHandler() {
if (!is_null($this->_previousExceptionHandler
)) set_exception_handler
($this->_previousExceptionHandler
);
$this->_previousErrorHandler = null;
$this->_previousExceptionHandler = null;
ini_set('error_reporting', $this->_previousErrorReporting
);
}
public function __phpErrorHandler($errno, $errstr, $errfile, $errline) {
self::$_errorHandlerInstance->alert("Error $errno\n$errstr\n\nOccurred in $errfile on line $errline");
}
public function __phpExceptionHandler(Exception $e) {
self::$_errorHandlerInstance->alert('An error occurred: '.$e->getMessage());
}
public static function __phpShutdownFunction() {
if (!self::isAjaxActionsRequest()) return;
if (self::$autoOutputOnShutdown) {
// NOTE: OB_INITIAL_LEVEL is C5 SPECIFIC - and will
// need updating if moving this class to another framework!
if (!defined('OB_INITIAL_LEVEL')) {
echo 'AjaxActionsError - Please see comments in __phpShutdownFunction for more details.';
return;
}
if ($lastError['type'] === E_ERROR) {
$ajax = self::init();
$ajax->jQuery->ajaxActions->loading_start();
$ajax->jQuery->ajaxActions->error("PHP Fatal Error\n\n".
$lastError['message'].' in '.$lastError['file'].' on line '.$lastError['line']
'width' => '1000px',
'margin-left' => '-500px',
'text-align' => 'left',
'font-size' => '12pt'
));
// On fatal error, clear all output buffers
}
if (!is_null(self::$_autoOutputInstance)) {
$response = self::$_autoOutputInstance;
} else {
$response = self::init();
}
// var_export($response);
$response->output();
}
}
}
public function __construct() {
if (!self::$_isShutdownFunctionSet) {
self::$_isShutdownFunctionSet = true;
}
}
public function getOutput() {
// return print_r($this->toArray(), true);
return json_encode($this->utf8encodestrings(array('ajaxActions' => $this->toArray())));
// return json_encode(array('ajaxActions' => $this->toArray()));
}
private function utf8encodestrings($data) {
foreach ($data as $k => &$v) $v = $this->utf8encodestrings($v);
// $data = iconv(mb_detect_encoding($data, 'auto'), 'UTF-8//TRANSLIT', $data);
// $data = utf8_encode(iconv(mb_detect_encoding($data, 'auto'), 'UTF-8//TRANSLIT', $data));
}
return $data;
}
}
/**
* Ajax Actions Action List
*
* @method alert($text) will show a javascript alert.
*/
class AjaxActionList {
protected $_actions = array();
protected $_isExecuteChain = false;
protected $_parent = null;
protected $_single = false;
protected $_return = null;
/**
*
* @return type
*/
public function getOutput() {
}
protected static $_outputCount = 0;
public function output($reset = true) {
if (AjaxResponse::isIframeSubmit()) {
if (self::$_outputCount++ == 0) {
echo '<script>window.parent.$.ajaxActions.loading_complete();</script>';
}
echo '<script>window.parent.$.ajaxActions.processResponse('.$this->getOutput().');</script>';
header('content-type: application/json; charset=utf-8');
echo $this->getOutput();
}
if ($reset) $this->_actions
= array();
}
public function _addAction($method, $params, $startExecuteChain = false) {
foreach ($params as &$param) {
if ($param instanceof self) if ($param->_isExecuteChain) {
$param = $param->_getParent();
}
}
'method' => $method,
'params' => $params
);
if ($this->_isExecuteChain || $startExecuteChain) {
$chain = new self();
$chain->_isExecuteChain = true;
$chain->_parent = $this;
$action['chain'] = $chain;
}
$this->_actions[] = $action;
return ($this->_isExecuteChain || $startExecuteChain) ? $chain : $this;
}
public function _addGet($name) {
$chain = new self();
$chain->_isExecuteChain = true;
$chain->_parent = $this;
$this->_actions
[] = array(
'__get__' => $name,
'chain' => $chain
);
return $chain;
}
public static function callback($return = null) {
$callback = new self();
if ($return !== null) $callback->_return = $return;
return $callback;
}
protected function _getParent() {
return is_null($this->_parent
) ?
$this : $this->_parent
->_getParent
();
}
// -------------------------------------------------------------------------
public function jQuery() {
//return $this->_addAction('jQuery', func_get_args(), true);
return $this->_addAction('jQuery', $data, true);
}
public function __call($name, $arguments) {
return $this->_addAction($name, $arguments);
}
public function __get($name) {
return $this->_addGet($name);
}
public function __set($name, $value) {
$this->_actions
[] = array(
'__set__' => $name,
'value' => $value
);
return $this;
}
public function toArray() {
foreach ($this->_actions as &$action) {
if (isset($action['chain'])) if ($action['chain'] instanceof
self) {
$action['chain'] = $action['chain']->toArray();
if (count($action['chain']) == 0) {
}
}
if (isset($action['__get__']) || isset($action['__set__'])) {
} else foreach ($action['params'] as &$param) {
foreach ($param as &$p) {
if ($p instanceof self) {
$p = $p->_getParent()->toArray();
$p['isAjaxActionChainObject'] = true;
}
}
} else if ($param instanceof self) {
$param = $param->toArray();
$param['isAjaxActionChainObject'] = true;
}
}
}
if ($this->_return !== null) $this->_actions['__return__'] = $this->_return;
return $this->_actions;
}
public function _ajaxLoadScript($url, $multiple = false, $async = true) {
if ($async) {
$callback = self::callback();
$this->jQuery->ajaxActions->ajaxLoadScript($url, $multiple, $callback);
return $callback;
} else {
$this->jQuery->ajaxActions->ajaxLoadScript($url, $multiple);
return $this;
}
}
public function _ajaxLoadCss($url) {
$this->jQuery->ajaxActions->ajaxLoadCss($url);
return $this;
}
/* @method alert($text) */
}