Hi,

This might already exist or have been done before. But thought some might find it useful.

Just needed a way to debug what's happening in PHP so the PHP call Console::log('message') will show on either Firebug or Chrome's console.

This is nowhere perfected, but works.

Usage:

In you php Direct Class call:
PHP Code:
  Console::log('Some Message Here'); 
The code in green need to be added to your app:
Code:
    // Handle all exceptions in Ext.direct
    Ext.Direct.on('exception',function(e)
		{
        Ext.MessageBox.alert('Message', e.message );            
		}, this
  	);

    // output debug to console
    Ext.Direct.on('event',function(e, provider)
		{
		  if (e.debug && console)
		  {
        for(var i = 0, len = e.debug.length; i < len; i++){
            console.log(e.debug[i].msg);
        }		    
		  }
		}, this
  	);
    
    Ext.onReady(function() {    
        Ext.Direct.addProvider(ImapGate.API);
    });
And changes to Router.php are highlighted in green:
Code:
<?php

class Console
{
  private static $messages = array();
  
  public static function log($msg)
  {
    self::$messages[] = array('type' => 'log', 'msg' => $msg);
  }
  
  public static function getMsgs()
  {
    return self::$messages;
  }  
}

class BogusAction {
    public $action;
    public $method;
    public $data;
    public $tid;
}

class ExtDirect_Router {
        public $data = null;
        public $isForm = false;
        public $isUpload = false;
        
        private $_response = null;
        
        public function __construct($api) {
            $this->setAPI($api);
            $this->parseRequest();
        }
        
        public function setAPI($api) {
            if(!($api instanceof ExtDirect_API)) {
                throw new Exception('setAPI expects an instance of ExtDirect_API');
            }
            
            $this->_api = $api;
        }
        
        public function parseRequest() {
            if(isset($GLOBALS['HTTP_RAW_POST_DATA'])){
                $this->data = json_decode($GLOBALS['HTTP_RAW_POST_DATA']);
            }
            else if(isset($_POST['extAction'])){ // form post
                $this->isForm = true;
                $this->isUpload = $_POST['extUpload'] == 'true';
                
                $data = new BogusAction();
                $data->action = $_POST['extAction'];
                $data->method = $_POST['extMethod'];
                $data->tid = $_POST['extTID'];
                $data->data = array($_POST, $_FILES);
                
                $this->data = $data;
            }
            else {
                die('Invalid request.');
            }
        }
        
        public function dispatch() {
            if(isset($this->_response)) return;
            
            $response = null;
            $output = '';
            if(is_array($this->data)){
                $response = array();
                foreach($this->data as $d){
                        $response[] = $this->rpc($d);
                }
            }else{
                $response = $this->rpc($this->data);
            }
            
            if($this->isForm && $this->isUpload){
                $json = json_encode($response);
                $json = preg_replace("/&quot;/", '\\&quot;', $json);
                
                $output .= '<html><body><textarea>';
                $output .= $json;
                $output .= '</textarea></body></html>';
            }else{
                $output = json_encode($response);
            }
            
            $this->_response = $output;                
            return $output;
        }
        
        public function rpc($cdata) {
//            ob_start(); // mod
            $classes = $this->_api->getClasses();
            try {
                if(!isset($classes[$cdata->action])){
                    throw new Exception('Call to undefined class: ' . $cdata->action);
                }
                
                $class = $cdata->action;
                $method = $cdata->method;
                
                $cconf = $classes[$class];
                $mconf = null;
                
                $classPath = isset($cconf['fullPath']) 
                    ? $cconf['fullPath'] 
                    : $this->_api->getClassPath($class, $cconf);
                    
                require_once($classPath);
                $parsedAPI = $this->_api->getParsedAPI();

                if(!empty($parsedAPI) && isset($parsedAPI['actions'][$class])) {
                    foreach($parsedAPI['actions'][$class] as $m) {
                        if($m['name'] === $method) {                            
                            $mconf = $m;
                            $serverMethod = isset($m['serverMethod']) ? $m['serverMethod'] : $method;
                        }
                    }
                }
                else {
                    // do some very simple reflection on the class to check if the method is allowed
                    $rClass = new ReflectionClass($cconf['prefix'] . $class);
                    if(!$rClass->hasMethod($method)) {
                        $rMethods = $rClass->getMethods();
                        foreach($rMethods as $rMethod) {
                            $doc = $rMethod->getDocComment();
                            if(
                                $rMethod->isPublic() &&
                                strlen($doc) > 0 &&
                                !!preg_match('/' . $this->_remoteAttribute . '/', $doc) &&
                                !!preg_match('/' . $this->_nameAttribute . ' ([w]+)/', $doc, $matches) &&
                                $method === $matches[1]
                            ) {
                                $serverMethod = $rMethod->getName();
                                $mconf = array(
                                    'name' => $method,
                                    'len' => $rMethod->getNumberOfRequiredParameters(),
                                );
                                if(!!preg_match('/' . $this->_api->getFormAttribute() . '/', $doc)) {
                                    $mconf['formHandler'] = true;
                                }                                
                            }
                        }
                        if(!$serverMethod) {
                            throw new Exception("Call to undefined method: $method on class $class");
                        }                        
                    } else {
                        $rMethod = $rClass->getMethod($method);
                        $doc = $rMethod->getDocComment();
                        if($rMethod->isPublic() && strlen($doc) > 0) {
                            if(!!preg_match('/' . $this->_api->getRemoteAttribute() . '/', $doc)) {
                                $serverMethod = $method;
                                $mconf = array(
                                    'name' => $method,
                                    'len' => $rMethod->getNumberOfRequiredParameters(),
                                );
                                if(!!preg_match('/' . $this->_api->getFormAttribute() . '/', $doc)) {
                                    $mconf['formHandler'] = true;
                                }
                            }            
                        }                        
                    }
                }
                
                if(!isset($mconf)) {
                    throw new Exception("Call to undefined or unallowed method: $method on class $class");
                }
                
                if($this->isForm && (!isset($mconf['formHandler']) || $mconf['formHandler'] !== true)) {
                    throw new Exception("Called method $method on class $class is not a form handler");
                }
                
                $params = isset($cdata->data) && is_array($cdata->data) ? $cdata->data : array();
                
                if(count($params) < $mconf['len']) {
                    throw new Exception("Not enough required params specified for method: $method on class $class");
                }
                
                $response = array(
                    'type' => 'rpc',
                    'tid' => $cdata->tid,
                    'action' => $class,
                    'method' => $method
                );
                
                $className = $cconf['prefix'] . $class;
                $instance = new $className();
                
                $result = call_user_func_array(array($instance, $serverMethod), $params);
                $response['debug'] = Console::getMsgs();
                $response['result'] = $result;
            } catch(Exception $e) {
                $response = array(
                    'type' => 'exception',                    
                    'tid' => $cdata->tid,
                    'message' => $e->getMessage(),
                    'where' => $e->getTraceAsString()
                );
            }
            
            return $response;
        }
        
        public function getResponse($print = false) {
            if(!$this->_response) {
                $this->dispatch();
            }
            
            if($print !== false) $this->_print($this->_response);
            
            return $this->_response;
        }
        
        private function _print($response) {
            if(!$this->isForm) {
                header('Content-Type: text/javascript');
            }
    
            echo $response;
        }
}