Advertisement
fruffl

Struct for PHP

Aug 28th, 2012
51
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 29.15 KB | None | 0 0
  1. <?PHP
  2.     /**
  3.      * ILLI
  4.      *
  5.      * @category   ILLI_Core
  6.      * @package    ILLI
  7.      * @link       http://illi.be
  8.      * @license    http://l.illi.be
  9.      * @copyright  ILLI Conference
  10.      */
  11.     NAMESPACE ILLI\Core;
  12.     USE Closure;
  13.  
  14.     /**
  15.      * ILLI Memberfield (pseudo Struct)
  16.      *
  17.      * I like structs!
  18.      *
  19.      * tMemberfield allows you to implement a qualified table of private/protected members
  20.      * including trigger-events for set/get.
  21.      *
  22.      * features:
  23.      *  - strict type definition
  24.      *  - you can set an initial value
  25.      *  - reset everytime to initial
  26.      *  - blacklist for scalar values
  27.      *  - whitelist for scalar values
  28.      *  - undo-function/-history
  29.      *  - redo-function/-history
  30.      *  - flag fields as read-only
  31.      *  - flag fields as required
  32.      *  - validate fields
  33.      *  - event-handler for set
  34.      *  - event-handler for get
  35.      *  - lock everything virtual
  36.      *
  37.      *
  38.      * class design is a pseudo-static collection, stored by spl hash per object;
  39.      *
  40.      * note:
  41.      *  - isset() doesn't mean isset()! isset is PHP-gutter politics...
  42.      *      for isset in sense of PHP @see isDefined().
  43.      *
  44.      *  - events: they should not be used as adapters and not to overwrite stored values
  45.      *      converting a registered integer to a non-registered string will throw an exception
  46.      *
  47.      *
  48.      * bitflags are bad for performance, hu?
  49.      *
  50.      *
  51.      * @category   ILLI_Core
  52.      * @package    ILLI
  53.      * @subpackage Core
  54.      * @namespace  ILLI\Core
  55.      * @link       http://illi.be
  56.      * @license    http://l.illi.be
  57.      * @copyright  ILLI Conference
  58.      * @since      2.0.1
  59.      * @version    3.0.1
  60.      *
  61.      * @todo i believe it's useful to fire some exceptions
  62.      * @todo prototype study to create a setter-/getter-class with \ILLI\Core\Dynamic\Spl
  63.      */
  64.     TRAIT tMemberfield
  65.     {
  66.         /**
  67.          * what do whant to see in var_dump()
  68.          * @var int
  69.          * @static
  70.          * @internal
  71.          */
  72.         private static  $__printableFlag            = 0;
  73.        
  74.         /**
  75.          * what do you set
  76.          * @var array
  77.          * @static
  78.          * @internal
  79.          */
  80.         private static  $__tMemberfield_PropContains        = [];
  81.        
  82.         /**
  83.          * strict type definitions
  84.          * @var array
  85.          * @static
  86.          * @internal
  87.          */
  88.         private static  $__tMemberfield_PropAcceptsType     = [];
  89.        
  90.         /**
  91.          * can not overwrite|undo|redo|reset
  92.          * @var array
  93.          * @static
  94.          * @internal
  95.          */
  96.         private static  $__tMemberfield_PropIsLocked        = [];
  97.        
  98.         /**
  99.          * set() was called after initialization
  100.          * @var array
  101.          * @static
  102.          * @internal
  103.          */
  104.         private static  $__tMemberfield_PropIsTouched       = [];
  105.        
  106.         /**
  107.          * fast validate: compares between init- and contains-value; considered stop-handle
  108.          * @var array
  109.          * @static
  110.          * @internal
  111.          */
  112.         private static  $__tMemberfield_PropIsRequired      = [];
  113.        
  114.         /**
  115.          * allows you to switch in __set() between protected and local access
  116.          * @var array
  117.          * @static
  118.          * @internal
  119.          */
  120.         private static  $__tMemberfield_PropPrivateSet      = [];
  121.        
  122.         /**
  123.          * allows you to switch in __get() between protected and local access
  124.          * @var array
  125.          * @static
  126.          * @internal
  127.          */
  128.         private static  $__tMemberfield_PropPrivateGet      = [];
  129.        
  130.         /**
  131.          * stores the initial value (for reset; for comparison)
  132.          * @var array
  133.          * @static
  134.          * @internal
  135.          */
  136.         private static  $__tMemberfield_PropInitializedAs   = [];
  137.        
  138.         /**
  139.          * switch: allowed is only from whitelist (only scalar now)
  140.          * @var array
  141.          * @static
  142.          * @internal
  143.          */
  144.         private static  $__tMemberfield_PropAcceptsValues   = [];
  145.        
  146.         /**
  147.          * switch: forbidden is all in blacklist (only scalar now)
  148.          * @var array
  149.          * @static
  150.          * @internal
  151.          */
  152.         private static  $__tMemberfield_PropForbidsValues   = [];
  153.        
  154.         /**
  155.          * onSet-event
  156.          * @var array
  157.          * @static
  158.          * @internal
  159.          */
  160.         private static  $__tMemberfield_PropOnSetEvent      = [];
  161.        
  162.         /**
  163.          * onGet-event
  164.          * @var array
  165.          * @static
  166.          * @internal
  167.          */
  168.         private static  $__tMemberfield_PropOnGetEvent      = [];
  169.        
  170.         /**
  171.          * counter
  172.          * @var array
  173.          * @static
  174.          * @internal
  175.          */
  176.         private static  $__tMemberfield_PropUndoSteps       = [];
  177.        
  178.         /**
  179.          * last values
  180.          * @var array
  181.          * @static
  182.          * @internal
  183.          */
  184.         private static  $__tMemberfield_PropUndoStack       = [];
  185.        
  186.         /**
  187.          * counter
  188.          * @var array
  189.          * @static
  190.          * @internal
  191.          */
  192.         private static  $__tMemberfield_PropRedoSteps       = [];
  193.        
  194.         /**
  195.          * next values
  196.          * @var array
  197.          * @static
  198.          * @internal
  199.          */
  200.         private static  $__tMemberfield_PropRedoStack       = [];
  201.        
  202.         /**
  203.          * accessor: limitation of visible fields in var_dump(); short hand...
  204.          * @var array property => reference to static prop-tables
  205.          */
  206.         protected   $__tMemberfields            = [];
  207.        
  208.         /**
  209.          * lock registration of new fields
  210.          * @var array
  211.          */
  212.         private     $__tMemberfield_LockRegistration    = FALSE;
  213.        
  214.         /**
  215.          * keep property-lock-state set a lock-wrapper
  216.          * @var array
  217.          */
  218.         private     $__tMemberfield_LockAllFields       = FALSE;
  219.        
  220.         /**
  221.          * spl hash
  222.          * @internal
  223.          */
  224.         private     $__tMemberfield_Hash            = NULL;
  225.        
  226.         /**
  227.          * trait-constructor
  228.          */
  229.         private function tMemberfield_register()
  230.         {
  231.             if(NULL !== $this->__tMemberfield_Hash)
  232.                 return;
  233.                
  234.             $this->__tMemberfield_Hash = spl_object_hash($this);
  235.            
  236.             self::$__tMemberfield_PropContains      [$this->__tMemberfield_Hash] = [];
  237.             self::$__tMemberfield_PropAcceptsType       [$this->__tMemberfield_Hash] = [];
  238.             self::$__tMemberfield_PropIsLocked      [$this->__tMemberfield_Hash] = [];
  239.             self::$__tMemberfield_PropIsTouched     [$this->__tMemberfield_Hash] = [];
  240.             self::$__tMemberfield_PropIsRequired        [$this->__tMemberfield_Hash] = [];
  241.             self::$__tMemberfield_PropPrivateSet        [$this->__tMemberfield_Hash] = [];
  242.             self::$__tMemberfield_PropPrivateGet        [$this->__tMemberfield_Hash] = [];
  243.             self::$__tMemberfield_PropInitializedAs     [$this->__tMemberfield_Hash] = [];
  244.             self::$__tMemberfield_PropAcceptsValues     [$this->__tMemberfield_Hash] = [];
  245.             self::$__tMemberfield_PropForbidsValues     [$this->__tMemberfield_Hash] = [];
  246.             self::$__tMemberfield_PropOnSetEvent        [$this->__tMemberfield_Hash] = [];
  247.             self::$__tMemberfield_PropOnGetEvent        [$this->__tMemberfield_Hash] = [];
  248.             self::$__tMemberfield_PropUndoSteps     [$this->__tMemberfield_Hash] = [];
  249.             self::$__tMemberfield_PropUndoStack     [$this->__tMemberfield_Hash] = [];
  250.             self::$__tMemberfield_PropRedoSteps     [$this->__tMemberfield_Hash] = [];
  251.             self::$__tMemberfield_PropRedoStack     [$this->__tMemberfield_Hash] = [];
  252.         }
  253.        
  254.         /**
  255.          * trait-destructor
  256.          */
  257.         private function tMemberfield_unregister()
  258.         {
  259.             unset(self::$__tMemberfield_PropContains    [$this->__tMemberfield_Hash]);
  260.             unset(self::$__tMemberfield_PropAcceptsType [$this->__tMemberfield_Hash]);
  261.             unset(self::$__tMemberfield_PropIsLocked    [$this->__tMemberfield_Hash]);
  262.             unset(self::$__tMemberfield_PropIsTouched   [$this->__tMemberfield_Hash]);
  263.             unset(self::$__tMemberfield_PropIsRequired  [$this->__tMemberfield_Hash]);
  264.             unset(self::$__tMemberfield_PropPrivateSet  [$this->__tMemberfield_Hash]);
  265.             unset(self::$__tMemberfield_PropPrivateGet  [$this->__tMemberfield_Hash]);
  266.             unset(self::$__tMemberfield_PropInitializedAs   [$this->__tMemberfield_Hash]);
  267.             unset(self::$__tMemberfield_PropAcceptsValues   [$this->__tMemberfield_Hash]);
  268.             unset(self::$__tMemberfield_PropForbidsValues   [$this->__tMemberfield_Hash]);
  269.             unset(self::$__tMemberfield_PropOnSetEvent  [$this->__tMemberfield_Hash]);
  270.             unset(self::$__tMemberfield_PropOnGetEvent  [$this->__tMemberfield_Hash]);
  271.             unset(self::$__tMemberfield_PropUndoSteps   [$this->__tMemberfield_Hash]);
  272.             unset(self::$__tMemberfield_PropUndoStack   [$this->__tMemberfield_Hash]);
  273.             unset(self::$__tMemberfield_PropRedoSteps   [$this->__tMemberfield_Hash]);
  274.             unset(self::$__tMemberfield_PropRedoStack   [$this->__tMemberfield_Hash]);
  275.             unset($this->__tMemberfields);
  276.             unset($this->__tMemberfield_Hash);
  277.             unset($this->__tMemberfield_Locked);
  278.         }
  279.        
  280.         /**
  281.          * register a new memberfield
  282.          *
  283.          * @param string $field name of memberfield
  284.          * @param string $type type-def e. g. integer, array, double or \Exception, \Closure etc
  285.          * @param array $options [
  286.          *      @init       mixed       initial value (not typesafe)
  287.          *      @locked     bool        value is locked and can not changed
  288.          *      @required   bool        its required to touch the value, e. g. config-struct
  289.          *      @private:set    bool   
  290.          *      @private:get    bool   
  291.          *      @types      string|array    type-def
  292.          *      @only       scalar      scalar whitelist for values
  293.          *      @not        scalar      scalar blacklist for values
  294.          *      @get        Closure|array   list of closures: applied by get(); format: closure(['contains', 'initializedAs'])
  295.          *      @set        Closure|array   list of closures: applied by set(); format: closure(['new', 'contains', 'initializedAs'])
  296.          *  ]
  297.          * @param int $__debugFlag control-flag for var_dump()
  298.          */
  299.         protected function tMemberfield_registerProperty($field, $type, array $options = [], $__debugFlag = iMemberfield::DEBUG_CONTAINS)
  300.         {
  301.             $this->tMemberfield_register();
  302.            
  303.             $defaults = [
  304.                 'init'      => NULL,
  305.                 'locked'    => FALSE,
  306.                 'required'  => FALSE,
  307.                 'private:set'   => FALSE,
  308.                 'private:get'   => FALSE,
  309.                 'types'     => (array) $type,
  310.                 'only'      => [],
  311.                 'not'       => [],
  312.                 'get'       => (function(array $data){ return $data; }),
  313.                 'set'       => (function(array $data){ return $data; })
  314.             ];
  315.            
  316.             $options += $defaults;
  317.            
  318.             self::$__tMemberfield_PropIsLocked      [$this->__tMemberfield_Hash][$field] = $options['locked'];
  319.             self::$__tMemberfield_PropIsTouched     [$this->__tMemberfield_Hash][$field] = FALSE;
  320.             self::$__tMemberfield_PropIsRequired        [$this->__tMemberfield_Hash][$field] = $options['required'];
  321.             self::$__tMemberfield_PropContains      [$this->__tMemberfield_Hash][$field] = $options['init'];
  322.             self::$__tMemberfield_PropInitializedAs     [$this->__tMemberfield_Hash][$field] = $options['init'];
  323.             self::$__tMemberfield_PropAcceptsType       [$this->__tMemberfield_Hash][$field] = (array) $options['types'];
  324.             self::$__tMemberfield_PropAcceptsValues     [$this->__tMemberfield_Hash][$field] = (array) $options['only'];
  325.             self::$__tMemberfield_PropForbidsValues     [$this->__tMemberfield_Hash][$field] = (array) $options['not'];
  326.             self::$__tMemberfield_PropOnGetEvent        [$this->__tMemberfield_Hash][$field] = (array) $options['get'];
  327.             self::$__tMemberfield_PropOnSetEvent        [$this->__tMemberfield_Hash][$field] = (array) $options['set'];
  328.             self::$__tMemberfield_PropPrivateSet        [$this->__tMemberfield_Hash][$field] = $options['private:set'];
  329.             self::$__tMemberfield_PropPrivateGet        [$this->__tMemberfield_Hash][$field] = $options['private:get'];
  330.             self::$__tMemberfield_PropUndoSteps     [$this->__tMemberfield_Hash][$field] = 0;
  331.             self::$__tMemberfield_PropRedoSteps     [$this->__tMemberfield_Hash][$field] = 0;
  332.             self::$__tMemberfield_PropUndoStack     [$this->__tMemberfield_Hash][$field] = [];
  333.             self::$__tMemberfield_PropRedoStack     [$this->__tMemberfield_Hash][$field] = [];
  334.            
  335.             // primary to cast isset(array[key]) (instead of array-key-exists), because its ~60% faster;
  336.             // an initialValue of a memberfield in PHP is always null (not void). and we want to know if the key exists - not if its not null
  337.             // the proplem is:
  338.             //  $array[key] = NULL; isset($array[key]) -> FALSE
  339.             //  $array[key] = NULL; array_key_exists(key, $array) -> TRUE (NULL but exists!)
  340.             //
  341.             //
  342.             // solution: create an array into our array[key]... with some references
  343.             // comment in/out what do you want to see in var_dump()
  344.             $this->__tMemberfields[$field] = []; // never delete this line!
  345.            
  346.             if($__debugFlag & iMemberfield::DEBUG_IS_LOCKED)
  347.                 $this->__tMemberfields[$field]['isLocked']  = & self::$__tMemberfield_PropIsLocked      [$this->__tMemberfield_Hash][$field];
  348.             if($__debugFlag & iMemberfield::DEBUG_IS_TOUCHED)
  349.                 $this->__tMemberfields[$field]['isTouched'] = & self::$__tMemberfield_PropIsTouched     [$this->__tMemberfield_Hash][$field];
  350.             if($__debugFlag & iMemberfield::DEBUG_IS_REQUIRED)
  351.                 $this->__tMemberfields[$field]['isRequired']    = & self::$__tMemberfield_PropIsRequired    [$this->__tMemberfield_Hash][$field];
  352.             if($__debugFlag & iMemberfield::DEBUG_CONTAINS)
  353.                 $this->__tMemberfields[$field]['contains']  = & self::$__tMemberfield_PropContains      [$this->__tMemberfield_Hash][$field];
  354.             if($__debugFlag & iMemberfield::DEBUG_INITIALIZED_AS)
  355.                 $this->__tMemberfields[$field]['initializedAs'] = & self::$__tMemberfield_PropInitializedAs [$this->__tMemberfield_Hash][$field];
  356.             if($__debugFlag & iMemberfield::DEBUG_ACCEPTED_TYPES)
  357.                 $this->__tMemberfields[$field]['acceptedTypes'] = & self::$__tMemberfield_PropAcceptsType   [$this->__tMemberfield_Hash][$field];
  358.             if($__debugFlag & iMemberfield::DEBUG_WHITELISTE)
  359.                 $this->__tMemberfields[$field]['allowsOnly']    = & self::$__tMemberfield_PropAcceptsValues [$this->__tMemberfield_Hash][$field];
  360.             if($__debugFlag & iMemberfield::DEBUG_BLACKLIST)
  361.                 $this->__tMemberfields[$field]['allowsNever']   = & self::$__tMemberfield_PropForbidsValues [$this->__tMemberfield_Hash][$field];
  362.             if($__debugFlag & iMemberfield::DEBUG_EVENT_GET)
  363.                 $this->__tMemberfields[$field]['event:get'] = & self::$__tMemberfield_PropOnGetEvent    [$this->__tMemberfield_Hash][$field];
  364.             if($__debugFlag & iMemberfield::DEBUG_EVENT_SET)
  365.                 $this->__tMemberfields[$field]['event:set'] = & self::$__tMemberfield_PropOnSetEvent    [$this->__tMemberfield_Hash][$field];
  366.             if($__debugFlag & iMemberfield::DEBUG_IS_PRIVATE_SET)
  367.                 $this->__tMemberfields[$field]['private:set']   = & self::$__tMemberfield_PropPrivateSet    [$this->__tMemberfield_Hash][$field];
  368.             if($__debugFlag & iMemberfield::DEBUG_IS_PRIVATE_GET)
  369.                 $this->__tMemberfields[$field]['private:get']   = & self::$__tMemberfield_PropPrivateGet    [$this->__tMemberfield_Hash][$field];
  370.             if($__debugFlag & iMemberfield::DEBUG_UNDO_STEPS)
  371.                 $this->__tMemberfields[$field]['undo:steps']    = & self::$__tMemberfield_PropUndoSteps     [$this->__tMemberfield_Hash][$field];
  372.             if($__debugFlag & iMemberfield::DEBUG_UNDO_STACK)
  373.                 $this->__tMemberfields[$field]['undo:stack']    = & self::$__tMemberfield_PropUndoStack     [$this->__tMemberfield_Hash][$field];
  374.             if($__debugFlag & iMemberfield::DEBUG_REDO_STEPS)
  375.                 $this->__tMemberfields[$field]['redo:steps']    = & self::$__tMemberfield_PropRedoSteps     [$this->__tMemberfield_Hash][$field];
  376.             if($__debugFlag & iMemberfield::DEBUG_REDO_STACK)
  377.                 $this->__tMemberfields[$field]['redo:stack']    = & self::$__tMemberfield_PropRedoStack     [$this->__tMemberfield_Hash][$field];
  378.         }
  379.        
  380.         protected function tMemberfield_template__set($key, $value)
  381.         {
  382.             if(FALSE === $this->tMemberfield_isPrivateSet($key))
  383.                 $this->tMemberfield_set($key, $value);
  384.         }
  385.        
  386.         protected function tMemberfield_template__get($key)
  387.         {
  388.             if(FALSE === $this->tMemberfield_isPrivateGet($key))
  389.                 return $this->tMemberfield_get($key);
  390.         }
  391.        
  392.         /**
  393.          * memberfield is registered as { private set; }
  394.          *
  395.          * @param string $field name of memberfield
  396.          * @return bool
  397.          * @see tMemberfield_registerProperty
  398.          */
  399.         protected function tMemberfield_isPrivateSet($field)
  400.         {
  401.             $this->tMemberfield_register();
  402.             if(FALSE === isset($this->__tMemberfields[$field]))
  403.                 return;
  404.                
  405.             return self::$__tMemberfield_PropPrivateSet[$this->__tMemberfield_Hash][$field];
  406.         }
  407.        
  408.         /**
  409.          * memberfield is registered as { private get; }
  410.          *
  411.          * @param string $field name of memberfield
  412.          * @return bool
  413.          * @see tMemberfield_registerProperty
  414.          */
  415.         protected function tMemberfield_isPrivateGet($field)
  416.         {
  417.             $this->tMemberfield_register();
  418.             if(FALSE === isset($this->__tMemberfields[$field]))
  419.                 return;
  420.                
  421.             return self::$__tMemberfield_PropPrivateGet[$this->__tMemberfield_Hash][$field];
  422.         }
  423.        
  424.         /**
  425.          * memberfield is registered as { required to store data }
  426.          *
  427.          * @param string $field name of memberfield
  428.          * @return bool
  429.          * @see tMemberfield_registerProperty
  430.          */
  431.         protected function tMemberfield_isRequired($field)
  432.         {
  433.             $this->tMemberfield_register();
  434.             if(FALSE === isset($this->__tMemberfields[$field]))
  435.                 return;
  436.                
  437.             return self::$__tMemberfield_PropIsRequired[$this->__tMemberfield_Hash][$field];
  438.         }
  439.        
  440.         /**
  441.          * memberfield::set() was called after initialization
  442.          *
  443.          * @param string $field name of memberfield
  444.          * @return bool
  445.          */
  446.         protected function tMemberfield_isTouched($field)
  447.         {
  448.             $this->tMemberfield_register();
  449.             if(FALSE === isset($this->__tMemberfields[$field]))
  450.                 return;
  451.                
  452.             return self::$__tMemberfield_PropIsTouched[$this->__tMemberfield_Hash][$field];
  453.         }
  454.        
  455.         /**
  456.          * compare: current value === initial-value
  457.          *
  458.          * applies stored filters to compare
  459.          *
  460.          * @param string $field name of memberfield
  461.          * @return bool
  462.          */
  463.         protected function tMemberfield_isInitialValue($field)
  464.         {
  465.             $this->tMemberfield_register();
  466.             if(FALSE === isset($this->__tMemberfields[$field]))
  467.                 return;
  468.            
  469.             $contains   = self::$__tMemberfield_PropIsRequired[$this->__tMemberfield_Hash][$field];
  470.             $initializedAs  = self::$__tMemberfield_PropInitializedAs[$this->__tMemberfield_Hash][$field];
  471.                
  472.             return $contains === $initializedAs;
  473.         }
  474.        
  475.         /**
  476.          * memberfield exists (PHP: __isset())
  477.          *
  478.          * @param string $field name of memberfield
  479.          * @return bool
  480.          */
  481.         protected function tMemberfield_isDefined($field)
  482.         {
  483.             $this->tMemberfield_register();
  484.             return isset($this->__tMemberfields[$field]);
  485.         }
  486.        
  487.         /**
  488.          * returns true if field is explicit or virtual locked
  489.          *
  490.          * @param string $field name of memberfield
  491.          * @return bool
  492.          */
  493.         protected function tMemberfield_isFieldLocked($field)
  494.         {
  495.             $this->tMemberfield_register();
  496.             if(FALSE === isset($this->__tMemberfields[$field]))
  497.                 return;
  498.                
  499.             return TRUE === self::$__tMemberfield_PropIsLocked[$this->__tMemberfield_Hash][$field]
  500.                 || TRUE === $this->__tMemberfield_LockAllFields;
  501.         }
  502.        
  503.         /**
  504.          * setter
  505.          *
  506.          * @param string $field name of memberfield
  507.          * @param mixed $value type by field definition
  508.          * @see tMemberfield_registerProperty
  509.          */
  510.         protected function tMemberfield_set($field, $value)
  511.         {
  512.             $this->tMemberfield_register();
  513.            
  514.             if(FALSE === isset($this->__tMemberfields[$field]))
  515.                 return;
  516.                
  517.             if(TRUE === self::$__tMemberfield_PropIsLocked[$this->__tMemberfield_Hash][$field]
  518.             || TRUE === $this->__tMemberfield_LockAllFields)
  519.                 return;
  520.                
  521.             $filtered = $this->tMemberfield_applyFilter
  522.             (
  523.                 self::$__tMemberfield_PropOnSetEvent[$this->__tMemberfield_Hash][$field],
  524.                 [
  525.                     'new'       => $value,
  526.                     'contains'  => self::$__tMemberfield_PropContains[$this->__tMemberfield_Hash][$field],
  527.                     'initializedAs' => self::$__tMemberfield_PropInitializedAs[$this->__tMemberfield_Hash][$field]
  528.                 ]
  529.             );
  530.            
  531.             $new = $filtered['new'];
  532.            
  533.             if(FALSE === $this->tMemberfield_isAcceptable($field, $new))
  534.                 return;
  535.            
  536.             // undo back to initialVualue?
  537.             if(TRUE === self::$__tMemberfield_PropIsTouched[$this->__tMemberfield_Hash][$field]) // yes: delete this or write an option
  538.             {
  539.                 // no
  540.                 self::$__tMemberfield_PropUndoSteps[$this->__tMemberfield_Hash][$field]++;
  541.                 self::$__tMemberfield_PropRedoSteps[$this->__tMemberfield_Hash][$field]     = 0;
  542.                 self::$__tMemberfield_PropRedoStack[$this->__tMemberfield_Hash][$field]     = [];
  543.                 self::$__tMemberfield_PropUndoStack[$this->__tMemberfield_Hash][$field][]
  544.                     = self::$__tMemberfield_PropContains[$this->__tMemberfield_Hash][$field];
  545.             }
  546.            
  547.             self::$__tMemberfield_PropContains[$this->__tMemberfield_Hash][$field]  = $new;
  548.             self::$__tMemberfield_PropIsTouched[$this->__tMemberfield_Hash][$field] = TRUE;
  549.         }
  550.        
  551.         /**
  552.          * getter
  553.          *
  554.          * @param string $field name of memberfield
  555.          * @return mixed type by field definition
  556.          */
  557.         protected function tMemberfield_get($field)
  558.         {
  559.             $this->tMemberfield_register();
  560.             if(FALSE === isset($this->__tMemberfields[$field]))
  561.                 return;
  562.            
  563.             $filtered = $this->tMemberfield_applyFilter
  564.             (
  565.                 self::$__tMemberfield_PropOnGetEvent[$this->__tMemberfield_Hash][$field],
  566.                 [
  567.                     'contains'  => self::$__tMemberfield_PropContains[$this->__tMemberfield_Hash][$field],
  568.                     'initializedAs' => self::$__tMemberfield_PropInitializedAs[$this->__tMemberfield_Hash][$field]
  569.                 ]
  570.             );
  571.            
  572.             $contains = $filtered['contains'];
  573.            
  574.             return $contains;
  575.         }
  576.        
  577.         /**
  578.          * reset the current value to the initial value; deletes undo-/redo-stack
  579.          *
  580.          * @param string $field name of memberfield
  581.          */
  582.         protected function tMemberfield_reset($field)
  583.         {
  584.             $this->tMemberfield_register();
  585.             if(FALSE === isset($this->__tMemberfields[$field]))
  586.                 return;
  587.                
  588.             if(TRUE === self::$__tMemberfield_PropIsLocked[$this->__tMemberfield_Hash][$field]
  589.             || TRUE === $this->__tMemberfield_LockAllFields)
  590.                 return;
  591.                
  592.             self::$__tMemberfield_PropContains[$this->__tMemberfield_Hash][$field]
  593.                 = self::$__tMemberfield_PropInitializedAs[$this->__tMemberfield_Hash][$field];
  594.             self::$__tMemberfield_PropUndoSteps[$this->__tMemberfield_Hash][$field]     = 0;
  595.             self::$__tMemberfield_PropRedoSteps[$this->__tMemberfield_Hash][$field]     = 0;
  596.             self::$__tMemberfield_PropRedoStack[$this->__tMemberfield_Hash][$field]     = [];
  597.             self::$__tMemberfield_PropUndoStack[$this->__tMemberfield_Hash][$field]     = [];
  598.            
  599.             return $this;
  600.         }
  601.        
  602.         /**
  603.          * go one step back (not tested with objects!)
  604.          *
  605.          * @param string $field name of memberfield
  606.          * @beta
  607.          */
  608.         protected function tMemberfield_undo($field)
  609.         {
  610.             $this->tMemberfield_register();
  611.            
  612.             if(FALSE === isset($this->__tMemberfields[$field]))
  613.                 return;
  614.                
  615.             if(TRUE === self::$__tMemberfield_PropIsLocked[$this->__tMemberfield_Hash][$field]
  616.             || TRUE === $this->__tMemberfield_LockAllFields)
  617.                 return;
  618.            
  619.             if(0 === self::$__tMemberfield_PropUndoSteps[$this->__tMemberfield_Hash][$field])
  620.                 return;
  621.                
  622.             self::$__tMemberfield_PropUndoSteps[$this->__tMemberfield_Hash][$field]--;
  623.             self::$__tMemberfield_PropRedoSteps[$this->__tMemberfield_Hash][$field]++;
  624.             self::$__tMemberfield_PropRedoStack[$this->__tMemberfield_Hash][$field][]
  625.                 = self::$__tMemberfield_PropContains[$this->__tMemberfield_Hash][$field];
  626.             self::$__tMemberfield_PropContains[$this->__tMemberfield_Hash][$field]
  627.                 = array_pop(self::$__tMemberfield_PropUndoStack[$this->__tMemberfield_Hash][$field]);
  628.         }
  629.        
  630.         /**
  631.          * forwards one step (not tested with objects!)
  632.          *
  633.          * @param string $field name of memberfield
  634.          * @beta
  635.          */
  636.         protected function tMemberfield_redo($field)
  637.         {
  638.             $this->tMemberfield_register();
  639.             if(FALSE === isset($this->__tMemberfields[$field]))
  640.                 return;
  641.                
  642.             if(TRUE === self::$__tMemberfield_PropIsLocked[$this->__tMemberfield_Hash][$field]
  643.             || TRUE === $this->__tMemberfield_LockAllFields)
  644.                 return;
  645.                
  646.             if(0 === self::$__tMemberfield_PropRedoSteps[$this->__tMemberfield_Hash][$field])
  647.                 return;
  648.                
  649.             self::$__tMemberfield_PropUndoSteps[$this->__tMemberfield_Hash][$field]++;
  650.             self::$__tMemberfield_PropRedoSteps[$this->__tMemberfield_Hash][$field]--;
  651.             self::$__tMemberfield_PropUndoStack[$this->__tMemberfield_Hash][$field][]
  652.                 = self::$__tMemberfield_PropContains[$this->__tMemberfield_Hash][$field];
  653.             self::$__tMemberfield_PropContains[$this->__tMemberfield_Hash][$field]
  654.                 = array_pop(self::$__tMemberfield_PropRedoStack[$this->__tMemberfield_Hash][$field]);
  655.         }
  656.        
  657.         /**
  658.          * change to read-only mode for one field
  659.          *
  660.          * @param string $field name of memberfield
  661.          */
  662.         protected function tMemberfield_lockField($field)
  663.         {
  664.             $this->tMemberfield_register();
  665.             if(FALSE === isset($this->__tMemberfields[$field]))
  666.                 return;
  667.                
  668.             self::$__tMemberfield_PropIsLocked[$this->__tMemberfield_Hash][$field] = TRUE;
  669.             return $this;
  670.         }
  671.        
  672.         /**
  673.          * change to read-only mode for all field
  674.          *
  675.          * @param bool $explicit false: virtual (wrapper); true: all fields will be locked
  676.          */
  677.         protected function tMemberfield_lockAllFields($explicit = FALSE)
  678.         {
  679.             $this->tMemberfield_register();
  680.            
  681.             $this->__tMemberfield_LockAllFields = TRUE;
  682.            
  683.             if(TRUE === $explicit)
  684.                 foreach(self::$__tMemberfield_PropContains[$this->__tMemberfield_Hash] as $field => $data)
  685.                     $this->tMemberfield_lockField($field);
  686.            
  687.             return $this;
  688.         }
  689.        
  690.         /**
  691.          * selct ALL members
  692.          *
  693.          * @param bool $applyGetFilters apply get-filters
  694.          * @return array name => value
  695.          */
  696.         protected function tMemberfield_createFieldValuePair($applyGetFilters = TRUE)
  697.         {
  698.             $this->tMemberfield_register();
  699.            
  700.             $selected = [];
  701.             foreach(self::$__tMemberfield_PropContains[$this->__tMemberfield_Hash] as $field => $data)
  702.                 $selected[$field] = (TRUE === $applyGetFilters)
  703.                     ? $this->tMemberfield_get($field)
  704.                     : $data;
  705.                
  706.             return $selected;
  707.         }
  708.        
  709.         /**
  710.          * select all untouched fields (with initial-value)
  711.          *
  712.          * @param bool $applyGetFilters apply get-filters
  713.          * @return array name => value
  714.          */
  715.         protected function tMemberfield_createUntouchedFieldValuePair($applyGetFilters = TRUE)
  716.         {
  717.             $this->tMemberfield_register();
  718.            
  719.             $selected = [];
  720.             foreach(self::$__tMemberfield_PropContains[$this->__tMemberfield_Hash] as $field => $data)
  721.                 if(FALSE === $this->tMemberfield_isTouched($field))
  722.                     $selected[$field] = (TRUE === $applyGetFilters)
  723.                         ? $this->tMemberfield_get($field)
  724.                         : $data;
  725.                
  726.             return $selected;
  727.         }
  728.        
  729.         /**
  730.          * select all writable fields
  731.          *
  732.          * @param bool $applyGetFilters apply get-filters
  733.          * @return array name => value
  734.          */
  735.         protected function tMemberfield_createUnlockedFieldValuePair($applyGetFilters = TRUE)
  736.         {
  737.             $this->tMemberfield_register();
  738.            
  739.             if(TRUE === $this->__tMemberfield_LockAllFields)
  740.                 return [];
  741.            
  742.             $selected = [];
  743.             foreach(self::$__tMemberfield_PropIsLocked[$this->__tMemberfield_Hash] as $field => $locked)
  744.                 if(FALSE === $locked)
  745.                     $selected[$field] = (TRUE === $applyGetFilters)
  746.                         ? $this->tMemberfield_get($field)
  747.                         : self::$__tMemberfield_PropContains[$this->__tMemberfield_Hash][$field];
  748.                        
  749.             return $selected;
  750.         }
  751.        
  752.         /**
  753.          * create a list of all fields with accepted datatypes
  754.          *
  755.          * @param string $field name of memberfield
  756.          * @return array name => array with types
  757.          */
  758.         protected function tMemberfield_createFieldAcceptsPair()
  759.         {
  760.             $this->tMemberfield_register();
  761.            
  762.             $selected = [];
  763.             foreach(self::$__tMemberfield_PropAcceptsType[$this->__tMemberfield_Hash] as $field => $types)
  764.                 $selected[$field] = $types;
  765.                        
  766.             return $selected;
  767.         }
  768.        
  769.         /**
  770.          * validate required fields by isTouched
  771.          *
  772.          * @param Closure $handleStop action when field is untouched
  773.          */
  774.         protected function tMemberfield_validateFields(Closure $handleStop)
  775.         {
  776.             $this->tMemberfield_register();
  777.            
  778.             foreach(self::$__tMemberfield_PropContains[$this->__tMemberfield_Hash] as $field => $data)
  779.                 if(FALSE === $this->tMemberfield_isTouched($field)
  780.                 && TRUE  === $this->tMemberfield_isRequired($field))
  781.                     $handleStop($field);
  782.                        
  783.             return $this;
  784.         }
  785.        
  786.         /**
  787.          * validate value by datatype(s) and black-/whitelist
  788.          *
  789.          * @param string $field name of memberfield
  790.          * @param mixed $value incoming data
  791.          * @return bool
  792.          */
  793.         protected function tMemberfield_isAcceptable($field, $value)
  794.         {
  795.             $this->tMemberfield_register();
  796.            
  797.             if(FALSE === (bool) $this->__tMemberfields)
  798.                 return FALSE;
  799.            
  800.             $typePassed = FALSE;
  801.             $whitePassed    = FALSE;
  802.             $blackPassed    = FALSE;
  803.            
  804.             // type
  805.             foreach(self::$__tMemberfield_PropAcceptsType[$this->__tMemberfield_Hash][$field] as $type)
  806.             {
  807.                 if(is_object($value))
  808.                 {
  809.                     if(TRUE === ($typePassed = (get_class($value) === $type)))
  810.                         break;
  811.                    
  812.                     if(TRUE === ($typePassed = ($value instanceOf $type)))
  813.                         break;
  814.                    
  815.                     continue;
  816.                 }
  817.                
  818.                 if(TRUE === ($typePassed = ($type === getType($value))))
  819.                     break;
  820.                
  821.             }
  822.            
  823.             // whitelist
  824.             if(FALSE === (bool) self::$__tMemberfield_PropAcceptsValues[$this->__tMemberfield_Hash][$field])
  825.             {
  826.                 $whitePassed = TRUE;
  827.             }
  828.             else
  829.             if(is_object($value) || is_array($value))
  830.             {
  831.                 /**
  832.                  * @todo compare... structure only or strict?
  833.                  */
  834.             }
  835.             else
  836.             {
  837.                 foreach(self::$__tMemberfield_PropAcceptsValues[$this->__tMemberfield_Hash][$field] as $allowed)
  838.                     if(TRUE === ($whitePassed = ($allowed === $value)))
  839.                         break;
  840.             }
  841.            
  842.             // blacklist
  843.             if(FALSE === (bool) self::$__tMemberfield_PropForbidsValues[$this->__tMemberfield_Hash][$field])
  844.             {
  845.                 $blackPassed = TRUE;
  846.             }
  847.             else
  848.             if(is_object($value) || is_array($value))
  849.             {
  850.                 /**
  851.                  * @todo compare... structure only or strict?
  852.                  */
  853.             }
  854.             else
  855.             {
  856.                 foreach(self::$__tMemberfield_PropForbidsValues[$this->__tMemberfield_Hash][$field] as $forbidden)
  857.                     if(TRUE === ($blackPassed = ($forbidden !== $value)))
  858.                         break;
  859.             }
  860.            
  861.            
  862.             return $typePassed && $whitePassed && $blackPassed;
  863.         }
  864.        
  865.         /**
  866.          * apply your registered filters
  867.          *
  868.          * @param array $filterStack array with closures
  869.          * @param array $data the arguments
  870.          * @return array
  871.          * @internal
  872.          */
  873.         private function tMemberfield_applyFilter(array $filterStack, array $data)
  874.         {
  875.             if(sizeOf($data) === 0)
  876.                 return $data;
  877.                
  878.             $passable_args  = ['data' => $data];
  879.            
  880.             foreach($filterStack as $FilterAlias)
  881.             {
  882.                 if(FALSE === ($FilterAlias instanceOf Closure))
  883.                     continue;
  884.                    
  885.                 $passable_args['data'] = $FilterAlias($passable_args['data']);
  886.             }
  887.            
  888.             return $passable_args['data'];
  889.         }
  890.     }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement