Changeset 5341
- Timestamp:
- 01/10/12 11:25:51 (12 years ago)
- Location:
- trunk
- Files:
-
- 385 added
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/prototype/REST.php
r5136 r5341 1 1 <?php 2 //TODO:Arrumar isso 3 // define( 'ROOTPATH' , '/home/natan/expresso2.4' ); 2 4 3 5 $REST = $_GET['q']; unset( $_GET['q'] ); … … 8 10 if( !(count($REST) % 2) ) 9 11 $id = array_pop($REST); 12 else 13 $id = false; 10 14 11 15 $concept = array_pop($REST); 16 17 $parents = array(); 12 18 13 19 while( $REST ) 14 20 $parents[ array_shift($REST) ] = array_shift($REST); 15 21 16 require_once 'app/controller.php'; 17 $controller = Controller::newInstance( $concept, $id, $parents ); 22 $accept = $_SERVER["HTTP_ACCEPT"]; 23 24 $args = array(); 18 25 19 26 if( $_SERVER["REQUEST_METHOD"] === "GET" ) 20 27 { 21 $attr = $_GET["attr"]; 28 if( isset( $_GET["attr"] ) ) 29 { 30 $args = $_GET["attr"]; 22 31 unset( $_GET["attr"] ); 32 } 23 33 24 echo $controller->find( $attr, $_GET ); 25 return; 34 $method = $id ? "read" : "find"; 26 35 } 36 else 37 { 38 parse_str( file_get_contents('php://input'), $args ); 27 39 28 $accept = $_SERVER["HTTP_ACCEPT"]; 29 30 parse_str( file_get_contents('php://input'), $args ); 31 32 switch( $_SERVER["REQUEST_METHOD"] ) 33 { 34 case "DELETE": 40 switch( $_SERVER["REQUEST_METHOD"] ) 35 41 { 36 echo $controller->delete( $args, $_GET ); 42 case "DELETE": 43 $method = $id ? "delete" : "deleteAll"; 37 44 break; 38 }39 45 case "PUT": 40 { 41 echo $controller->update( $args, $_GET ); 46 $method = $id ? "update" : "replace"; 42 47 break; 43 }44 48 case "POST": 45 { 46 echo $controller->create( $args, $_GET ); 49 $method = "create"; 47 50 break; 48 51 } 49 52 } 50 53 54 require_once 'app/controller.php'; 55 56 $URI = Controller::URI( $concept, $id ); 57 58 $args = array_merge( $args, array('context'=>$parents)); 59 60 echo json_encode( Controller::call( $method, $URI, $args, $_GET ) ); 61 62 Controller::closeAll(); 63 51 64 ?> -
trunk/prototype/app/cache/MemoryCache.php
r5136 r5341 72 72 file_put_contents( "/tmp/cache.log", file_get_contents( "/tmp/cache.log" ) . $output . "\n" ); 73 73 74 if($compressed) 75 return $this->_memcache->set($id, $data, MEMCACHE_COMPRESSED, $expire); 76 else 77 return $this->_memcache->set($id, $data, 0, $expire); 74 // if($compressed) 75 // return $this->_memcache->set($id, $data, MEMCACHE_COMPRESSED, $expire); 76 // else 77 // return $this->_memcache->set($id, $data, 0, $expire); 78 return false; 78 79 } 79 80 … … 86 87 public function get($id){ 87 88 88 $return = $this->_memcache->get($id); 89 // $return = $this->_memcache->get($id); 90 $return = false; 89 91 90 92 if( $return ){ -
trunk/prototype/app/controller.php
r5136 r5341 1 1 <?php 2 2 3 require_once "service.php"; 3 if( !defined( 'ROOTPATH' ) ) 4 define( 'ROOTPATH', dirname(__FILE__).'/..' ); 5 6 require_once(ROOTPATH.'/app/config.php'); 7 8 /** 9 TODO list: 10 11 * definir de forma centralizada os caminhos e as constantes necessárias; 12 * criar um User Agent detect e um OS server detect para customizações espeçÃficas de cada browser / servidor; 13 * criar um registrador para fallback handlers; 14 * criar um dependency manager na configuração dos serviços, para poder gerenciar os imports corretamente 15 * criar um login e a recuperação da sessão; 16 17 */ 4 18 5 19 class Controller { 6 20 7 var $config; 8 var $className; 9 var $parent; 10 var $target; 11 var $cache; 12 var $service; 13 var $includes; 14 15 public static function newInstance( $className, $id = false, $parents = false ) 16 { 17 return new Controller( $className, $id, $parents ); 18 } 19 20 public function __construct( $className, $id = false, $parents = false ) 21 { 22 $this->className = $className; 23 24 if( is_array( $id ) ) 25 { 26 $parents = $id; 27 $id = null; 28 } 29 30 $this->parents = $parents; 31 $this->target = $id; 32 $this->includes = array(); 33 21 static $cache; 22 static $services = array(); 23 static $interceptors = array(); 24 static $config = array(); 25 static $includes = array(); 26 static $tx = array(); 27 static $txID = 0; 28 static $wallet; 29 30 public function __destruct() 31 { 32 // if( $this->service ) 33 // $this->service->close(); 34 // else 35 self::closeAll(); 36 } 37 38 public static function closeAll() 39 { 40 if( self::$services ) 41 foreach( self::$services as $serviceName => $service ) 42 if( self::$config[ $serviceName ]['type'] === 'service' ) 43 $service->close(); 44 } 45 46 public static function clearAll() 47 { 48 return self::$cache->clearAll(); 49 } 50 51 public static function clear( $id ) 52 { 53 return self::$cache->clear( $id ); 54 } 55 56 public static function check( $id ) 57 { 58 return self::$cache->get( $id ); 59 } 60 61 public static function store( $id, $data, $expires, $compressed ) 62 { 63 return self::$cache->put( $id, $data, $expires, $compressed ); 64 } 65 66 public static function put( $URI, $data, $txIds = false ) 67 { 68 try 69 { 70 $URI = self::serviceName( $URI ); 71 72 if( $commit = !$txIds ) 73 $txIds = array(); 74 75 if( !isset( self::$tx[ $URI['service'] ] ) ) 76 { 77 self::call( 'begin', $URI ); 78 self::$tx[ $txIds[] = $URI['service'] ] = array(); 79 } 80 81 $method = $data ? isset( $data['id'] ) ? 82 'update' : 'create' : 'delete'; 83 84 $links = self::links( $URI['concept'] ); 85 86 $Tx = array( 'order' => self::$txID++ ); 87 88 $postpone = array(); 89 90 if( $data ) 91 { 92 $URI['id'] = isset( $data['id'] ) ? $data['id'] : false; 93 94 foreach( $links as $linkName => $linkTarget ) 95 { 96 if( isset( $data[$linkName] ) && is_array( $data[$linkName] ) ) 97 { 98 if( self::isConcept( $linkName ) ) 99 $data[$linkName] = self::put( array( 'concept' => $linkTarget ), $data[$linkName], &$txIds ); 100 else 101 $postpone[$linkTarget] = $data[$linkName]; 102 } 103 } 104 } 105 else 106 $URI['id'] = isset( $data['id'] ) ? $data['id'] : $URI['id']; 107 108 $result = Controller::call( $method, $URI, $data, false, false, true ); 109 110 if( !is_bool( $result ) && !is_string( $result ) && isset( $result['id'] ) ) 111 $URI['id'] = $result['id']; 112 113 self::$tx[ $URI['service'] ][] = array_merge( $Tx, array( 'id' => $URI['id'], 'concept' => $URI['concept'], 'method' => $method, 'service' => $URI['service'], 'rollback' => !!!$result ) ); 114 115 foreach( $postpone as $linkTarget => $dt ) 116 foreach( $dt as $ii => $value ) 117 { 118 if( !is_array( $value ) ) 119 $value = array( 'id' => $value ); 120 121 $value[ $URI['concept'] ] = $URI['id']; 122 123 self::put( array( 'concept' => $linkTarget ), $value, &$txIds ); 124 } 125 126 if( $commit ) 127 { 128 $result = array(); 129 130 for( $i = count( $txIds ) - 1; $i >= 0; $i-- ) 131 { 132 $currentTx = self::$tx[ $txIds[$i] ]; 133 unset( self::$tx[ $txIds[$i] ] ); 134 135 if( !self::commit( array( 'service' => $txIds[$i] ), $currentTx ) ) 136 { 137 self::rollback( array( 'service' => $txIds[$i] ), $currentTx ); 138 139 foreach( $currentTx as $i => $st ) 140 $currentTx[$i][ 'rollback' ] = true; 141 } 142 143 $result = array_merge( $result, $currentTx ); 144 } 145 146 self::$txID = 0; 147 148 return( $result ); 149 } 150 151 } 152 catch( Exception $e ) 153 { 154 if( !self::fallback( $e ) ) 155 self::closeAll(); 156 157 return( false ); 158 } 159 160 return( $URI['id'] ); 161 } 162 163 public static function get() 164 { 165 166 } 167 168 public static function find( $URI, $params = false, $criteria = false ) 169 { 170 if( isset($URI['id']) && $URI['id'] ) 171 return self::read( $URI, $params, $criteria ); 172 173 return self::call( 'find', $URI, $params, $criteria ); 174 } 175 176 public static function read( $URI, $params = false, $criteria = false ) 177 { 178 if( !isset($URI['id']) || !$URI['id'] ) 179 return self::find( $URI, $params, $criteria ); 180 181 return self::call( 'read', $URI, $params, $criteria ); 182 } 183 184 public static function deleteAll( $URI, $params = false, $criteria = false ) 185 { 186 if( isset($URI['id']) && $URI['id'] ) 187 return self::delete( $URI, $params, $criteria ); 188 189 return self::call( 'deleteAll', $URI, $params, $criteria ); 190 } 191 192 public static function delete( $URI, $params = false, $criteria = false ) 193 { 194 if( !isset($URI['id']) || !$URI['id'] ) 195 return self::deleteAll( $URI, $params, $criteria ); 196 197 return self::call( 'delete', $URI, $params, $criteria ); 198 } 199 200 public static function replace( $URI, $params, $criteria = false ) 201 { 202 if( isset($URI['id']) && $URI['id'] ) 203 return self::update( $URI, $params, $criteria ); 204 205 return self::call( 'replace', $URI, $params, $criteria ); 206 } 207 208 public static function update( $URI, $params, $criteria = false ) 209 { 210 if( !isset($URI['id']) || !$URI['id'] ) 211 return self::replace( $URI, $params, $criteria ); 212 213 return self::call( 'update', $URI, $params, $criteria ); 214 } 215 216 public static function create( $URI, $params, $criteria = false ) 217 { 218 return self::call( 'create', $URI, $params, $criteria ); 219 } 220 221 public static function begin( $URI, $params = false, $criteria = false ) 222 { 223 return self::call( 'begin', $URI, $params, $criteria ); 224 } 225 226 public static function commit( $URI, $criteria = false ) 227 { 228 return self::call( 'commit', $URI, false, $criteria ); 229 } 230 231 public static function rollback( $URI, $criteria = false ) 232 { 233 return self::call( 'rollback', $URI, false, $criteria ); 234 } 235 236 public static function format( $URI, $params, $criteria = false ) 237 { 238 return self::call( 'format', $URI, $params, $criteria ); 239 } 240 241 public static function parse( $URI, $data, $criteria = false ) 242 { 243 return self::call( 'parse', $URI, $data, $criteria ); 244 } 245 246 public static function URI( $className, $id = false, $service = false ) 247 { 248 return array( 'concept' => $className, 249 'service' => $service ? $service : false, 250 'id' => $id ? $id : '' ); 251 } 252 253 public static function links( $concept ) 254 { 255 if( !isset(self::$config[ $concept ]) ) 256 self::$config[ $concept ] = self::loadConfig( $concept ); 257 258 return( isset(self::$config[ $concept ]['links']) ? 259 self::$config[ $concept ]['links'] : array() ); 260 } 261 262 public static function isConcept( $concept ) 263 { 264 if( isset( self::$config[ $concept ] ) && 265 self::$config[ $concept ] ) 266 return( true ); 267 else 268 return file_exists( ROOTPATH."/config/$concept.ini" ); 269 } 270 271 public static function getConcept( $concept ) 272 { 273 if( isset( self::$config[ $concept ] ) ) 274 return( self::$config[ $concept ] ); 275 276 return( self::$config[ $concept ] = self::loadConfig( $concept ) ); 277 } 278 279 public static function loadCache( $cacheType = 'Memory' ) 280 { 34 281 include_once( "cache/MemoryCache.php" ); 35 $this->cache = new MemoryCache(); 36 37 $this->config = $this->cache->get( "$className.ini" ); 38 39 if( !$this->config ) 40 { 41 $this->config = parse_ini_file( "config/$className.ini", true ); 42 43 $this->cache->put( "$className.ini", $this->config[$className] ); 44 } 45 46 $this->service = $this->load( "service" ); 47 48 if( $this->service ) 49 $this->service->connect( $this->config["config"] ); 50 } 51 52 public function __destruct() 53 { 54 if( $this->service ) 55 $this->service->close(); 56 } 57 58 public function load( $type ) 59 { 60 if( !$this->config[$type] ) 282 return new MemoryCache(); 283 } 284 285 public static function loadConfig( $className, $isService = false ) 286 { 287 $fileName = $className.'.'.($isService ? 'srv' : 'ini'); 288 289 $config = self::$cache->get( $fileName ); 290 291 if( !$config ) 292 { 293 $config = parse_ini_file( ROOTPATH."/config/$fileName", true ); 294 295 self::$cache->put( $fileName, $config ); 296 } 297 298 return( $config ); 299 } 300 301 public static function import( $path, $ext = ".php" ) 302 { 303 if( !isset(self::$includes[$path]) ) 304 { 305 require_once( ROOTPATH.'/'.$path.$ext ); 306 self::$includes[$path] = false; 307 } 308 309 return( self::$includes[$path] ); 310 } 311 312 public static function load( $path, $class = false ) 313 { 314 if( $return = self::import( $path, "" ) ) 315 return( $return ); 316 317 if( !$class ){ 318 preg_match( '/^\/?.*\/([^\/]+).php$/', $path, $class ); 319 $class = $class[1]; 320 } 321 322 $object = self::$cache->get( $class ); 323 324 if( !$object ) 325 { 326 $object = new $class(); 327 self::$cache->put( $class, $object ); 328 } 329 330 self::$includes[$path] = $object; 331 332 return( $object ); 333 } 334 335 public static function wallet( $serviceName ) 336 { 337 if( !isset( self::$wallet ) ) 338 { 339 //// Hack //// TODO: passar o init da sessão no login do expresso 340 Config::init(); 341 342 if(isset($_SESSION['wallet'])) 343 self::$wallet = $_SESSION['wallet']; 344 ///////////// 345 } 346 347 return isset( self::$wallet[ $serviceName ] )? self::$wallet[ $serviceName ] : false; 348 } 349 350 public static function connect( $service, $config ) 351 { 352 $result = $service->open( $config ); 353 354 if( is_string( $result ) ) 355 throw new Exception( $result ); 356 357 return( true ); 358 } 359 360 public static function configure( $config, $newConfig ) 361 { 362 foreach( $newConfig as $key => $value ) 363 $config[$key] = $value; 364 365 return( $config ); 366 } 367 368 public static function dispatch( $dispatcher, $data, $optionsMap = false ) 369 { 370 // if( $mappedTo ) 371 // $data = array( $mappedTo => $data ); 372 // 373 // foreach( $data as $method => $params ) 374 // { 375 // // foreach( $data[ $method ] as $name => $value ) 376 // } 377 // 378 // self::import( "$dispatcher.php" ); 379 } 380 381 public static function service( $serviceName, $concept = false ) 382 { 383 if( isset( self::$services[ $serviceName ] ) ) 384 return self::$services[ $serviceName ]; 385 386 if( !isset(self::$config[ $serviceName ]) ) 387 self::$config[ $serviceName ] = self::loadConfig( $serviceName, true ); 388 389 if( !isset(self::$config[ $serviceName ]) ) 61 390 return( false ); 62 391 63 return $this->import( $this->config[$type]["path"], 64 $this->config[$type]["class"] ); 65 } 66 67 public function import( $path, $class ) 68 { 69 if( !$class ){ 70 preg_match( "/^\/?.*\/([^\/]+).php$/", $path, $class ); 71 $class = $class[1]; 72 } 392 if( !isset(self::$config[ $serviceName ]['type']) ) 393 self::$config[ $serviceName ]['type'] = 'service'; 394 395 self::import( 'app/'.self::$config[ $serviceName ]['type'] ); //TODO: Item 4 396 397 $service = self::load( self::$config[ $serviceName ]['path'], 398 self::$config[ $serviceName ]['class'] ); 399 400 $srvConfig = array(); 401 402 if( isset(self::$config[ $serviceName ][ 'config' ]) ) 403 $srvConfig = self::configure( $srvConfig, self::$config[ $serviceName ][ 'config' ] ); 404 if( $wallet = self::wallet( $serviceName ) ) 405 $srvConfig = self::configure( $srvConfig, $wallet ); 406 if( $concept && isset(self::$config[ $concept ]['service.config']) ) 407 $srvConfig = self::configure( $srvConfig, self::$config[ $concept ]['service.config'] ); 408 409 if( empty( $srvConfig ) ) 410 $srvConfig = false; 411 412 if( $service && self::$config[ $serviceName ]['type'] === 'service' ) 413 self::connect( $service, $srvConfig ); 414 415 return( self::$services[ $serviceName ] = $service ); 416 } 417 418 public static function interceptor( $method, $concept = false, $serviceName = false, $isService = false ) 419 { 420 if( $concept && !isset(self::$config[ $concept ]) ) 421 self::$config[ $concept ] = self::loadConfig( $concept ); 422 423 if( !$concept ) $concept = 'global'; 424 if( !$isService || !$serviceName ) $serviceName = 'global'; 425 426 if( !isset( self::$interceptors[ $concept ] ) ) 427 self::$interceptors[ $concept ] = array(); 428 429 if( !isset( self::$interceptors[ $concept ][ $serviceName ] ) ) 430 self::$interceptors[ $concept ][ $serviceName ] = array(); 431 432 if( !isset( self::$interceptors[ $concept ][ $serviceName ][ $method ] ) ) 433 { 434 $events = array( 'before', 'after' ); 435 $interceptors = array(); 436 437 $prefix = ( $isService )? "$serviceName." : ""; 438 439 foreach( $events as $i => $event ) 440 { 441 $interceptors[$event] = array(); 442 443 if( !isset(self::$config[$concept]["$prefix$event.$method"]) ) 444 continue; 445 446 foreach( self::$config[$concept]["$prefix$event.$method"] as $intercept => $interceptor ) 447 $interceptors[$event][$intercept] = self::load( $interceptor ); 448 } 449 450 self::$interceptors[ $concept ][ $serviceName ][ $method ] = $interceptors; 451 } 452 453 return( self::$interceptors[ $concept ][ $serviceName ][ $method ] ); 454 } 455 456 public static function interceptorCommit( $eventType, $commitList, $isService = false ) 457 { 458 $result = array( $eventType => array() ); 459 460 if( is_array( $commitList ) ) 461 foreach( $commitList as $i => $tx ) 462 { 463 $interceptors = self::interceptor( 'commit', $tx['concept'], $tx['service'], $isService ); 464 465 $result[$eventType] = array_merge( $result[$eventType], $interceptors[$eventType] ); 466 } 467 468 return( $result ); 469 } 470 471 public static function fire( $eventType, $method, &$params, $original, $isService = false ) 472 { 473 if( $method === 'commit' ) 474 $interceptors = self::interceptorCommit( $eventType, $params['criteria'], $isService ); 475 476 else 477 $interceptors = self::interceptor( $method, 478 isset($original['URI']['concept']) ? $original['URI']['concept'] : false, 479 isset($params['URI']['service']) ? $params['URI']['service'] : false, $isService ); 480 481 if( $interceptors && isset($interceptors[ $eventType ]) ) 482 foreach( $interceptors[ $eventType ] as $intercept => $interceptor ) 483 { 484 $return = $interceptor->$intercept( $params['URI'], $params['properties'], $params['criteria'], $original/*, $params['service']*/ ); 485 486 if( $return === false ) 487 return( false ); 488 489 if( isset($return) ) 490 $params['properties'] = $return; 491 } 492 493 return( $params ); 494 } 495 496 /* 497 * ex: array 498 * ( 499 * [0] array( 'OR', array( array( '=', 'campo', 'valor' ), 500 array( 'OR', array( array( '=', 'campo', 'valor' ) ) ) ) 501 * [1] array( '=', 'campo' , 'valor' ) 502 * [2] array( 'OR' , array( array( '=' , campo', 'valor' ) ) ) 503 * [3] array( 'IN', 'campo', array( '1' , '2' , '3' ) ) 504 * ) 505 * OR 506 * array( '=' , 'campo' , 'valor' ) 507 */ 73 508 74 if( !$this->includes[$path] ) 75 { 76 include_once( $path ); 77 $this->includes[ $path ] = true; 78 } 79 80 $object = $this->cache->get( $class ); 81 82 if( $object ) 83 return( $object ); 84 85 $object = new $class(); 86 $this->cache->put( $class, $object ); 87 88 return( $object ); 89 } 90 91 public function clearAll() 92 { 93 return $this->cache->clearAll(); 94 } 95 96 public function clear( $id ) 97 { 98 return $this->cache->clear( $id ); 99 } 100 101 public function get( $id ) 102 { 103 return $this->cache->get( $id ); 104 } 105 106 public function put( $id, $data, $expires, $compressed ) 107 { 108 return $this->cache->put( $id, $data, $expires, $compressed ); 109 } 110 111 public function fireEvent( $event, $method, $params ) 112 { 113 if( !$this->config["$event.$method"] ) 114 return( $params ); 115 116 $original = $params; 117 118 foreach( $this->config["$event.$method"] as $intercept => $interceptor ) 119 { 120 if( is_string( $interceptor ) ) 121 $this->config["$event.$method"][$intercept] = $interceptor = $this->import( $interceptor ); 122 123 $return = $interceptor->$intercept( $original, $params ); 124 125 if( $return === false ) 126 return( false ); 127 128 if( $return ) 129 $params = $return; 130 } 131 132 return( $params ); 133 } 134 135 public function find( $params, $criteria = false ) 136 { 137 138 if( ($params = $this->fireEvent( "before", "find", $params )) === false ) 139 return( false ); 140 141 if( $this->service ) 509 public static function serviceName( $URI, $original = false ) 510 { 511 $concept = ""; 512 513 if( $original && isset($original['concept']) && $original['concept'] ) 514 $concept = $original['concept']; 515 elseif( isset($URI['concept']) && $URI['concept'] ) 516 $concept = $URI['concept']; 517 518 if( ( !isset($URI['service']) || !$URI['service'] ) && $concept ) 519 { 520 if( !isset(self::$config[ $concept ]) ) 521 self::$config[ $concept ] = self::loadConfig( $concept ); 522 523 $URI['service'] = self::$config[ $concept ][ 'service' ]; 524 } 525 526 if( !isset($URI['service']) ) 527 throw new Exception( "CONFIGURATION ERROR: service name from concept '$concept' not found" ); 528 529 return( $URI ); 530 } 531 532 public static function call( $method, $URI, $properties = false, $options = false, $service = false, $noTX = false ) 533 { 534 try 535 { 536 if( !isset($URI['concept']) ) $URI['concept'] = false; 537 538 $original = $params = array( 'properties' => $properties, 539 'criteria' => $options, 540 'URI' => $URI, 541 'service' => $service ); 542 543 if( isset($params['URI']['concept']) && !self::fire( 'before', $method, $params, $original ) ) 544 return( empty($params['properties']) ? false : $params['properties'] ); 545 546 if( $params && !$params['service'] ) 547 { 548 $params['URI'] = self::serviceName( $params['URI'], $original['URI'] ); 549 550 $params['service'] = self::service( $params['URI']['service'], $params['URI']['concept'] ); 551 } 552 553 if( isset($params['URI']['service']) ) 554 { 555 if( $commit = (!isset(self::$tx[ $params['URI']['service'] ]) && ( $method === 'create' || 556 $method === 'update' || 557 $method === 'delete' )) ) 558 { 559 self::call( 'begin', $params['URI'] ); 560 self::$tx[ $params['URI']['service'] ] = true; 561 } 562 563 if( !self::fire( 'before', $method, $params, $original, true ) ) 564 return( empty($params['properties']) ? false : $params['properties'] ); 565 } 566 567 if( $params['service'] ) 568 switch( $method ) 142 569 { 143 if( $this->target ) 144 $result = $this->service->retrieve( $this->className, $this->target, $this->parents, $params, $criteria ); 145 else 146 $result = $this->service->find( $this->className, $this->parents, $params, $criteria ); 147 148 if( $result ) 149 $params = $result; 150 } 151 152 if( ($result = $this->fireEvent( "after", "find", $params )) === false ) 153 return( false ); 154 155 $result = json_encode( $result ); 156 157 return( $result ); 158 } 159 160 public function update( $params, $criteria = false ) 161 { 162 163 if( !($params = $this->fireEvent( "before", "update", $params )) ) 570 case 'find': $return = $params['service']->find( $params['URI'], $params['properties'], $params['criteria'] ); break; 571 572 case 'read': $return = $params['service']->read( $params['URI'], $params['properties']/*, $criteria*/ ); break; 573 574 case 'create': $return = $params['service']->create( $params['URI'], $params['properties']/*, $criteria*/ ); break; 575 576 case 'delete': $return = $params['service']->delete( $params['URI'], $params['properties']/*, $criteria*/ ); break; 577 578 case 'deleteAll': $return = $params['service']->deleteAll( $params['URI'], $params['properties'], $params['criteria'] ); break; 579 580 case 'update': $return = $params['service']->update( $params['URI'], $params['properties']/*, $criteria*/ ); break; 581 582 case 'replace': $return = $params['service']->replace( $params['URI'], $params['properties'], $params['criteria'] ); break; 583 584 case 'begin': $return = $params['service']->begin( $params['URI'] ); break; 585 586 case 'commit': $return = $params['service']->commit( $params['URI'], $params['criteria'] ); break; 587 588 case 'rollback': $return = $params['service']->rollback( $params['URI'], $params['criteria'] ); break; 589 590 case 'parse': $return = $params['service']->parse( $params['properties'], $params['criteria'] ); break; 591 592 case 'format': $return = $params['service']->format( $params['properties'], $params['criteria'] ); break; 593 } 594 595 if( isset($return) && $return !== false ) 596 $params['properties'] = $return; 597 598 if( isset($params['URI']['service']) ) 599 { 600 if( !self::fire( 'after', $method, $params, $original, true ) ) 601 return( empty($params['properties']) ? false : $params['properties'] ); 602 603 if( $commit ) 604 { 605 if( !self::call( 'commit', $params['URI'], false, self::$tx[ $params['URI']['service'] ] ) ) 606 self::call( 'rollback', $params['URI'] , false, self::$tx[ $params['URI']['service'] ] ); 607 608 unset( self::$tx[ $params['URI']['service'] ] ); 609 } 610 } 611 612 if( isset($URI['concept']) && !self::fire( 'after', $method, $params, $original ) ) 613 return( empty($params['properties']) ? false : $params['properties'] ); 614 } 615 catch( Exception $e ) 616 { 617 if( !self::fallback( $e ) ) 618 self::closeAll(); 619 164 620 return( false ); 165 166 if( $this->service ) 167 { 168 if( is_string( $idOrfilter ) ) 169 $result = $this->service->update( $this->className, $this->target, $this->parents, $params, $criteria ); 170 else 171 $result = $this->service->replace( $this->className, $this->parents, $params, $criteria ); 172 173 if( $result ) 174 $params = $result; 175 } 176 177 if( !($result = $this->fireEvent( "after", "update", $params )) ) 178 return( false ); 179 180 $result = json_encode( $result ); 181 182 return( $result ); 183 } 184 185 public function delete( $params, $criteria = false ) 186 { 187 if( ($params = $this->fireEvent( "before", "delete", $params )) === false ) 188 return( false ); 189 190 if( $this->service ) 191 { 192 if( is_string( $idOrfilter ) ) 193 $result = $this->service->delete( $this->className, $this->target, $this->parents, $params, $criteria ); 194 else 195 $result = $this->service->deleteAll( $this->className, $this->parents, $params, $criteria ); 196 197 if( $result ) 198 $params = $result; 199 } 200 201 if( ($result = $this->fireEvent( "after", "delete", $params )) === false ) 202 return( false ); 203 204 $result = json_encode( $result ); 205 206 return( $result ); 207 } 208 209 public function create( $params ) 210 { 211 if( ($params = $this->fireEvent( "before", "create", $params )) === false ) 212 return( false ); 213 214 if( $this->service ) 215 { 216 $result = $this->service->create( $this->className, $this->parents, $params ); 217 218 if( $result ) 219 $params = $result; 220 } 221 222 if( ($result = $this->fireEvent( "after", "create", $params )) === false ) 223 return( false ); 224 225 $result = json_encode( $result ); 226 227 return( $result ); 621 } 622 623 return( empty($params['properties']) ? false : $params['properties'] ); 624 } 625 626 public static function fallback( $exception ) 627 { 628 error_log( $exception->getMessage() ); 629 return( true ); 228 630 } 229 631 } 632 633 Controller::$cache = Controller::loadCache(); 230 634 ?> -
trunk/prototype/app/datalayer.js
r5283 r5341 48 48 $("form").live( "submit", function( event ){ 49 49 50 var action = $(this).attr("action"), res = false; 50 var $this = $(this), action = $this.attr('action'), res = false, 51 52 method = $this.attr( 'method' ), 53 54 fileInputs = $this.find('input[type="file"]'); 55 56 if( fileInputs.length && !$this.is('[enctype="multipart/form-data"]') ) 57 { 58 event.preventDefault(); 59 60 DataLayer.send( action, 61 [ method, 'iframe json' ], {}, 62 //TODO: check the type for conversion 63 DataLayer.receive, 64 false, { 'formData': $this.serializeArray(), 'fileInput': fileInputs } ); 65 66 return( false ); 67 } 51 68 52 69 if( res = internalUrl.exec( action ) ) … … 55 72 56 73 var data = DataLayer.form( this ); 74 75 switch( method.toUpperCase() ) 76 { 77 case 'GET': 78 DataLayer.get( res[0], data ); 79 80 case 'POST': 57 81 DataLayer.put( res[1], data ); 82 } 58 83 59 84 return( false ); … … 63 88 }); 64 89 65 $.storage = new $.store();90 this.storage = new $.store(); 66 91 67 92 DataLayer = { … … 113 138 }, 114 139 115 send: function( url, type, data, callback, sync ){140 send: function( url, type, data, callback, sync, extraOptions ){ 116 141 117 142 var result = false, fired = false; … … 147 172 envelope['dataType'] = type[1]; 148 173 174 if( extraOptions ) 175 envelope = $.extend( envelope, extraOptions ); 176 149 177 $.ajax( envelope ); 150 178 … … 152 180 }, 153 181 154 dispatch: function( dispatcher, data, callback, isPost ){182 dispatch: function( dispatcher, data, callback, isPost, dataType ){ 155 183 156 184 return this.send( this.dispatchPath + dispatcher + ".php", 157 [ ( isPost ? 'post' : 'get' ), 'json' ],185 [ ( isPost ? 'post' : 'get' ), dataType || 'json' ], 158 186 data, 159 187 callback ); … … 300 328 $.each( data[i][link], function( ii, el ){ 301 329 302 var isRef = false 330 var isRef = false; 303 331 304 332 if( isRef = ($.type(el) === "string") ) … … 332 360 333 361 if( data[i].id ) 334 data[i] = this.merge( concept,current[ data[i].id ], data[i] );362 data[i] = this.merge( current[ data[i].id ], data[i] ); 335 363 336 364 current[ key ] = data[i]; … … 344 372 for( var setKey in updateSet ) 345 373 { 346 DataLayer.put( setKey, updateSet[ setKey ], false );347 348 374 if( bothSides ) 349 375 for( var i = 0; i < updateSet[ setKey ].length; i++ ) 350 376 this.report( setKey, updateSet[ setKey ][i].id, updateSet[ setKey ][i] ); 377 378 DataLayer.put( setKey, updateSet[ setKey ], false ); 351 379 } 352 380 } … … 383 411 current[ id ] = this.check( concept, id ) || {}; 384 412 385 this.store( ':current', concept, current );413 this.store( ':current', concept, current[ id ] ); 386 414 387 415 var diff = this.diff( current[ id ], data ); … … 389 417 var diffs = this.check( ':diff', concept ) || {}; 390 418 419 if( diffs[ id ] ) 420 diff = this.merge( diffs[ id ], diff ); 421 422 if( !$.isEmptyObject( diff ) ) 391 423 diffs[ id ] = diff; 392 424 … … 430 462 prepareQ: function( queueName, concept, ids ){ 431 463 464 var notArray = false; 465 432 466 if( notArray = ($.type(concept) !== "array") ) 433 467 concept = [ concept ]; 468 469 var q = {}; 434 470 435 471 for( var i = 0; i < concept.length; i++ ) … … 437 473 var queue = this.check( ':' + queueName, concept[i] || false ); 438 474 475 if( !queue ) continue; 476 439 477 if( ids ) 440 478 { … … 451 489 queue = filtered; 452 490 } 491 492 q[ concept[i] ] = queue; 453 493 } 454 494 455 return( queue);495 return( notArray ? q[ concept[0] ] : q ); 456 496 }, 457 497 458 498 clearQ: function( concept, ids ){ 459 499 460 var current = this.check( ':current', concept || false );500 // var current = this.check( ':current', concept || false ); 461 501 var diffs = this.check( ':diff', concept || false ); 462 502 463 503 if( !ids ) 464 current =diffs = {};504 /* current =*/ diffs = {}; 465 505 else 466 506 { … … 470 510 for( var i = 0; i < ids.length; i++ ) 471 511 { 472 delete current[ ids[i] ];512 // delete current[ ids[i] ]; 473 513 delete diffs[ ids[i] ]; 474 514 } 475 515 } 476 516 477 this.store( ':current', concept, current );517 // this.store( ':current', concept, current ); 478 518 this.store( ':diff', concept, diffs ); 479 519 }, … … 483 523 var queue = this.prepareQ( 'diff', concept, ids ); 484 524 485 this.sync( queue, concept || false, callback );525 this.sync( queue, !$.isArray(concept) && concept || false, callback ); 486 526 }, 487 527 … … 523 563 // } 524 564 565 var received = DataLayer.receive( data ); 566 567 for( var URI in URIs ) 568 if( typeof received[URI] !== "undefined" ) 569 DataLayer.clearQ( URIs[URI].concept, URIs[URI].id ); 570 571 if( callback ) 572 callback( received ); 573 574 // for( var URI in data ) 575 // { 576 // var parsed = DataLayer.parseURI( URI ), 577 // 578 // concept = parsed[1], id = parsed[3]; 579 // 580 // if( $.type(data[URI]) === "string" ) 581 // { 582 // //TODO:threat the exception thrown 583 // DataLayer.rollback( concept, id ); 584 // delete URIs[ URI ]; 585 // continue; 586 // } 587 // 588 // if( data[URI] === false ){ 589 // DataLayer.remove( concept, id, false ); 590 // continue; 591 // } 592 // 593 // if( id !== data[URI].id ) 594 // DataLayer.move( concept, id, data[URI].id ); 595 // 596 // DataLayer.put( concept, id, data[URI], false ); 597 // } 598 // 599 // for( var URI in URIs ) 600 // DataLayer.clearQ( URIs[URI].concept, URIs[URI].id ); 601 // 602 // if( callback ) 603 // callback(); 604 605 }, true ); 606 607 }, 608 609 receive: function( data ){ 610 611 var received = {}; 612 525 613 for( var URI in data ) 526 614 { 527 615 var parsed = DataLayer.parseURI( URI ), 528 616 529 concept = parsed[1], id = parsed[3]; 617 concept = parsed[4], id = parsed[5]; 618 619 received[ URI ] = data[ URI ]; 530 620 531 621 if( $.type(data[URI]) === "string" ) … … 533 623 //TODO:threat the exception thrown 534 624 DataLayer.rollback( concept, id ); 535 delete URIs[ URI ];536 625 continue; 537 626 } … … 548 637 } 549 638 550 for( var URI in URIs ) 551 DataLayer.clearQ( URIs[URI].concept, URIs[URI].id ); 639 return( received ); 552 640 553 if( callback ) 554 callback(); 555 556 }, true ); 557 558 }, 559 560 receive: function( concept, data ){ 561 562 this.put( concept, data, false ); 563 564 // if( typeof data.URI === "undefined" ) 565 // { 566 // URI = this.add( concept, data, oneSide ); 567 // } 568 // else if( data.URI === false ) 569 // { 570 // status = this.remove( concept, URI, oneSide ); 571 // } 572 // else 573 // { 574 // status = this.set( concept, URI, data, oneSide ); 575 // } 576 // 577 // if( URI && data.URI && URI !== data.URI ) 578 // this.move( concept, URI, data.URI ); 641 }, 642 643 644 645 merge: function( current, data ){ 646 647 return this.copy( data, current ); 648 649 // return $.extend( current, data ); 650 651 }, 652 653 // clone objects, skip other types. 654 clone: function(target) { 655 if ( typeof target == 'object' ) { 656 Clone.prototype = target; 657 return new Clone(); 658 } else { 659 return target; 660 } 661 }, 662 663 // Shallow Copy 664 shallowCopy: function(target) { 665 if (typeof target !== 'object' ) { 666 return target; // non-object have value sematics, so target is already a copy. 667 } else { 668 var value = target.valueOf(); 669 if (target != value) { 670 // the object is a standard object wrapper for a native type, say String. 671 // we can make a copy by instantiating a new object around the value. 672 return new target.constructor(value); 673 } else { 674 // ok, we have a normal object. If possible, we'll clone the original's prototype 675 // (not the original) to get an empty object with the same prototype chain as 676 // the original. If just copy the instance properties. Otherwise, we have to 677 // copy the whole thing, property-by-property. 678 if ( target instanceof target.constructor && target.constructor !== Object ) { 679 var c = clone(target.constructor.prototype); 680 681 // give the copy all the instance properties of target. It has the same 682 // prototype as target, so inherited properties are already there. 683 for ( var property in target) { 684 if (target.hasOwnProperty(property)) { 685 c[property] = target[property]; 686 } 687 } 688 } else { 689 var c = {}; 690 for ( var property in target ) c[property] = target[property]; 691 } 692 693 return c; 694 } 695 } 696 }, 697 698 // entry point for deep copy. 699 // source is the object to be deep copied. 700 // depth is an optional recursion limit. Defaults to 256. 701 // deep copy handles the simple cases itself: non-objects and object's we've seen before. 702 // For complex cases, it first identifies an appropriate DeepCopier, then delegate the details of copying the object to him. 703 copy: function(source, result, depth) { 704 705 // null is a special case: it's the only value of type 'object' without properties. 706 if ( source === null ) return null; 707 708 // All non-objects use value semantics and don't need explict copying. 709 if ( typeof source !== 'object' ) return source; 710 711 if( !depth || !(depth instanceof RecursionHelper) ) depth = new RecursionHelper(depth); 712 713 var cachedResult = depth.getCachedResult(source); 714 715 // we've already seen this object during this deep copy operation 716 // so can immediately return the result. This preserves the cyclic 717 // reference structure and protects us from infinite recursion. 718 if ( cachedResult ) return cachedResult; 719 720 // objects may need special handling depending on their class. There is 721 // a class of handlers call "DeepCopiers" that know how to copy certain 722 // objects. There is also a final, generic deep copier that can handle any object. 723 for ( var i=0; i<this.comparators.length; i++ ) { 724 725 var comparator = this.comparators[i]; 726 727 if ( comparator.can(source) ) { 579 728 580 581 }, 582 583 584 585 merge: function( concept, current, data ){ 586 587 return $.extend( current, data ); 588 729 // once we've identified which DeepCopier to use, we need to call it in a very 730 // particular order: create, cache, populate. This is the key to detecting cycles. 731 // We also keep track of recursion depth when calling the potentially recursive 732 // populate(): this is a fail-fast to prevent an infinite loop from consuming all 733 // available memory and crashing or slowing down the browser. 734 735 if( !result ) 736 // Start by creating a stub object that represents the copy. 737 result = comparator.create(source); 738 else if( !comparator.can(result) ) 739 throw new Error("can't compare diferent kind of objects."); 740 741 // we now know the deep copy of source should always be result, so if we encounter 742 // source again during this deep copy we can immediately use result instead of 743 // descending into it recursively. 744 depth.cacheResult(source, result); 745 746 // only DeepCopier.populate() can recursively deep copy. So, to keep track 747 // of recursion depth, we increment this shared counter before calling it, 748 // and decrement it afterwards. 749 depth.depth++; 750 if ( depth.depth > depth.maxDepth ) { 751 throw new Error("Exceeded max recursion depth in deep copy."); 752 } 753 754 var thisPass = this; 755 756 // It's now safe to let the comparator recursively deep copy its properties. 757 comparator.populate( function(source, result) { return thisPass.copy(source, result, depth); }, source, result ); 758 759 depth.depth--; 760 761 return result; 762 } 763 } 764 // the generic copier can handle anything, so we should never reach this line. 765 throw new Error("no DeepCopier is able to copy " + source); 766 }, 767 768 // publicly expose the list of deepCopiers. 769 comparators: [], 770 771 // make deep copy() extensible by allowing others to 772 // register their own custom Comparators. 773 registerComparator: function(comparatorOptions) { 774 775 // publicly expose the Comparator class. 776 var comparator = { 777 778 // determines if this Comparator can handle the given object. 779 can: function(source) { return false; }, 780 781 // starts the deep copying process by creating the copy object. You 782 // can initialize any properties you want, but you can't call recursively 783 // into the copy(). 784 create: function(source) { }, 785 786 // Completes the deep copy of the source object by populating any properties 787 // that need to be recursively deep copied. You can do this by using the 788 // provided deepCopyAlgorithm instance's copy() method. This will handle 789 // cyclic references for objects already deepCopied, including the source object 790 // itself. The "result" passed in is the object returned from create(). 791 populate: function(deepCopyAlgorithm, source, result) {} 792 }; 793 794 for ( var key in comparatorOptions ) comparator[key] = comparatorOptions[key]; 795 796 this.comparators.unshift( comparator ); 589 797 }, 590 798 591 799 diff: function( base, toDiff ){ 592 800 593 // var df = toDiff; 594 // 595 // for( var key in base ){ 596 // 597 // if( base[key] === df[key] ) 598 // delete df[key]; 599 // 600 // 601 // } 801 if( typeof base === 'undefined' || $.isEmptyObject(base) ) 802 return( toDiff ); 803 602 804 if( toDiff === false ) 603 805 return( false ); 604 806 605 var toDiff = $.extend( {}, toDiff ); 606 607 if( isGeneratedId.test( toDiff.id ) ) 608 delete toDiff['id']; 807 toDiff = $.extend( {}, toDiff ); 808 809 for( var key in toDiff ) 810 { 811 switch( $.type(toDiff[key]) ) 812 { 813 case 'object': 814 if( $.isEmptyObject(toDiff[key] = this.diff( base[key], toDiff[key] )) ) 815 delete toDiff[key]; 816 break; 817 case 'array': 818 if( base[key] && !(toDiff[key] = $.grep( toDiff[key], function( el, i ){ return( $.inArray( el, base[key] ) === -1 ); } )).length ) 819 delete toDiff[key]; 820 break; 821 default: 822 if( base[key] == toDiff[key] ) 823 delete toDiff[key]; 824 } 825 } 609 826 610 827 return( toDiff ); … … 733 950 result = this.request( concept, id || filter.filter, filter.criteria ); 734 951 735 if( result && bothSides )952 if( result && bothSides && !filter.criteria.format ) 736 953 { 737 954 var newResult = []; … … 807 1024 }, 808 1025 1026 // clone: function( object ){ 1027 // 1028 // new { prototype: object }; 1029 // 1030 // }, 809 1031 810 1032 check: function( namespace, keys ){ … … 813 1035 return( false ); 814 1036 815 var result = $.storage.get( namespace );1037 var result = this.storage.get( namespace ); 816 1038 817 1039 if( !keys || !result ) … … 831 1053 }, 832 1054 1055 storage: { 1056 1057 cache: {}, 1058 1059 set: function( key, value ){ 1060 1061 this.cache[key] = value; 1062 1063 }, 1064 get: function( key ){ 1065 1066 return DataLayer.copy( this.cache[key] ); 1067 1068 }, 1069 del: function( key ){ 1070 1071 delete this.cache[key]; 1072 1073 } 1074 }, 1075 1076 flush: function(){ 1077 1078 }, 1079 1080 restore: function(){ 1081 1082 }, 1083 833 1084 store: function( namespace, key, data ){ 834 1085 835 1086 if( !data ) 836 return $.storage.set( namespace, key );1087 return this.storage.set( namespace, key ); 837 1088 838 1089 var res = this.check( namespace ) || {}; … … 840 1091 res[key] = data; 841 1092 842 return $.storage.set( namespace, res );1093 return this.storage.set( namespace, res ); 843 1094 }, 844 1095 … … 846 1097 847 1098 if( !key ) 848 return $.storage.del( namespace );1099 return this.storage.del( namespace ); 849 1100 850 1101 var res = this.check( namespace ) || {}; … … 852 1103 delete res[key]; 853 1104 854 return $.storage.set( namespace, res );1105 return this.storage.set( namespace, res ); 855 1106 856 1107 }, … … 858 1109 move: function( concept, oldId, newId ){ 859 1110 860 this. store( concept, newId, this.check( concept, oldId ));1111 this.put( concept, newId, this.check( concept, oldId ), false ); 861 1112 862 1113 this.del( concept, oldId ); … … 1308 1559 // 1309 1560 // if( !URI ) 1310 // return $.storage.del( concept );1561 // return this.storage.del( concept ); 1311 1562 // 1312 1563 // var res = this.check( concept ); … … 1499 1750 register: function( kind, concept, deployable ){ 1500 1751 1752 if( arguments.length < 3 ) 1753 { 1754 deployable = concept; 1755 concept = kind; 1756 kind = 'global'; 1757 } 1758 1501 1759 if( !this[ kind ][ concept ] ) 1502 1760 this[ kind ][ concept ] = []; … … 1522 1780 var result = tasks[i].task( now ); 1523 1781 1782 if( tasks[i].factor ) 1524 1783 DataLayer.schedule( tasks[i].task, tasks[i].factor ); 1525 1784 } … … 1531 1790 }, 1532 1791 1792 task: function( timestamp, task, factor ) 1793 { 1794 if( !this.tasks[ timestamp ] ) 1795 this.tasks[ timestamp ] = []; 1796 1797 this.tasks[ timestamp ][ this.tasks[ timestamp ].length ] = { task: task, factor: factor || false }; 1798 }, 1799 1533 1800 schedule: function( task, time ){ 1534 1801 … … 1537 1804 var index = parseInt( $.now() / 1000 ) + time; 1538 1805 1539 if( !this.tasks[ index ] ) 1540 this.tasks[ index ] = []; 1541 1542 this.tasks[ index ][ this.tasks[ index ].length ] = { task: task, factor: time }; 1806 this.task( index, task, time ); 1543 1807 }, 1544 1808 … … 1565 1829 this.basePath = this.dispatchPath + "REST.php?q="; 1566 1830 1831 this.schedule( function( now ){ 1832 1833 DataLayer.flush(); 1834 1835 }); 1836 1567 1837 this.start(); 1568 1838 } 1569 1839 } 1570 1840 1841 // the re-usable constructor function used by clone(). 1842 function Clone() {} 1843 1844 //Recursion Helper 1845 function RecursionHelper(){ this.clear(); }; 1846 1847 RecursionHelper.prototype = { 1848 1849 constructor: RecursionHelper, 1850 1851 // copiedObjects keeps track of objects already copied by this 1852 // deepCopy operation, so we can correctly handle cyclic references. 1853 copiedObjects: [], 1854 1855 depth: 0, 1856 1857 maxDepth: 256, 1858 1859 //reset the recursion helper cache 1860 clear: function(){ 1861 this.copiedObjects = []; 1862 this.depth = 0; 1863 }, 1864 1865 // add an object to the cache. No attempt is made to filter duplicates; 1866 // we always check getCachedResult() before calling it. 1867 cacheResult: function(source, result) { 1868 this.copiedObjects.push([source, result]); 1869 }, 1870 1871 // Returns the cached copy of a given object, or undefined if it's an 1872 // object we haven't seen before. 1873 getCachedResult: function(source) { 1874 1875 for ( var i=0; i<this.copiedObjects.length; i++ ) { 1876 if ( this.copiedObjects[i][0] === source ) { 1877 return this.copiedObjects[i][1]; 1878 } 1879 } 1880 1881 return undefined; 1882 } 1883 }; 1884 1885 // Generic Object copier 1886 // the ultimate fallback DeepCopier, which tries to handle the generic case. This 1887 // should work for base Objects and many user-defined classes. 1888 DataLayer.registerComparator({ 1889 can: function(source) { return true; }, 1890 1891 create: function(source) { 1892 if ( source instanceof source.constructor ) { 1893 return DataLayer.clone(source.constructor.prototype); 1894 } else { 1895 return {}; 1896 } 1897 }, 1898 1899 populate: function(deepCopy, source, result) { 1900 for ( var key in source ) { 1901 if ( source.hasOwnProperty(key) ) { 1902 result[key] = deepCopy(source[key], result[key]); 1903 } 1904 } 1905 return result; 1906 } 1907 }); 1908 1909 // Array copier 1910 DataLayer.registerComparator({ 1911 can: function(source) { 1912 return ( source instanceof Array ); 1913 }, 1914 1915 create: function(source) { 1916 return new source.constructor(); 1917 }, 1918 1919 populate: function(deepCopy, source, result) { 1920 for ( var i=0; i<source.length; i++) { 1921 result.push( deepCopy(source[i], result[i]) ); 1922 } 1923 return result; 1924 } 1925 }); 1926 1927 // Date copier 1928 DataLayer.registerComparator({ 1929 can: function(source) { 1930 return ( source instanceof Date ); 1931 }, 1932 1933 create: function(source) { 1934 return new Date(source); 1935 } 1936 }); 1937 1938 // HTML DOM Node copier 1939 DataLayer.registerComparator({ 1940 1941 // function to detect Nodes. In particular, we're looking 1942 // for the cloneNode method. The global document is also defined to 1943 // be a Node, but is a special case in many ways. 1944 can: function(source) { 1945 1946 if ( window.Node ) { 1947 return source instanceof Node; 1948 } else { 1949 // the document is a special Node and doesn't have many of 1950 // the common properties so we use an identity check instead. 1951 if ( source === document ) return true; 1952 return ( 1953 typeof source.nodeType === 'number' && 1954 source.attributes && 1955 source.childNodes && 1956 source.cloneNode 1957 ); 1958 } 1959 }, 1960 1961 create: function(source) { 1962 // there can only be one (document). 1963 if ( source === document ) return document; 1964 1965 // start with a shallow copy. We'll handle the deep copy of 1966 // its children ourselves. 1967 return source.cloneNode(false); 1968 }, 1969 1970 diff: function(base, source){ 1971 1972 }, 1973 1974 populate: function(deepCopy, source, result) { 1975 // we're not copying the global document, so don't have to populate it either. 1976 if ( source === document ) return document; 1977 1978 // if this Node has children, deep copy them one-by-one. 1979 if ( source.childNodes && source.childNodes.length ) { 1980 for ( var i=0; i<source.childNodes.length; i++ ) { 1981 var childCopy = deepCopy(source.childNodes[i], result.childNodes[i] || false ); 1982 result.appendChild(childCopy); 1983 } 1984 } 1985 } 1986 }); 1987 1571 1988 DataLayer.init(); 1572 1989 … … 1581 1998 // get: function( concept, filter ){ 1582 1999 // 1583 // var data = $.storage.get( concept );2000 // var data = this.storage.get( concept ); 1584 2001 // 1585 2002 // if( !filter ) … … 1672 2089 // data = [ data ]; 1673 2090 // 1674 // var target = $.storage.get( concept );2091 // var target = this.storage.get( concept ); 1675 2092 // 1676 2093 // var diff = { New: {}, Update:{}, Delete: {} }; … … 1698 2115 // data = $.extend( target, data ); 1699 2116 // 1700 // $.storage.set( concept, data );2117 // this.storage.set( concept, data ); 1701 2118 // 1702 2119 // // return; … … 1754 2171 // get: function( concept, filter ){ 1755 2172 // 1756 // var data = $.storage.get( concept );2173 // var data = this.storage.get( concept ); 1757 2174 // 1758 2175 // if( !filter ) … … 1798 2215 // data = $.extend( target, data ); 1799 2216 // 1800 // $.storage.set( concept, data );2217 // this.storage.set( concept, data ); 1801 2218 // 1802 2219 // //diff … … 1908 2325 // } 1909 2326 1910 // var model = $.storage.get( concept );2327 // var model = this.storage.get( concept ); 1911 2328 // 1912 2329 // $.each( model, function( i, o ){ … … 1933 2350 // concept = uri.join( '.' ); 1934 2351 1935 // var model = $.storage.get( concept );2352 // var model = this.storage.get( concept ); 1936 2353 // 1937 2354 // $.each( model, function( i, o ){ -
trunk/prototype/app/service.php
r5136 r5341 40 40 //--------------- 41 41 42 public function find ( $ concept, $parents = false, $justthese = false, $criteria = false );42 public function find ( $uri, $justthese = false, $criteria = false ); 43 43 44 public function re trieve ( $concept, $id, $parents = false, $justthese = false, $criteria = false);44 public function read ( $uri, $justthese = false/*, $criteria = false*/ ); 45 45 46 46 //--------------- 47 47 48 public function deleteAll( $ concept, $parents = false, $justthese = false, $criteria = false ); // avaliar48 public function deleteAll( $uri, $justthese = false, $criteria = false ); 49 49 50 public function delete ( $ concept, $id, $parents = false, $justthese = false, $criteria = false );50 public function delete ( $uri, $justthese = false/*, $criteria = false*/ );// avaliar 51 51 52 52 //--------------- 53 53 54 public function replace ( $ concept, $parents = false, $data,$criteria = false );54 public function replace ( $uri, $data, $criteria = false ); 55 55 56 public function update ( $ concept, $id, $parents = false, $data, $criteria = false);56 public function update ( $uri, $data/*, $criteria = false*/ ); 57 57 58 58 //--------------- 59 59 60 public function create ( $ concept, $parents = false, $data);60 public function create ( $uri, $data/*, $criteria = false*/ ); 61 61 62 62 //--------------- 63 63 64 public function connect( $config );64 public function open ( $config ); 65 65 66 public function close ();66 public function close (); 67 67 68 public function setup();69 68 70 public function teardown(); 69 public function begin ( $uri ); 70 71 public function commit ( $uri ); 72 73 public function rollback ( $uri ); 74 75 76 public function setup (); 77 78 public function teardown (); 71 79 } -
trunk/prototype/app/templates/foldertree.ejs
r5283 r5341 1 1 <% 2 2 var specialFolders = { 3 INBOX: {name:'Caixa de Entrada', classe:'inbox'}, 3 4 Inbox: {name:'Caixa de Entrada', classe:'inbox'}, 4 5 Trash: {name:'Lixeira', classe:'trash'}, -
trunk/prototype/services/ImapServiceAdapter.php
r5204 r5341 1 1 <?php 2 2 3 include_once "../header.session.inc.php";4 5 include_once "../expressoMail1_2/inc/class.imap_functions.inc.php";3 include_once ROOTPATH."/../header.session.inc.php"; 4 5 include_once ROOTPATH."/../expressoMail1_2/inc/class.imap_functions.inc.php"; 6 6 7 7 class ImapServiceAdapter extends imap_functions/* implements Service*/ … … 12 12 } 13 13 14 public function connect( $config ) 15 { 16 $this->init(); 17 } 18 19 public function find( $URI, $context, $justthese = false, $criteria = false ) 20 { 14 // public function connect( $config ) 15 // { 16 // $this->init(); 17 // } 21 18 22 if( is_array($URI))19 public function find( $URI, $justthese = false, $criteria = false ) 23 20 { 24 $criteria = $justthese; 25 $justthese = $context; 26 $context = $URI['context']; 21 $context = $justthese['context']; 27 22 $URI = $URI['concept']; 28 }29 23 30 24 switch( $URI ) … … 54 48 $sord = $criteria['sord']; //{desc} get the direction 55 49 50 $filter = $criteria['filter']; 51 56 52 if( !$sidx ) $sidx = 1; 57 53 58 54 $folder_name = str_replace( '.', $this->imap_delimiter, $context['folder'] ); 59 55 60 $folder = $this->get_range_msgs2(array('folder'=>$folder_name)); 61 62 $count = $folder['num_msgs']; 56 $count = imap_num_msg( $this->open_mbox( $folder_name ) ); 63 57 64 58 $total_pages = $count > 0 ? ceil( $count/$limit ) : 0; … … 67 61 $page = $total_pages; 68 62 69 $start = $limit * $page - $limit; // do not put $limit*($page - 1) 63 $start = $limit * $page - $limit; 64 65 // do not put $limit*($page - 1) 70 66 //end: for grid 71 67 72 $service_params = array( 'folder' => $folder_name, //INBOX 68 if( $filter ) 69 { 70 if( $filter[0] !== 'msgNumber' ) 71 { 72 for( $i = 0; $i < count($filter); $i++ ) 73 { 74 if( count( $filter[$i] ) === 4 ) 75 $criteria['isExact'] = ( array_shift( $filter[$i] ) === 'AND' ); 76 77 $criteria[ $filter[$i][0] ] = array( 'criteria' => $filter[$i][2], 'filter' => $filter[$i][1] ); 78 } 79 80 return $this->searchSieveRule($criteria); 81 } 82 83 $msgNumber = array(); 84 85 for( $i = $start; $i < $start + $limit && isset( $filter[2][$i] ); $i++ ) 86 $msgNumber[] = $filter[2][$i]; 87 88 if( empty( $msgNumber ) ) 89 return( false ); 90 91 $result = $this->get_info_msgs( array( 'folder' => $folder_name, 92 'msgs_number' => implode( ',', $msgNumber ) ) ); 93 94 foreach( $result as $i => $val ) 95 $result[$i] = unserialize( $val ); 96 97 } 98 else 99 { 100 $result = $this->get_range_msgs2( array( 'folder' => $folder_name, //INBOX 73 101 'msg_range_begin' => $start + 1, //?? 74 102 'msg_range_end' => $start + $limit, //$limit = $_GET['rows']; // get how many rows we want to have into the grid 75 103 'sort_box_type' => 'SORTARRIVAL', 76 104 'search_box_type' => 'ALL', 77 'sort_box_reverse' => 1 ); 78 79 $result = $this->to_utf8($this->get_range_msgs2($service_params)); 105 'sort_box_reverse' => 1 ) ); 106 } 80 107 //return var_export($result); 81 108 82 $response = array( "page" => $page, "total" => $total_pages, "records" => $ result['num_msgs']);109 $response = array( "page" => $page, "total" => $total_pages, "records" => $count ); 83 110 84 111 for ($i=0; $i<count($result); $i++) … … 96 123 { 97 124 $response["rows"][$i] = $result[$i]; 98 $response["rows"][$i]['body'] = $this->to_utf8($result[$i]['body']); 99 $response["rows"][$i]['timestamp'] = ( ( $result[$i]['udate']) * 1000 ); 100 //USA OS TIME ZONES 101 //$response["rows"][$i]['timestamp'] = ( ( $result[$i]['udate'] + $this->functions->CalculateDateOffset()) * 1000 ); 125 $response["rows"][$i]['timestamp'] = ( ( $result[$i]['udate'] + $this->functions->CalculateDateOffset() ) * 1000 ); 102 126 $response["rows"][$i]['flags'] = implode(',', $flags_enum); 103 127 $response["rows"][$i]['size'] = $response["rows"][$i]['Size']; 104 128 // $response["rows"][$i]['udate'] = ( $result[$i]['udate'] + $this->functions->CalculateDateOffset() * 1000 ); 105 129 unset($response["rows"][$i]['Size']); 106 130 } 107 131 } 132 133 $response = $this->to_utf8($response); 108 134 109 135 break; … … 113 139 } 114 140 115 public function retrieve( $concept, $id, $parents, $justthese = false, $criteria = false )116 {117 return $this->read( array( 'id' => $id,118 'concept' => $concept,119 'context' => $parents ), $justthese );120 }141 // public function retrieve( $concept, $id, $parents, $justthese = false, $criteria = false ) 142 // { 143 // return $this->read( array( 'id' => $id, 144 // 'concept' => $concept, 145 // 'context' => $parents ), $justthese ); 146 // } 121 147 122 148 public function read( $URI, $justthese = false ) 123 149 { 124 $folder_name = str_replace( '.', $this->imap_delimiter, $URI['context']['folder'] ); 125 126 $response = $this->get_info_msg( array('msg_number'=>$URI['id'],'msg_folder'=>$folder_name) ); 127 128 return $this->to_utf8( $response ); 150 151 return $this->to_utf8( $this->get_info_msg( array('msg_number'=>$URI['id'], 152 'msg_folder'=>str_replace( '.', $this->imap_delimiter, $justthese['context']['folder'] )) ) ); 129 153 } 130 154 … … 149 173 public function setup() 150 174 {} 175 176 public function commit( $uri ) 177 { return( true ); } 178 179 public function rollback( $uri ) 180 {} 181 182 public function begin( $uri ) 183 {} 184 151 185 152 186 public function teardown() … … 160 194 } 161 195 } elseif(is_string($in)) { 162 //if(mb_detect_encoding($in) != "UTF-8")163 196 return mb_convert_encoding( $in , 'UTF-8' , 'UTF-8 , ISO-8859-1' ); 164 //else165 // return $in;166 197 } else { 167 198 return $in;
Note: See TracChangeset
for help on using the changeset viewer.