Advertisement
fruffl

AOP/Injectable Object

Jan 13th, 2013
51
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 15.17 KB | None | 0 0
  1. <?PHP
  2.     NAMESPACE ILLI\Core;
  3.     USE ILLI\Core\Object\tAdapter;
  4.     USE ILLI\Core\Object\tFilter;
  5.     USE ILLI\Core\Object\tInvoke;
  6.     USE ILLI\Core\Object\tObserver;
  7.     USE ILLI\Core\Object\tSignal;
  8.     USE ILLI\Core\Object\tClass;
  9.     USE ILLI\Core\Object\tTo;
  10.     USE ILLI\Core\Object\tMethod;
  11.     USE ILLI\Core\Object\tMethodFilter;
  12.     USE ILLI\Core\Object\tMethodProto;
  13.     USE ILLI\Core\iObject;
  14.     USE ILLI\Core\Filter;
  15.    
  16.     CLASS Object IMPLEMENTS iObject
  17.     {
  18.         USE tMethodFilter
  19.         {
  20.             Core_Object_tMethodFilter_register as public applyMethodFilter;
  21.         }
  22.        
  23.         USE tAdapter;
  24.         USE tClass;
  25.         USE tFilter;
  26.         USE tMethod;
  27.         USE tObserver;
  28.         USE tSignal;
  29.         USE tTo;
  30.         USE tInvoke;
  31.         USE tMethodProto;
  32.        
  33.        
  34.         protected static $__parentClasses   = [];
  35.         protected static $__usedTraits      = [];
  36.        
  37.         /**
  38.          * used when item is not in initConfig and not in baseConfig
  39.          * @configurable
  40.          */
  41.         protected $__defaultConfig      = [];
  42.        
  43.         /**
  44.          * define class-properties for env
  45.          * @configurable
  46.          */
  47.         protected $__autoConfig         = [];
  48.        
  49.         /**
  50.          * property-value-pair by initConfig
  51.          */
  52.         protected $__env            = [];
  53.        
  54.         /**
  55.          * merged config: baseConfig + options-array from __construct
  56.          */
  57.         protected $__initConfig         = [];
  58.        
  59.         /**
  60.          * base config for object
  61.          */
  62.         private static $__baseConfig            =
  63.         [
  64.             '__run'     => TRUE,        // excecute setup()
  65.             '__main'    => '__main',        // onConstructEvent
  66.             '__delegate'    => NULL,        // class-delegate: adapter for every method; instance or className
  67.            
  68.             '__adapter' =>          // trigger__FUNCTION__ => hook | trigger__FUNCTION__ => [event => hook]
  69.             [
  70.                 //__FUNCTION__ => []        // 0 => class|instance, 1 => method | 0 => closure; overwrites methods from __delegate
  71.             ],
  72.            
  73.             '__filter'  =>          // trigger__FUNCTION__ => hook
  74.             [
  75.                 //__FUNCTION__ => []        // [filter 1, filter 2, filter n ...] | [eventName => [filter 1, filter 2, filter n]]; default event is '*'
  76.             ],
  77.            
  78.             '__proto'   =>          // prototype defines the core of a method; default (class internal): methodname calls prototypeMethodname
  79.             [
  80.                 //__FUNCTION__ => NULL      // delegate;
  81.             ],
  82.            
  83.             '__method'  =>          // public virtual methods, called by __call
  84.             [
  85.                                 // name => closure
  86.                                 // name => delegate
  87.             ],
  88.             '__observer'    =>
  89.             [
  90.                 //__FUNCTION__ => []        // event => [notify 1, notify 2, ...]
  91.             ],
  92.            
  93.             '__signal' =>
  94.             [
  95.                 //__FUNCTION__ =>           // trigger__FUNCTION__ => [event => hook]
  96.                 //[
  97.                 //  'PRE_EVENT' =>  [], // event => [signal 1, signal 2, ...]
  98.                 //  'POST_EVENT' => []  // event => [signal 1, signal 2, ...]
  99.                 //],
  100.             ],
  101.             '__class'   =>          // class alias hook: new __class['Alias']() instead of new hardCodedClassName()
  102.             [
  103.                 // 'ILLI\Core\Media' => 'My\Media'
  104.             ],
  105.             '__to'      =>          // cast to: type => handler
  106.             [
  107.                 'string' => 'toString',
  108.                 'array'  => 'toArray'
  109.             ],
  110.             '__protoprefix'     => 'prototype'  // prefix for prototype-method
  111.         ];
  112.        
  113.         public $__export            = [];
  114.        
  115.        
  116.         protected function __main()
  117.         {
  118.         }
  119.        
  120.         public static function __load()
  121.         {
  122.         }
  123.        
  124.         final public function __construct(array $__options = [])
  125.         {
  126.             $this->__initConfig = $this->extend(TRUE, self::$__baseConfig, $__options);
  127.            
  128.             if(TRUE === $this->__initConfig['__run'])
  129.                 $this->__run();
  130.                
  131.             return $this;
  132.         }
  133.        
  134.         protected function __run()
  135.         {
  136.             $this->__configure();
  137.            
  138.             $class = get_called_class();
  139.            
  140.                         $this->Core_Object_tMethod_install      ($class, $this->__initConfig['__method']);
  141.                         $this->Core_Object_tMethodProto_install ($class, $this->__initConfig['__proto']);
  142.                        
  143.                         $this->Core_Object_tAdapter_install     ($class, $this->__initConfig['__delegate']);
  144.                         $this->Core_Object_tAdapter_install     ($class, $this->__initConfig['__adapter']);
  145.                         $this->Core_Object_tObserver_install    ($class, $this->__initConfig['__observer']);
  146.                         $this->Core_Object_tSignal_install      ($class, $this->__initConfig['__signal']);
  147.                         $this->Core_Object_tFilter_install      ($class, $this->__initConfig['__filter']);
  148.                         $this->Core_Object_tTo_install      ($class, $this->__initConfig['__to']);
  149.                         $this->Core_Object_tClass_install   ($class, $this->__initConfig['__class']);
  150.            
  151.             $this->prototype('__construct', $this->__env);
  152.            
  153.             return $this;
  154.         }
  155.        
  156.         protected function __configure()
  157.         {
  158.             $defaultConfig      = &$this->__defaultConfig;
  159.             $initConfig     = &$this->__initConfig;
  160.             $autoConfig     = &$this->__autoConfig;
  161.             $env            = &$this->__env;
  162.            
  163.             foreach($autoConfig as $key => $flag)
  164.             {
  165.                 // option not given. use default value
  166.                 if(!isset($initConfig[$key])
  167.                 && isset($defaultConfig[$key]))
  168.                 {
  169.                     $env[$key] = $defaultConfig[$key];
  170.                     continue;
  171.                 }
  172.                
  173.                 if(!isset($initConfig[$flag])
  174.                 && isset($defaultConfig[$flag]))
  175.                 {
  176.                     $env[$flag] = $defaultConfig[$flag];
  177.                     continue;
  178.                 }
  179.                
  180.                 if($flag === 'merge') // initConfig + defaultConfig
  181.                 {
  182.                     if(isset($defaultConfig[$key]))
  183.                     {
  184.                         if(is_array($initConfig[$key])
  185.                         && is_array($defaultConfig[$key]))
  186.                         {
  187.                             $env[$key] = $this->extend
  188.                             (
  189.                                 TRUE,
  190.                                 $initConfig[$key],
  191.                                 $defaultConfig[$key]
  192.                             );
  193.                         }
  194.                         else
  195.                         {
  196.                             $env[$key] =
  197.                                 $initConfig[$key]
  198.                                 + $defaultConfig[$key];
  199.                         }
  200.                        
  201.                     }
  202.                     else
  203.                     {
  204.                         $env[$key] = $initConfig[$key];
  205.                     }
  206.                 }
  207.                 else // initConfig[${key}]
  208.                 if(isset($initConfig[$key]))
  209.                 {
  210.                     $env[$flag] = $initConfig[$flag];
  211.                 }
  212.                 else // initConfig[${flag}]
  213.                 if(isset($initConfig[$flag]))
  214.                 {
  215.                     $env[$flag] = $initConfig[$flag];
  216.                 }
  217.                 else // defaultConfig[${key}]
  218.                 if(isset($defaultConfig[$key]))
  219.                 {
  220.                     $env[$key] = $defaultConfig[$key];
  221.                 }
  222.                 else // default[${flag}]
  223.                 if(isset($defaultConfig[$flag]))
  224.                 {
  225.                     $env[$flag] = $defaultConfig[$flag];
  226.                 }
  227.                 else
  228.                 {
  229.                     $env[$flag] = NULL;
  230.                 }
  231.             }
  232.            
  233.             // accessible as property
  234.             foreach($env as $property => &$value)
  235.             {
  236.                 $this->{$property} =& $value;
  237.                
  238.                 // remove property from initConfig
  239.                 if(isset($initConfig[$property]))
  240.                     unset($initConfig[$property]);
  241.             }
  242.            
  243.             return $this;
  244.         }
  245.        
  246.         /**
  247.          * allows you to replaace the core-function of a method without editing your class-file
  248.          *
  249.          * <code>
  250.          * function myMethod()
  251.          * {
  252.          *  // do additional stuff
  253.          *  $this->prototype('myMethod');
  254.          *  // do additional stuff
  255.          *  // return $whatever;
  256.          * }
  257.          * </code>
  258.          *
  259.          *  1.  adapter-lookup
  260.          *
  261.          *  2.1 send signal PRE_EVENT with unfiltered parameters
  262.          *  2.2 filter parameters
  263.          *  2.3 run method-filters
  264.          *  2.3.1   run outer-filters
  265.          *  2.3.2   execute virtual method
  266.          *  2.3.3   execute virtual proto or physical existing proto
  267.          *  2.4 filter result
  268.          *  2.5 observer notify with filtered result
  269.          *  2.6 send signal POST_EVENT with filtered result
  270.          *  2.7 return filtered result
  271.          */
  272.         protected function prototype($__function, $__parameters)
  273.         {
  274.             if(isset($__parameters['this']))
  275.                 unset($__parameters['this']);
  276.                
  277.             $class = get_called_class();
  278.             $function = $__function;
  279.            
  280.             if(TRUE === $this->Core_Object_tAdapter_exists($class, $function))
  281.                 return $this->Core_Object_tAdapter_emit($class, $function, $__parameters);
  282.            
  283.             $this->Core_Object_tSignal_emit($class, $function, 'PRE_EVENT', $__parameters);
  284.            
  285.             $data   = $this->Core_Object_tFilter_emit($class, $function, $__parameters, ['event' => 'DATA']);
  286.            
  287.             $result = $this->Core_Object_tMethodFilter_emit($class, $function, $data, function(array $__params) use ($function, $data)
  288.             {
  289.                 $result = NULL;
  290.                
  291.                 if(TRUE === $this->Core_Object_tMethod_exists($function))
  292.                 {
  293.                     $result = $__params = $this->Core_Object_tMethod_emit($function, $__params);
  294.                 }
  295.                
  296.                 if(TRUE === $this->Core_Object_tMethodProto_exists($function))
  297.                 {
  298.                     $result = $this->Core_Object_tMethodProto_emit($function, $__params);
  299.                 }
  300.                 else
  301.                 {
  302.                     $proto = $function === '__construct'
  303.                         ? $this->__initConfig['__main']
  304.                         : $this->__initConfig['__protoprefix'].$function;
  305.                
  306.                     if($proto === $function)
  307.                     {
  308.                         throw new \Exception('Proto is called method '.$function);
  309.                         return $__params;
  310.                     }
  311.                    
  312.                     if(method_exists($this, $proto))
  313.                         $result = $this->Core_Object_tInvoke_method($proto, $__params);
  314.                 }
  315.                
  316.                 return $result;
  317.             });
  318.            
  319.             $result = [$result];
  320.             $result = $this->Core_Object_tFilter_emit($class, $function, $result, ['event' => 'RESULT']);
  321.            
  322.             $this->Core_Object_tObserver_emit($class, $function, $result);
  323.             $this->Core_Object_tSignal_emit($class, $function, 'POST_EVENT', $result);
  324.            
  325.             return $result[0];
  326.         }
  327.        
  328.         public static function parents($__className = NULL)
  329.         {
  330.             $parentClasses = &self::$__parentClasses;
  331.            
  332.             $class = NULL === $__className ? get_called_class() : $__className;
  333.            
  334.             if(isset($parentClasses[$class]))
  335.                 return $parentClasses[$class];
  336.            
  337.             $classes = [$class];
  338.                 while($class = get_parent_class($class))
  339.                     $classes[] = $class;
  340.                
  341.                 $classes = array_reverse($classes);
  342.                 $parentClasses[$class] = $classes;
  343.                
  344.                 return $classes;
  345.         }
  346.        
  347.         public static function traits($__className = NULL)
  348.         {
  349.             $usedTraits = &self::$__usedTraits;
  350.            
  351.             $class = NULL === $__className ? get_called_class() : $__className;
  352.             $classes = self::parents($class);
  353.            
  354.             if(isset($usedTraits[$class]))
  355.                 return $usedTraits[$class];
  356.            
  357.             $traits = [];
  358.             foreach($classes as $class)
  359.                 foreach((new \ReflectionClass($class))->getTraits() as $trait)
  360.                     $traits[] = $trait->name;
  361.            
  362.                 $usedTraits[$class] = $traits;
  363.                
  364.                 return $traits;
  365.         }
  366.        
  367.        
  368.         /**
  369.          * referenced runtime to create new object from called-class
  370.          */
  371.         public function link()
  372.         {
  373.             return $this->____construct($this->__runtimeConfig);
  374.         }
  375.        
  376.         /**
  377.          * dereference runtime and create new object from called-class
  378.          */
  379.         public function copy()
  380.         {
  381.             $class = get_called_class();
  382.             $config = $this->__env; // config is a reference!
  383.             unset($this->__env);    // unlink
  384.             $this->__env = $config; // re-reference original
  385.             return new $class($config);             // build
  386.         }
  387.        
  388.         public function __clone()
  389.         {
  390.                         if($this instanceOf iCopy)
  391.                                 return $this->copy();
  392.                                
  393.                         if($this instanceOf iLink)
  394.                                 return $this->link();
  395.  
  396.                         throw new \Exception('Not supported');
  397.         }
  398.        
  399.         public static function __set_state(array $__data = [])
  400.         {
  401.             $this->__export = $__data;
  402.            
  403.             $class = get_called_class();
  404.             $object = new $class($__data);
  405.        
  406.             foreach($object as $property => $value)
  407.                 $object->{$property} = $value;
  408.            
  409.             return $object;
  410.         }
  411.        
  412.         /**
  413.          *
  414.          *
  415.          * replace:
  416.          *  $c->extend(['myNewBar' => ['foo' => 'blop']]);
  417.          *  $c->extend(['myNewBar' => ['fob' => 'baz']]);
  418.          *
  419.          *  ["myNewBar"]=>
  420.          *      array(1) {
  421.          *          ["fob"]=>
  422.          *          string(3) "baz"
  423.          *      }
  424.          *
  425.          *
  426.          * extend:
  427.          *  $c->extend(['myNewBar' => ['foo' => 'blop']]);
  428.          *  $c->extend(true, ['myNewBar' => ['fob' => 'baz']]);
  429.          *
  430.          *  ["myNewBar"]=>
  431.          *      array(2) {
  432.          *          ["foo"]=>
  433.          *          string(4) "blop"
  434.          *          ["fob"]=>
  435.          *          string(3) "baz"
  436.          *      }
  437.          *
  438.          * extend multi:
  439.          *  $c->extend(['myNewBar' => ['foo' => 'blop']]);
  440.          *  $c->extend(true, $c, ['myNewBar' => ['fob' => 'baz']], ['myNewBar' => ['bla' => 'baz']]);
  441.          *
  442.          *  ["myNewBar"]=>
  443.          *      array(3) {
  444.          *          ["foo"]=>
  445.          *          string(4) "blop"
  446.          *          ["fob"]=>
  447.          *          string(3) "baz"
  448.          *          ["bla"]=>
  449.          *          string(3) "baz"
  450.          *      }
  451.          *
  452.          * @callable array $__data
  453.          * @callable array $__target, array $__data
  454.          * @callable bool $__recursive, array $__data
  455.          * @callable bool $__recursive, array $__target, array $__data
  456.          * @param mixed
  457.          * @return array|this
  458.          * @note $__target is not a referenced array
  459.          */
  460.         public function extend()
  461.         {
  462.             $args       = func_get_args();
  463.             $tar        = $args[0];
  464.             $i      = 1;
  465.             $length     = count($args);
  466.             $rec        = false;
  467.            
  468.             if($tar === true || $tar === false)
  469.             {
  470.                 $rec = $tar;
  471.                 $tar = isset($args[1]) ? $args[1] : [];
  472.                 $i = 2;
  473.             }
  474.            
  475.             if(!is_array($tar) && !is_object($tar))
  476.                 $tar = [];
  477.                
  478.             if($length === $i)
  479.             {
  480.                 if(FALSE === ($this instanceof \Iterator))
  481.                     throw new \Exception('Unable to iterate throw '.get_called_class());
  482.                
  483.                 $tar = $this;
  484.                 --$i;
  485.             }
  486.            
  487.             for( ; $i < $length; $i++)
  488.             {
  489.                 if(NULL === ($opt = $args[$i]))
  490.                     continue;
  491.                
  492.                 foreach($opt as $key => $value)
  493.                 {
  494.                     if(is_array($tar))
  495.                     {
  496.                         if(TRUE === $rec && is_array($value) && isset($tar[$key]) && is_array($tar[$key]))
  497.                         {
  498.                             $tar[$key] = $this->extend($rec, $tar[$key], $value);
  499.                             continue;
  500.                         }
  501.                        
  502.                         if(is_object($value))
  503.                         {
  504.                             //$tar[$key] = TRUE === $rec ? clone $value : $value;
  505.                             $tar[$key] = $value;
  506.                             continue;
  507.                         }
  508.                        
  509.                         $tar[$key] = $opt[$key];
  510.                         continue;
  511.                     }
  512.                    
  513.                     if(is_object($tar))
  514.                     {
  515.                         if(TRUE === $rec && is_array($value) && isset($tar->$key) && is_array($tar->$key))
  516.                         {
  517.                             $tar->$key = $this->extend($rec, $tar->$key, $value);
  518.                             continue;
  519.                         }
  520.                        
  521.                         if(is_object($value))
  522.                         {
  523.                             //$tar[$key] = TRUE === $rec ? clone $value : $value;
  524.                             $tar->$key = $value;
  525.                             continue;
  526.                         }
  527.                        
  528.                         $tar->$key = $opt[$key];
  529.                         continue;
  530.                     }
  531.                 }
  532.             }
  533.            
  534.             return $tar;
  535.         }
  536.        
  537.         public function __call($__name, array $__parameters = [])
  538.         {
  539.             if(FALSE === $this->Core_Object_tMethod_exists($__name))
  540.                 throw new \Exception(__CLASS__.'::'.$__name.'() is not a function.');
  541.            
  542.             return $this->prototype($__name, $__parameters);
  543.         }
  544.        
  545.         public function to($__format, array $__options = [])
  546.         {
  547.             $__options +=
  548.             [
  549.                 'handlers' => []
  550.             ];
  551.            
  552.             return $this->Core_Object_tTo_emit($__format, [], $__options);
  553.         }
  554.        
  555.         public function toString(array $__options = [])
  556.         {
  557.             return get_called_class();
  558.         }
  559.        
  560.         public function toArray(array $__options = [])
  561.         {
  562.             $result = [];
  563.        
  564.             foreach($this as $property => $value)
  565.             {
  566.                 if(substr($property, 0, 2) === '__')
  567.                     continue;
  568.                    
  569.                 switch(true):
  570.                     case is_array($value):
  571.                     case (!is_object($property)):
  572.                         $result[$property] = $value;
  573.                         break;
  574.                     case (isset($__options['handlers'][$class = get_class($value)])):
  575.                         $result[$property] = $__options['handlers'][$class]($value);
  576.                         break;
  577.                     case (method_exists($property, 'to')):
  578.                         $result[$property] = $value->to('array', $__options);
  579.                         break;
  580.                     case ($vars = get_object_vars($value)):
  581.                         $result[$property] = $vars;
  582.                         break;
  583.                     case (method_exists($value, '__toString')):
  584.                         $result[$property] = (string) $value;
  585.                         break;
  586.                     default:
  587.                         $result[$property] = $value;
  588.                         break;
  589.                 endswitch;
  590.             }
  591.            
  592.             return $result;
  593.         }
  594.     }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement