source: trunk/prototype/api/newcontroller.php @ 5715

Revision 5715, 19.2 KB checked in by natan, 12 years ago (diff)

Ticket #2434 - Implementacao da repeticao de eventos na agenda e adicao de suporte a relacionamentos 1x1 na API

Line 
1<?php
2
3if( !defined( 'ROOTPATH' ) )
4    define( 'ROOTPATH', dirname(__FILE__).'/..' );
5
6require_once(ROOTPATH.'/api/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*/
18
19class Controller {
20
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       
67
68//      public static function read( $concept, $id = false, $options = false )
69//      {
70//          if( !isset($URI['id']) || !$URI['id'] )
71//              return self::find( $URI, $params, $criteria );
72//
73//          return self::call( 'read', $URI, $params, $criteria );
74//      }
75
76//      public static function deleteAll( $URI, $params = false, $criteria = false )
77//      {
78//          if( isset($URI['id']) && $URI['id'] )
79//              return self::delete( $URI, $params, $criteria );
80//
81//          return self::call( 'deleteAll', $URI, $params, $criteria );
82//      }
83
84        //      public static function replace( $URI, $params, $criteria = false )
85//      {
86//          if( isset($URI['id']) && $URI['id'] )
87//              return self::update( $URI, $params, $criteria );
88//
89//          return self::call( 'replace', $URI, $params, $criteria );
90//      }
91
92        public static function find( $concept, $options )
93        {   
94            return self::get( $options['filter'],  self::context( $options, array( 'concept' => $concept ) ) );
95        }
96
97        public static function delete( $concept, $id = false, $options = array() )
98        {
99            return self::put( false, self::context( $options, array( 'concept' => $concept, 'id' => $id ) ) );
100        }
101
102        public static function update( $concept, $data, $id = false, $options = array() )
103        {
104            return self::put( $data, self::context( $options, array( 'concept' => $concept, 'id' => $id ) ) );
105        }
106
107        public static function create( $concept, $data, $options = array() )
108        {
109            return self::put( $data, self::context( $options, array( 'concept' => $concept ) ) );
110        }
111
112        public static function put( $data, $options )
113        {
114            try
115            {
116                $context = self::context( $options );
117
118                $txId = self::begin( $context['service'] );
119
120                if( $context['format'] )
121                    $data = self::parse( $data, $context['format'], $options );
122
123                if( !isset($options['concept']) )
124                {
125                    $return = array();
126
127                    for( $data as $concept => $dt )
128                         $return[] = self::put( $dt, array_merge( array( 'concept' => $concept ), $options ) );
129                       
130                    return $return;
131                }
132
133
134                $model = self::$models[ $options['concept'] ];
135
136                $postpone = array();
137
138                if( $data )
139                {
140                    foreach( $model['hasMany'] as $linkName => $linkTarget )
141                    {
142                        $postpone[$linkTarget] = $dt[$linkName];
143                    }
144                    foreach( $model['hasOne'] as $linkName => $linkTarget )
145                    {
146                        if( isset( $dt[$linkName] ) && is_array( $dt[$linkName] ) )
147                            $dt[$linkName] = self::put( $dt[$linkName],  array_merge( array( 'concept' => $linkTarget ), $options ) );
148                    }
149                }
150
151                $method =        $dt ? isset( $dt['id'] ) ?
152                                'update' : 'create' : 'delete';
153
154                $context['id'] = $dt ? isset( $dt['id'] ) ?
155                                 $dt['id'] : false : $context['id'];
156
157                self::before( $concept.':'.$method, &$context, $options );
158                self::call( $method, $options, $dt );
159                self::after( $concept.':'.$method, &$context, $options );
160
161                $result = $context['result'];
162
163                if( !is_bool( $result ) && !is_string( $result ) && isset( $result['id'] ) )
164                      $context['id'] = $result['id'];
165
166                foreach( $postpone as $linkTarget => $dt )
167                      foreach( $dt as $ii => $value )
168                      {
169                          if( !is_array( $value ) )
170                            $value = array( 'id' => $value );
171
172                          $value[ $options['concept'] ] = $options['id'];
173
174                          self::put( $value, array_merge( array( 'concept' => $linkTarget ), $options ) );
175                      }
176
177                if( $txId )
178                    return self::commit( $options['service'], $txId );
179            }
180            catch( Exception $e )
181            {
182                if( !self::fallback( $e ) )
183                    self::closeAll();
184
185                return( false );
186            }
187       
188            return( $options['id'] );
189        }
190
191        public static function context( $options, $custom = false )
192        {
193            if( $service )
194                $options['service'] = $service;
195
196            return $options;
197        }
198
199        public static function get( $filter, $options = false )
200        {
201            return self::call( 'find', self::context( $options, array( 'filter' => $filter ) ) );
202        }
203
204        public static function connect( $service, $options )
205        {
206            $result = self::call( 'open', self::context( $options, array( 'service' => $service ) ) );
207
208            if( is_string( $result ) )
209                throw new Exception( $result );
210
211            return( true );
212        }
213
214        public static function begin( $service, $txId = false, $options = false )
215        {
216            $context = self::context( $options );
217
218            $result = self::call( 'begin', $options );
219
220            if( !$txId )
221                $txId = $result ? $result : self::$txID++;
222
223            if( isset( self::$transactions[ $txId ] ) )
224                return( false );
225
226            self::$transactions[ $txId ] = array( 'txID' => $txId );
227            self::$transactions[ $service ][] =& self::$transactions[ $txId ];
228
229            return( $txId );
230        }
231
232        public static function commit( $service, $txId = false, $options = false )
233        {
234            $context = self::context( $options );
235
236            $txs = self::$transactions[ $service . ( $txId ? '.'.$txId : '' ) ];
237
238            if( !is_array( $txs ) ) $txs = array( $txs );
239
240            $return = array();
241
242            foreach( $txs as $tx )
243            {
244                $txID = $tx['txID'];
245
246                $result = false;
247
248                if( !$options || !$options['rollback'] )
249                    $result = self::call( 'commit', $context, $tx );
250
251                if( !$result )
252                    $result = self::call( 'rollback', $context, $tx );
253
254                $return[ $txID ] = $result;
255
256                unset( self::$transactions[ $txID ] );
257            }
258
259            return( $txId ? $return[ $txId ] : $return );
260        }
261
262        public static function rollback( $service, $txId = false, $options = array() )
263        {
264            return self::commit( $service, $txId, self::context( $options, array( 'rollback' => true ) ) );
265        }
266
267        public static function fallback( $exception, $context ) // ver a melhor forma de tratar exceptions nesse caso
268        {
269            if( !self::emmit( 'fallback', self::context( $context, array( 'exception' => $exception ) ), $exception ) )
270                error_log( $exception->getMessage() );
271 
272            return( true );
273        }
274
275        public static function format( $data, $service = false, $options = array() )
276        {
277            return self::call( 'format', self::context( $options, array( 'service' => $service ) ), $data );
278        }
279
280        public static function parse( $data, $service = false, $options = array() )
281        {
282            return self::call( 'parse', self::context( $options, array( 'service' => $service ) ), $data );
283        }
284
285        public static function before( $eventName, &$context, $extra = false )
286        {
287            return self::emmit( 'before.'.$eventName, $context, $extra );
288        }
289
290        public static function after( $eventName, &$context, $extra = false )
291        {
292            return self::emmit( 'after.'.$eventName, $context, $extra );
293        }
294
295        public static function emmit( $eventName, &$context, $extra = false )
296        {
297            if( self::$listeners[ $eventName ] )
298                return( false );
299
300            foreach( self::$listeners[ $eventName ] as $listen => $listener )
301            {
302                 $return = $listener->$listen( $context, $extra );
303
304                 if( $return === false )
305                    return( true );
306
307                 $context = self::context( $context, array( 'return' => $return ) );
308            }
309
310            return( $return );
311        }
312
313        //TODO: Compatibilizar as configs relativas aos modulos, adicionando os mesmos nas options passadas
314        public static function call( $method, $options, $data = false ) //see how data fit in it
315        {
316            try
317            {
318                $context = self::context( $options, array( 'data' => $data ) );
319
320                $service = $context['service'];
321
322                if( $context['config'] )
323                    self::connect( $service, $context['config'] );
324
325                self::before( $service.'.'.$method, &$context, $options );
326
327                if( self::$services[ $service ] )
328                    switch( $method )
329                    {
330                        case 'find': $return = self::$services[ $service ]->find( $context['URI'], $context['properties'], $context['criteria'] ); break;
331
332                        case 'read': $return = self::$services[ $service ]->read( $context['URI'], $context['properties']/*, $criteria*/ ); break;
333
334                        case 'create': $return = self::$services[ $service ]->create( $context['URI'], $context['properties']/*, $criteria*/ ); break;
335
336                        case 'delete': $return = self::$services[ $service ]->delete( $context['URI'], $context['properties']/*, $criteria*/ ); break;
337
338                        case 'deleteAll': $return = self::$services[ $service ]->deleteAll( $context['URI'], $context['properties'], $context['criteria'] ); break;
339
340                        case 'update': $return = self::$services[ $service ]->update( $context['URI'], $context['properties']/*, $criteria*/ ); break;
341
342                        case 'replace': $return = self::$services[ $service ]->replace( $context['URI'], $context['properties'], $context['criteria'] ); break;
343
344                        case 'begin': $return = self::$services[ $service ]->begin( $context['URI'] ); break;
345
346                        case 'commit': $return = self::$services[ $service ]->commit( $context['URI'], $context['criteria'] ); break;
347
348                        case 'rollback': $return = self::$services[ $service ]->rollback( $context['URI'], $context['criteria'] ); break;
349
350                        case 'parse': $return = self::$services[ $service ]->parse( $context['properties'], $context['criteria'] ); break;
351
352                        case 'analize': $return = self::$services[ $service ]->analize( $context['properties'], $context['criteria'] ); break;
353
354                        case 'format': $return = self::$services[ $service ]->format( $context['properties'], $context['criteria'] ); break;
355
356                        default : $return = self::$services[ $service ]->$method( $context['properties'], $context['criteria'] );
357                    }
358
359                $context['return'] = $return;
360
361                self::after( $service.'.'.$method, &$context, $options );
362            }
363            catch( Exception $e )
364            {
365                if( !self::fallback( $e ) )
366                    self::closeAll();
367
368                return( false );
369            }
370
371            return( $context['return'] );
372        }
373
374//      public static function URI( $className, $id = false, $service = false )
375//      {
376//          return array( 'concept' => $className,
377//                        'service' => $service ? $service : false,
378//                        'id' => $id ? $id : '' );
379//      }
380
381        //TODO: Compatibilizar as configs relativas aos modulos, adicionando os mesmo nos parametros passados
382//      public static function links( $concept = false )
383//      {
384//          if( !isset(self::$config[ $concept ]) )
385//            self::$config[ $concept ] = self::loadConfig( $concept );
386//
387//          return( isset(self::$config[ $concept ]['links']) ?
388//                        self::$config[ $concept ]['links'] : array() );
389//      }
390
391//      public static function isConcept( $concept )
392//      {
393//          if( isset( self::$config[ $concept ] ) &&
394//              self::$config[ $concept ] )
395//              return( true );
396//              else
397//              return file_exists( ROOTPATH."/config/$concept.ini" );
398//      }
399
400//      public static function getConcept( $concept, $moduleName = false )
401//      {
402//          if( isset( self::$config[ $concept ] ) )
403//              return( self::$config[ $concept ] );
404//
405//          return( self::$config[ $concept ] = self::loadConfig( $concept, $moduleName ) );
406//      }
407
408        public static function loadCache( $cacheType = 'Memory' )
409        {
410            include_once( "cache/MemoryCache.php" );
411            return new MemoryCache();
412        }
413
414        //TODO: Compatibilizar as configs relativas aos modulos, adicionando os mesmo nos parametros passados
415        public static function loadConfig( $className, $isService = false)
416        {
417            $fileName = $className.'.'.($isService ? 'srv' : 'ini');
418
419            $config = self::$cache->get( $fileName );
420       
421            if( !$config )
422            {
423                $config = parse_ini_file( ROOTPATH.'/config/'.$fileName, true );
424
425                self::$cache->put( $fileName, $config );
426            }
427
428            return( $config );
429        }
430
431        public static function import( $path, $ext = ".php" )
432        {
433            if( !isset(self::$includes[$path]) )
434        {
435                require_once( ROOTPATH.'/'.$path.$ext );
436                self::$includes[$path] = false;
437            }
438
439            return( self::$includes[$path] );
440        }
441
442        public static function load( $path, $class = false )
443            {
444            if( $return = self::import( $path, "" ) )
445                return( $return );
446
447            if( !$class ){
448                preg_match( '/^\/?.*\/([^\/]+).php$/', $path, $class );
449                $class = $class[1];
450            }
451
452            $object =  self::$cache->get( $class );
453
454            if( !$object )
455            {
456                $object = new $class();
457                 self::$cache->put( $class, $object );
458            }
459
460            self::$includes[$path] = $object;
461
462            return( $object );
463        }
464
465        public static function wallet( $serviceName )
466        {
467            if( !isset( self::$wallet ) )
468            {
469                //// Hack //// TODO: passar o init da sessão no login do expresso
470                Config::init();
471
472                if(isset($_SESSION['wallet']))
473                    self::$wallet = $_SESSION['wallet'];
474                /////////////
475            }
476
477            return isset( self::$wallet[ $serviceName ] )? self::$wallet[ $serviceName ] : false;
478        }
479               
480       
481
482        public static function configure( $config, $newConfig )
483        {
484            foreach( $newConfig as $key => $value )
485                $config[$key] = $value;
486
487            return( $config );
488            }
489
490        public static function dispatch( $dispatcher, $data, $optionsMap = false )
491        {
492//          if( $mappedTo )
493//              $data = array( $mappedTo => $data );
494//
495//          foreach( $data as $method => $params )
496//          {
497// //           foreach( $data[ $method ] as $name => $value )
498//          }
499//
500//          self::import( "$dispatcher.php" );
501        }
502
503        //TODO: Compatibilizar as configs relativas aos modulos, adicionando os mesmo nos parametros passados
504        public static function service( $serviceName, $concept = false )
505        {
506            if( isset( self::$services[ $serviceName ] ) )
507                return self::$services[ $serviceName ];
508
509            if( !isset(self::$config[ $serviceName ]) )
510                 self::$config[ $serviceName ] = self::loadConfig( $serviceName, true );
511
512            if( !isset(self::$config[ $serviceName ]) )
513                return( false );
514
515            if( !isset(self::$config[ $serviceName ]['type']) )
516                self::$config[ $serviceName ]['type'] = 'service';
517
518            self::import( 'api/'.self::$config[ $serviceName ]['type'] );   //TODO: Item 4
519
520            $service = self::load( self::$config[ $serviceName ]['path'],
521                                   self::$config[ $serviceName ]['class'] );
522
523              $srvConfig = array();
524
525            if( isset(self::$config[ $serviceName ][ 'config' ]) )
526                $srvConfig = self::configure( $srvConfig, self::$config[ $serviceName ][ 'config' ] );
527            if( $wallet = self::wallet( $serviceName ) )
528                $srvConfig = self::configure( $srvConfig, $wallet );
529            if( $concept && isset(self::$config[ $concept ]['service.config']) )
530                $srvConfig = self::configure( $srvConfig, self::$config[ $concept ]['service.config'] );
531
532            if( empty( $srvConfig ) )
533                $srvConfig = false;
534
535            if( $service && self::$config[ $serviceName ]['type'] === 'service' )
536                self::connect( $service, $srvConfig );
537
538            return( self::$services[ $serviceName ] = $service );
539        }
540
541        //TODO: Compatibilizar as configs relativas aos modulos, adicionando os mesmo nos parametros passados
542        public static function interceptor( $method, $concept = false, $serviceName = false, $isService = false )
543        {
544            if( $concept && !isset(self::$config[ $concept ]) )
545              self::$config[ $concept ] = self::loadConfig( $concept );
546
547            if( !$concept ) $concept = 'global';
548            if( !$isService || !$serviceName ) $serviceName = 'global';
549
550            if( !isset( self::$interceptors[ $concept ] ) )
551                self::$interceptors[ $concept ] = array();
552
553            if( !isset( self::$interceptors[ $concept ][ $serviceName ] ) )
554                self::$interceptors[ $concept ][ $serviceName ] = array();
555
556            if( !isset( self::$interceptors[ $concept ][ $serviceName ][ $method ] ) )
557            {
558                $events = array( 'before', 'after' );
559                $interceptors = array();
560
561                $prefix = ( $isService )? "$serviceName." : "";
562
563                foreach( $events as $i => $event )
564                {
565                    $interceptors[$event] = array();
566
567                    if( !isset(self::$config[$concept]["$prefix$event.$method"]) )
568                      continue;
569
570                    foreach( self::$config[$concept]["$prefix$event.$method"] as $intercept => $interceptor )
571                            $interceptors[$event][$intercept] = self::load( $interceptor );
572                }
573
574                self::$interceptors[ $concept ][ $serviceName ][ $method ] = $interceptors;
575            }
576
577            return( self::$interceptors[ $concept ][ $serviceName ][ $method ] );
578        }
579
580//      public static function interceptorCommit( $eventType, $commitList, $isService = false )
581//      {
582//          $result = array( $eventType => array() );
583//         
584//          if( is_array( $commitList ) )
585//              foreach( $commitList as $i => $tx )
586//              {
587//                  $interceptors = self::interceptor( 'commit', $tx['concept'], $tx['service'], $isService );
588//       
589//                  $result[$eventType] = array_merge( $result[$eventType], $interceptors[$eventType] );
590//              }
591//
592//          return( $result );
593//      }
594
595//      public static function fire( $eventType, $method, &$params, $original, $isService = false )
596//      {
597//          if( $method === 'commit' )
598//              $interceptors = self::interceptorCommit( $eventType, $params['criteria'], $isService );
599//
600//          else
601//              $interceptors = self::interceptor( $method,
602//                                                 isset($original['URI']['concept']) ? $original['URI']['concept'] : false,
603//                                                 isset($params['URI']['service']) ? $params['URI']['service'] : false, $isService );
604//
605//          if( $interceptors && isset($interceptors[ $eventType ]) )
606//              foreach( $interceptors[ $eventType ] as $intercept => $interceptor )
607//              {
608//                  $return = $interceptor->$intercept( $params['URI'], $params['properties'], $params['criteria'], $original/*, $params['service']*/ );
609//
610//                  if( $return === false )
611//              return( false );
612//
613//                  if( isset($return) )
614//                      $params['properties'] = $return;
615//              }
616//
617//            return( $params );
618//      }
619
620        /*
621          * ex: array
622          *             (
623          *                     [0] array( 'OR', array( array( '=', 'campo', 'valor' ),
624                                                          array( 'OR', array( array( '=', 'campo', 'valor' ) ) ) )
625          *                     [1] array( '=', 'campo' , 'valor' )
626          *                     [2] array( 'OR' , array( array( '=' , campo', 'valor' ) ) )
627          *                     [3] array( 'IN', 'campo', array( '1' , '2' , '3' ) )
628          *             )
629          * OR
630          *         array( '=' , 'campo' , 'valor' )
631        */
632
633        //TODO: Compatibilizar as configs relativas aos modulos, adicionando os mesmo nos parametros passados
634        public static function serviceName( $URI, $original = false )
635        {
636             $concept = "";
637
638            if( $original && isset($original['concept']) && $original['concept'] )
639                $concept = $original['concept'];
640            elseif( isset($URI['concept']) && $URI['concept'] )
641                $concept = $URI['concept'];
642
643            if( ( !isset($URI['service']) || !$URI['service'] ) && $concept )
644            {
645                if( !isset(self::$config[ $concept ]) )
646                    self::$config[ $concept ] = self::loadConfig( $concept );
647
648                $URI['service'] = self::$config[ $concept ][ 'service' ];
649            }
650
651            if( !isset($URI['service']) )
652                throw new Exception( "CONFIGURATION ERROR: service name from concept '$concept' not found" );
653
654            return( $URI );
655        }
656}
657
658Controller::$cache = Controller::loadCache();
659?>
Note: See TracBrowser for help on using the repository browser.