Changeset 5341


Ignore:
Timestamp:
01/10/12 11:25:51 (12 years ago)
Author:
wmerlotto
Message:

Ticket #2434 - Commit inicial do novo módulo de agenda do Expresso - expressoCalendar

Location:
trunk
Files:
385 added
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/prototype/REST.php

    r5136 r5341  
    11<?php 
     2//TODO:Arrumar isso  
     3// define( 'ROOTPATH' , '/home/natan/expresso2.4' ); 
    24 
    35$REST = $_GET['q']; unset( $_GET['q'] ); 
     
    810if( !(count($REST) % 2) ) 
    911    $id = array_pop($REST); 
     12else 
     13    $id = false; 
    1014 
    1115$concept = array_pop($REST); 
     16 
     17$parents = array(); 
    1218 
    1319while( $REST ) 
    1420    $parents[ array_shift($REST) ] = array_shift($REST); 
    1521 
    16 require_once 'app/controller.php'; 
    17 $controller = Controller::newInstance( $concept, $id, $parents ); 
     22$accept = $_SERVER["HTTP_ACCEPT"]; 
     23 
     24$args = array(); 
    1825 
    1926if( $_SERVER["REQUEST_METHOD"] === "GET" ) 
    2027{ 
    21     $attr = $_GET["attr"]; 
     28    if( isset( $_GET["attr"] ) ) 
     29    { 
     30        $args = $_GET["attr"]; 
    2231    unset( $_GET["attr"] ); 
     32    } 
    2333 
    24     echo $controller->find( $attr, $_GET ); 
    25     return; 
     34    $method = $id ? "read" : "find"; 
    2635} 
     36else 
     37{ 
     38    parse_str( file_get_contents('php://input'), $args ); 
    2739 
    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"] ) 
    3541    { 
    36         echo $controller->delete( $args, $_GET ); 
     42        case "DELETE": 
     43            $method = $id ? "delete" : "deleteAll"; 
    3744        break; 
    38     } 
    3945    case "PUT": 
    40     { 
    41         echo $controller->update( $args, $_GET ); 
     46            $method = $id ? "update" : "replace"; 
    4247        break; 
    43     } 
    4448    case "POST": 
    45     { 
    46         echo $controller->create( $args, $_GET ); 
     49            $method = "create"; 
    4750        break; 
    4851    } 
    4952} 
    5053 
     54require_once 'app/controller.php'; 
     55 
     56$URI = Controller::URI( $concept, $id ); 
     57 
     58$args = array_merge( $args, array('context'=>$parents)); 
     59 
     60echo json_encode( Controller::call( $method, $URI, $args, $_GET ) ); 
     61 
     62Controller::closeAll(); 
     63 
    5164?> 
  • trunk/prototype/app/cache/MemoryCache.php

    r5136 r5341  
    7272        file_put_contents( "/tmp/cache.log", file_get_contents( "/tmp/cache.log" ) . $output . "\n" ); 
    7373 
    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; 
    7879    } 
    7980 
     
    8687    public function get($id){ 
    8788      
    88         $return = $this->_memcache->get($id); 
     89//         $return = $this->_memcache->get($id); 
     90          $return = false; 
    8991 
    9092        if( $return ){ 
  • trunk/prototype/app/controller.php

    r5136 r5341  
    11<?php 
    22 
    3 require_once "service.php"; 
     3if( !defined( 'ROOTPATH' ) ) 
     4    define( 'ROOTPATH', dirname(__FILE__).'/..' ); 
     5 
     6require_once(ROOTPATH.'/app/config.php'); 
     7 
     8/** 
     9TODO 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*/ 
    418 
    519class Controller { 
    620 
    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        { 
    34281            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 ]) ) 
    61390                return( false ); 
    62391 
    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        */ 
    73508         
    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 ) 
    142569            {  
    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 
    164620                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 ); 
    228630        } 
    229631} 
     632 
     633Controller::$cache = Controller::loadCache(); 
    230634?> 
  • trunk/prototype/app/datalayer.js

    r5283 r5341  
    4848$("form").live( "submit", function( event ){ 
    4949 
    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    } 
    5168     
    5269    if( res = internalUrl.exec( action ) ) 
     
    5572 
    5673        var data = DataLayer.form( this ); 
     74         
     75        switch( method.toUpperCase() ) 
     76        { 
     77          case 'GET': 
     78                DataLayer.get( res[0], data ); 
     79 
     80          case 'POST': 
    5781        DataLayer.put( res[1], data ); 
     82        } 
    5883 
    5984        return( false ); 
     
    6388}); 
    6489 
    65 $.storage = new $.store(); 
     90this.storage = new $.store(); 
    6691 
    6792DataLayer = { 
     
    113138    }, 
    114139     
    115     send: function( url, type, data, callback, sync ){ 
     140    send: function( url, type, data, callback, sync, extraOptions ){ 
    116141       
    117142          var result = false, fired = false; 
     
    147172              envelope['dataType'] = type[1]; 
    148173 
     174          if( extraOptions ) 
     175              envelope = $.extend( envelope, extraOptions ); 
     176 
    149177          $.ajax( envelope ); 
    150178       
     
    152180    }, 
    153181     
    154     dispatch: function( dispatcher, data, callback, isPost ){ 
     182    dispatch: function( dispatcher, data, callback, isPost, dataType ){ 
    155183       
    156184      return this.send( this.dispatchPath + dispatcher + ".php",  
    157                         [ ( isPost ? 'post' : 'get' ), 'json' ], 
     185                        [ ( isPost ? 'post' : 'get' ), dataType || 'json' ], 
    158186                        data, 
    159187                        callback ); 
     
    300328                        $.each( data[i][link], function( ii, el ){ 
    301329 
    302                                 var isRef = false 
     330                                var isRef = false; 
    303331 
    304332                                if( isRef = ($.type(el) === "string") ) 
     
    332360 
    333361                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] ); 
    335363 
    336364                 current[ key ] = data[i]; 
     
    344372            for( var setKey in updateSet ) 
    345373            { 
    346                 DataLayer.put( setKey, updateSet[ setKey ], false ); 
    347  
    348374                if( bothSides ) 
    349375                    for( var i = 0; i < updateSet[ setKey ].length; i++ ) 
    350376                      this.report( setKey, updateSet[ setKey ][i].id, updateSet[ setKey ][i] ); 
     377                     
     378                DataLayer.put( setKey, updateSet[ setKey ], false ); 
    351379            } 
    352380        } 
     
    383411            current[ id ] = this.check( concept, id ) || {}; 
    384412         
    385         this.store( ':current', concept, current ); 
     413        this.store( ':current', concept, current[ id ] ); 
    386414 
    387415        var diff = this.diff( current[ id ], data ); 
     
    389417        var diffs = this.check( ':diff', concept ) || {}; 
    390418 
     419        if( diffs[ id ] ) 
     420            diff = this.merge( diffs[ id ], diff ); 
     421 
     422        if( !$.isEmptyObject( diff ) ) 
    391423        diffs[ id ] = diff; 
    392424 
     
    430462    prepareQ: function( queueName, concept, ids ){ 
    431463       
     464      var notArray = false; 
     465       
    432466      if( notArray = ($.type(concept) !== "array") ) 
    433467          concept = [ concept ]; 
     468       
     469      var q = {}; 
    434470       
    435471      for( var i = 0; i < concept.length; i++ ) 
     
    437473          var queue = this.check( ':' + queueName, concept[i] || false ); 
    438474           
     475          if( !queue ) continue; 
     476 
    439477          if( ids ) 
    440478          { 
     
    451489              queue = filtered; 
    452490          } 
     491 
     492          q[ concept[i] ] = queue; 
    453493      } 
    454494       
    455       return( queue ); 
     495      return( notArray ? q[ concept[0] ] : q ); 
    456496    }, 
    457497     
    458498    clearQ: function( concept, ids ){ 
    459499       
    460         var current = this.check( ':current', concept || false ); 
     500//              var current = this.check( ':current', concept || false ); 
    461501        var diffs = this.check( ':diff', concept || false ); 
    462502 
    463503        if( !ids ) 
    464             current = diffs = {}; 
     504           /* current =*/ diffs = {}; 
    465505        else 
    466506        { 
     
    470510            for( var i = 0; i < ids.length; i++ ) 
    471511            { 
    472                 delete current[ ids[i] ]; 
     512//              delete current[ ids[i] ]; 
    473513                delete diffs[ ids[i] ]; 
    474514            } 
    475515        } 
    476516 
    477         this.store( ':current', concept, current ); 
     517//      this.store( ':current', concept, current ); 
    478518        this.store( ':diff', concept, diffs ); 
    479519    }, 
     
    483523        var queue = this.prepareQ( 'diff', concept, ids ); 
    484524 
    485         this.sync( queue, concept || false, callback ); 
     525        this.sync( queue, !$.isArray(concept) && concept || false, callback ); 
    486526    }, 
    487527     
     
    523563//          } 
    524564 
     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         
    525613            for( var URI in data ) 
    526614            {  
    527615                var parsed = DataLayer.parseURI( URI ), 
    528616    
    529                 concept = parsed[1], id = parsed[3]; 
     617            concept = parsed[4], id = parsed[5]; 
     618 
     619            received[ URI ] = data[ URI ]; 
    530620 
    531621                if( $.type(data[URI]) === "string" ) 
     
    533623                  //TODO:threat the exception thrown 
    534624                  DataLayer.rollback( concept, id ); 
    535                   delete URIs[ URI ]; 
    536625                  continue; 
    537626                } 
     
    548637            } 
    549638             
    550             for( var URI in URIs ) 
    551                  DataLayer.clearQ( URIs[URI].concept, URIs[URI].id ); 
     639        return( received ); 
    552640             
    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) ) { 
    579728         
    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 ); 
    589797    }, 
    590798  
    591799    diff: function( base, toDiff ){ 
    592800 
    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 
    602804        if( toDiff === false ) 
    603805            return( false ); 
    604806 
    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        } 
    609826 
    610827        return( toDiff ); 
     
    733950            result = this.request( concept, id || filter.filter, filter.criteria ); 
    734951 
    735             if( result && bothSides ) 
     952            if( result && bothSides && !filter.criteria.format ) 
    736953            { 
    737954              var newResult = []; 
     
    8071024    }, 
    8081025     
     1026//     clone: function( object ){ 
     1027//  
     1028//      new { prototype: object }; 
     1029//  
     1030//     }, 
    8091031 
    8101032    check: function( namespace, keys ){ 
     
    8131035            return( false ); 
    8141036 
    815         var result = $.storage.get( namespace ); 
     1037        var result = this.storage.get( namespace ); 
    8161038 
    8171039        if( !keys || !result ) 
     
    8311053    }, 
    8321054 
     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 
    8331084    store: function( namespace, key, data ){ 
    8341085 
    8351086        if( !data ) 
    836           return $.storage.set( namespace, key ); 
     1087          return this.storage.set( namespace, key ); 
    8371088 
    8381089        var res = this.check( namespace ) || {}; 
     
    8401091        res[key] = data; 
    8411092 
    842         return $.storage.set( namespace, res ); 
     1093        return this.storage.set( namespace, res ); 
    8431094    }, 
    8441095 
     
    8461097       
    8471098        if( !key ) 
    848           return $.storage.del( namespace ); 
     1099          return this.storage.del( namespace ); 
    8491100 
    8501101        var res = this.check( namespace ) || {}; 
     
    8521103        delete res[key]; 
    8531104 
    854         return $.storage.set( namespace, res ); 
     1105        return this.storage.set( namespace, res ); 
    8551106       
    8561107    }, 
     
    8581109     move: function( concept, oldId, newId ){ 
    8591110 
    860         this.store( concept, newId, this.check( concept, oldId ) ); 
     1111        this.put( concept, newId, this.check( concept, oldId ), false ); 
    8611112 
    8621113        this.del( concept, oldId ); 
     
    13081559//  
    13091560//      if( !URI ) 
    1310 //          return $.storage.del( concept ); 
     1561//          return this.storage.del( concept ); 
    13111562//  
    13121563//      var res = this.check( concept ); 
     
    14991750    register: function( kind, concept, deployable ){ 
    15001751 
     1752      if( arguments.length < 3 ) 
     1753      { 
     1754          deployable = concept; 
     1755          concept = kind; 
     1756          kind = 'global'; 
     1757      } 
     1758 
    15011759      if( !this[ kind ][ concept ] ) 
    15021760            this[ kind ][ concept ] = []; 
     
    15221780                  var result = tasks[i].task( now ); 
    15231781 
     1782                  if( tasks[i].factor ) 
    15241783                  DataLayer.schedule( tasks[i].task, tasks[i].factor ); 
    15251784              } 
     
    15311790    }, 
    15321791     
     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 
    15331800    schedule: function( task, time ){ 
    15341801 
     
    15371804        var index = parseInt( $.now() / 1000 ) + time; 
    15381805 
    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 ); 
    15431807    }, 
    15441808     
     
    15651829            this.basePath = this.dispatchPath + "REST.php?q="; 
    15661830 
     1831        this.schedule( function( now ){ 
     1832 
     1833            DataLayer.flush(); 
     1834 
     1835        }); 
     1836 
    15671837        this.start(); 
    15681838    } 
    15691839} 
    15701840 
     1841// the re-usable constructor function used by clone(). 
     1842function Clone() {} 
     1843 
     1844//Recursion Helper 
     1845function RecursionHelper(){ this.clear(); }; 
     1846 
     1847RecursionHelper.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. 
     1888DataLayer.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 
     1910DataLayer.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 
     1928DataLayer.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 
     1939DataLayer.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 
    15711988DataLayer.init(); 
    15721989 
     
    15811998//     get: function( concept, filter ){ 
    15821999//  
    1583 //      var data = $.storage.get( concept ); 
     2000//      var data = this.storage.get( concept ); 
    15842001//  
    15852002//      if( !filter ) 
     
    16722089//          data = [ data ]; 
    16732090//  
    1674 //      var target = $.storage.get( concept ); 
     2091//      var target = this.storage.get( concept ); 
    16752092//       
    16762093//      var diff = { New: {}, Update:{}, Delete: {} }; 
     
    16982115//          data = $.extend( target, data ); 
    16992116//  
    1700 //      $.storage.set( concept, data ); 
     2117//      this.storage.set( concept, data ); 
    17012118//  
    17022119// //   return; 
     
    17542171//     get: function( concept, filter ){ 
    17552172//  
    1756 //      var data = $.storage.get( concept ); 
     2173//      var data = this.storage.get( concept ); 
    17572174//  
    17582175//      if( !filter ) 
     
    17982215//          data = $.extend( target, data ); 
    17992216//        
    1800 //      $.storage.set( concept, data ); 
     2217//      this.storage.set( concept, data ); 
    18012218//       
    18022219//      //diff 
     
    19082325//          } 
    19092326 
    1910 //              var model = $.storage.get( concept ); 
     2327//              var model = this.storage.get( concept ); 
    19112328//  
    19122329//              $.each( model, function( i, o ){ 
     
    19332350//              concept = uri.join( '.' ); 
    19342351 
    1935 //              var model = $.storage.get( concept ); 
     2352//              var model = this.storage.get( concept ); 
    19362353//  
    19372354//              $.each( model, function( i, o ){ 
  • trunk/prototype/app/service.php

    r5136 r5341  
    4040//--------------- 
    4141 
    42     public function find     ( $concept,      $parents = false, $justthese = false, $criteria = false ); 
     42    public function find     ( $uri, $justthese = false, $criteria = false ); 
    4343 
    44     public function retrieve ( $concept, $id, $parents = false, $justthese = false, $criteria = false ); 
     44    public function read     ( $uri, $justthese = false/*, $criteria = false*/ ); 
    4545 
    4646//--------------- 
    4747 
    48     public function deleteAll( $concept,      $parents = false, $justthese = false, $criteria = false ); // avaliar 
     48    public function deleteAll( $uri, $justthese = false, $criteria = false );  
    4949 
    50     public function delete   ( $concept, $id, $parents = false, $justthese = false, $criteria = false ); 
     50    public function delete   ( $uri, $justthese = false/*, $criteria = false*/ );// avaliar 
    5151 
    5252//--------------- 
    5353 
    54     public function replace  ( $concept,      $parents = false, $data,            $criteria = false ); 
     54    public function replace  ( $uri, $data, $criteria = false ); 
    5555 
    56     public function update   ( $concept, $id, $parents = false, $data,             $criteria = false ); 
     56    public function update   ( $uri, $data/*, $criteria = false*/ ); 
    5757 
    5858//--------------- 
    5959 
    60     public function create   ( $concept,      $parents = false, $data ); 
     60    public function create   ( $uri, $data/*, $criteria = false*/ ); 
    6161 
    6262//--------------- 
    6363 
    64     public function connect  ( $config ); 
     64    public function open     ( $config ); 
    6565 
    66     public function close(); 
     66    public function close    (); 
    6767 
    68     public function setup(); 
    6968 
    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  (); 
    7179} 
  • trunk/prototype/app/templates/foldertree.ejs

    r5283 r5341  
    11<% 
    22        var specialFolders = { 
     3                        INBOX: {name:'Caixa de Entrada', classe:'inbox'},  
    34                        Inbox: {name:'Caixa de Entrada', classe:'inbox'},  
    45                        Trash: {name:'Lixeira', classe:'trash'},  
  • trunk/prototype/services/ImapServiceAdapter.php

    r5204 r5341  
    11<?php 
    22 
    3 include_once "../header.session.inc.php"; 
    4  
    5 include_once "../expressoMail1_2/inc/class.imap_functions.inc.php"; 
     3include_once ROOTPATH."/../header.session.inc.php"; 
     4 
     5include_once ROOTPATH."/../expressoMail1_2/inc/class.imap_functions.inc.php"; 
    66 
    77class ImapServiceAdapter extends imap_functions/* implements Service*/ 
     
    1212    } 
    1313 
    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//     } 
    2118         
    22         if( is_array($URI) ) 
     19    public function find( $URI, $justthese = false, $criteria = false ) 
    2320        {  
    24             $criteria = $justthese; 
    25             $justthese = $context; 
    26             $context = $URI['context']; 
     21        $context = $justthese['context']; 
    2722            $URI = $URI['concept']; 
    28         } 
    2923 
    3024        switch( $URI ) 
     
    5448                $sord  = $criteria['sord']; //{desc} get the direction 
    5549 
     50                $filter = $criteria['filter']; 
     51 
    5652                if( !$sidx ) $sidx = 1; 
    5753 
    5854                $folder_name = str_replace( '.', $this->imap_delimiter, $context['folder'] ); 
    5955                 
    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 ) ); 
    6357 
    6458                $total_pages = $count > 0 ? ceil( $count/$limit ) : 0; 
     
    6761                    $page = $total_pages; 
    6862 
    69                 $start = $limit * $page - $limit; // do not put $limit*($page - 1) 
     63                $start = $limit * $page - $limit; 
     64 
     65                // do not put $limit*($page - 1) 
    7066                //end: for grid 
    7167 
    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 
    73101                                         'msg_range_begin' => $start + 1, //?? 
    74102                                         'msg_range_end' => $start + $limit, //$limit = $_GET['rows']; // get how many rows we want to have into the grid 
    75103                                         'sort_box_type' => 'SORTARRIVAL',  
    76104                                         '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                } 
    80107                //return var_export($result); 
    81108 
    82                 $response = array( "page" => $page, "total" => $total_pages, "records" => $result['num_msgs'] ); 
     109                $response = array( "page" => $page, "total" => $total_pages, "records" => $count ); 
    83110                 
    84111                for ($i=0; $i<count($result); $i++) 
     
    96123                    { 
    97124                                $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 ); 
    102126                                $response["rows"][$i]['flags'] = implode(',', $flags_enum); 
    103127                                $response["rows"][$i]['size'] = $response["rows"][$i]['Size']; 
    104                                 $response["rows"][$i]['udate'] = ( $result[$i]['udate'] + $this->functions->CalculateDateOffset()  * 1000 ); 
     128//                      $response["rows"][$i]['udate'] = ( $result[$i]['udate'] + $this->functions->CalculateDateOffset()  * 1000 ); 
    105129                                unset($response["rows"][$i]['Size']); 
    106130                    } 
    107131                 } 
     132 
     133                $response = $this->to_utf8($response); 
    108134 
    109135                break; 
     
    113139    } 
    114140 
    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//     } 
    121147 
    122148    public function read( $URI, $justthese = false ) 
    123149    { 
    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'] )) ) ); 
    129153    } 
    130154 
     
    149173    public function setup() 
    150174    {} 
     175 
     176    public function commit( $uri ) 
     177    { return( true ); } 
     178 
     179    public function rollback( $uri ) 
     180    {} 
     181 
     182    public function begin( $uri ) 
     183    {} 
     184 
    151185 
    152186    public function teardown() 
     
    160194                }  
    161195        } elseif(is_string($in)) {  
    162                 //if(mb_detect_encoding($in) != "UTF-8")  
    163196                        return mb_convert_encoding( $in , 'UTF-8' , 'UTF-8 , ISO-8859-1' );  
    164                 //else  
    165                 //      return $in;  
    166197        } else {  
    167198                return $in;  
Note: See TracChangeset for help on using the changeset viewer.