fruffl icon

not a joke

fruffl | 02/04/13 04:45:52 PM UTC | 0 ⭐ | 271 👁️ | Never ⏰ | []
PHP |

9.79 KB

|

None

|

0 👍

/

0 👎

<?PHP
    NAMESPACE ILLI\Core;
    USE ILLI\Core\Exception;
    USE ILLI\Util\Inflector;
    USE ILLI\Util\String;
    USE ILLI\Core\Proto\I_Boot;
    
    CLASS Proto EXTENDS \ILLI\Core\A_Proto IMPLEMENTS \ILLI\Core\I_Proto
    {
        USE \ILLI\Core\Proto\T_Boot;
        
        private static $__defaultOptions =
        [
            I_Proto::DI_RUN         => TRUE,
            I_Proto::DI_MAIN        => '__main',
            I_Proto::DI_CLASS       => [],
            I_Proto::DI_DELEGATE        => [],
            I_Proto::DI_FILTER      => [],
            I_Proto::DI_METHOD      => [],
            I_Proto::DI_OBSERVER        => [],
            I_Proto::DI_METHOD_PROTO    => [],
            I_Proto::DI_SIGNAL      => [],
            I_Proto::DI_TO  =>
            [
                'string'        => 'toString',
                'array'         => 'toArray'
            ]
        ];
        
        protected $__initConfig = [];
        
        public function __construct(array $__options = [])
        {
            $__boot = 
            [
                I_Proto::PROP_DEFINE_DEFAULTS =>
                [
                    I_Boot::ON_LOOKUP => function(array $c, $n, array $l)
                    {
                        array_walk($l, function($v, $p) use (&$c, $n)
                        {
                            $c[$p] = $this->Core_Proto_T_Boot_handleLookup($p, $n, $c) +
                            [
                                I_Proto::DEFAULT_VALUE => $v
                            ];
                            
                            $value = &$c[$p][I_Proto::DEFAULT_VALUE];
                            
                            if(isset($value)
                            && is_array($value)
                            && is_array($v)
                            && in_array($p, ['class'])) // I_Object namespaces
                                $value = $this->extend(TRUE, $v, $value);
                        });
                        
                        return $c;
                    },
                    I_Boot::ON_INIT => function(array $c)
                    {
                        array_walk($c, function($s, $p)
                        {
                            $this->__initConfig[$p] = $s[I_Proto::DEFAULT_VALUE];
                        });
                        
                        return $c;
                    }
                ],
                I_Proto::PROP_DEFINE_ASP =>
                [
                    I_Boot::ON_LOOKUP => function(array $c, $n, array $l)
                    {
                        $d =
                        [
                            I_Proto::ASP_TYPE_DEF   => [I_Proto::ASP_FN_PRFX_SET, I_Proto::ASP_FN_PRFX_RESTORE],
                            I_Proto::ASP_TYPE_OBJ   => [I_Proto::ASP_FN_PRFX_SET, I_Proto::ASP_FN_PRFX_RESTORE],
                            I_Proto::ASP_TYPE_ARR   => [I_Proto::ASP_FN_PRFX_SET, I_Proto::ASP_FN_PRFX_RESTORE,
                                            I_Proto::ASP_FN_PRFX_ADD, I_Proto::ASP_FN_PRFX_REMOVE, I_Proto::ASP_FN_PRFX_CLEAR],
                        ];
                        
                        array_walk($l, function($v, $p) use (&$c, $n, $d)
                        {
                            if(is_integer($p))
                            {
                                $p = $v;
                                $v = TRUE;
                            }
                            
                            $c[$p] = $this->Core_Proto_T_Boot_handleLookup($p, $n, $c) +
                            [
                                I_Proto::ASP_AVAIL  => $a = is_string($u = is_bool($v)
                                                ? I_Proto::ASP_TYPE_DEF : $v) ? isset($d[$u]) ? $d[$u] : explode('|', $u) : $u,
                                I_Proto::ASP_USE    => !isset($a[0]) ? isset($d[$u]) ? $d[$u][0] : I_Proto::ASP_FN_PRFX_SET : $a[0],
                                I_Proto::ASP_HANDLE => is_string($v) ? TRUE : $v
                            ];
                        });
                        
                        return $c;
                    },
                    I_Boot::ON_COMPLETE => function(array $c)
                    {
                        array_walk($c, function(&$s, $p)
                        {
                            if(FALSE === $s[I_Boot::EXISTS]
                            || FALSE === $s[I_Proto::ASP_HANDLE])
                                return;
                            
                            array_walk($s[I_Proto::ASP_AVAIL], function($a) use (&$s, $p)
                            {
                                $m = String::insert(I_Proto::TPL_ASP_FN_NAME, [
                                    'aspFnPrfx' => Inflector::camelize($a),
                                    'propertyName'  => Inflector::camelize($p)]);
                                
                                $s += [I_Proto::ASP_ACCESS_ALL.$a => $m];
                                $s += [(($e = method_exists($this, $m)) 
                                    ? I_Proto::ASP_ACCESS_ASP : I_Proto::ASP_ACCESS_DIR).$a => ($e ? $m : $p)];
                            });
                        });
                        
                        return $c;
                    }
                ],
                I_Proto::PROP_DEFINE_CONFIGURABLE =>
                [
                    I_Boot::ON_LOOKUP => function(array $c, $n, array $l)
                    {
                        array_walk($l, function($v, $p) use (&$c, $n)
                        {
                            if(is_integer($p))
                            {
                                $p = $v;
                                $v = FALSE;
                            }
                            
                            $c[$p] = $this->Core_Proto_T_Boot_handleLookup($p, $n, $c) +
                            [
                                I_Proto::CONFIG_HANDLE => $v
                            ];
                        });
                        
                        return $c;
                    }
                ]
            ];
            
            $__init = isset($__options[I_Proto::DI_BOOT_INIT]) && is_callable($__options[I_Proto::DI_BOOT_INIT])
                ? function($p, $v) use ($__options)
                {
                    $__options[I_Proto::DI_BOOT_INIT]($p, $v, self::$__Core_Proto_T_Boot_Static[get_called_class()]);
                }
                : function($p, $v)
                {
                    $a = self::$__Core_Proto_T_Boot_Static[get_called_class()][I_Proto::PROP_DEFINE_ASP];
                    
                    if(!isset($a[$p]))
                        return $this->$p = $v;
                    
                    $s = $a[$p];
                    
                    if(FALSE === $s[I_Proto::ASP_HANDLE])
                        return $this->$p = $v;
                    
                    $u = &$s[I_Proto::ASP_USE];
                        
                    if(!isset($u))
                        throw new Exception('The default handle is "set". No handler found.');
                    
                    $d = &$s[I_Proto::ASP_ACCESS_DIR.$u];
                    $m = &$s[I_Proto::ASP_ACCESS_ASP.$u];
                    
                    if(isset($d))
                        return $this->$p = $v;
                        
                    if(isset($m))
                        return $this->$m($v);
                        
                    $m = I_Proto::ASP_ACCESS_ASP.$u;
                    throw new Exception('Setter {:m} not avail.', compact('m'));
                };
            
            $__exec = isset($__options[I_Proto::DI_BOOT_EXEC]) && is_callable($__options[I_Proto::DI_BOOT_EXEC])
                ? function() use ($__init, $__options)
                {
                    $__options[I_Proto::DI_BOOT_EXEC]($__init, self::$__Core_Proto_T_Boot_Static[get_called_class()]);
                    
                    $this->__initConfig[I_Proto::DI_RUN] = TRUE;
                    unset($this->__initConfig[I_Proto::DI_BOOT_EXEC]);
                }
                : function() use ($__init)
                {
                    $_ = self::$__Core_Proto_T_Boot_Static[get_called_class()];
                    $c = $_[I_Proto::PROP_DEFINE_CONFIGURABLE];
                    $d = $_[I_Proto::PROP_DEFINE_DEFAULTS];
                    $i = &$this->__initConfig;
                    $t = [];
            
                    array_walk($d, function($s, $p) use (&$t)
                    {
                        if(FALSE === $s[I_Boot::EXISTS])
                            return;
                            
                        $t[$p] = &$s[I_Proto::DEFAULT_VALUE];
                    });
                    
                    array_walk($c, function($s, $p) use (&$i, &$t)
                    {
                        if(FALSE === isset($i[$p]))
                            return;
                        
                        $value = $i[$p];
                        
                        if(FALSE === $s[I_Boot::EXISTS])
                            return;
                        
                        switch(TRUE):
                            case is_array($value) && is_array($this->$p):
                                switch($s[I_Boot::CONFIG_HANDLE]):
                                    case I_Proto::CONFIG_HANDLE_ARR_ADD:
                                        $value = $this->$p + $value;
                                        break;
                                    case I_Proto::CONFIG_HANDLE_ARR_EXTEND:
                                        $value = $this->extend($this->$p, $value);
                                        break;
                                    case I_Proto::CONFIG_HANDLE_ARR_MERGE:
                                        $value = array_merge($this->$p, $value);
                                        break;
                                    case I_Proto::CONFIG_HANDLE_ARR_RECURSIVE:
                                        $value = $this->extend(TRUE, $this->$p, $value);
                                        break;
                                endswitch;
                                break;
                            case is_string($value) && is_string($this->$p):
                                switch($s[I_Boot::CONFIG_HANDLE]):
                                    case I_Proto::CONFIG_HANDLE_STR_APPEND:
                                        $value = $this->$p.$value;
                                        break;
                                    case I_Proto::CONFIG_HANDLE_STR_PREPEND:
                                        $value = $value.$this->$p;
                                        break;
                                endswitch;
                                break;
                        endswitch;
                        
                        $t[$p] = &$value;
                    });
                    
                    array_walk($t, function(&$v, $p) use (&$i, $__init)
                    {
                        unset($i[$p]);
                        $__init($p, $v);
                    });
                    
                    $this->__initConfig[I_Proto::DI_RUN] = TRUE;
                    unset($this->__initConfig[I_Proto::DI_BOOT_EXEC]);
                };
            
            $this->Core_Proto_T_Boot_emit
            (
                $this->extend(TRUE, (isset($__options[I_Proto::DI_BOOT_LOAD])
                    ? $__options[I_Proto::DI_BOOT_LOAD]
                    : []), $__boot)
            );
            
            unset($__options[I_Proto::DI_BOOT_LOAD]);
            unset($__options[I_Proto::DI_BOOT_EXEC]);
            unset($__options[I_Proto::DI_BOOT_INIT]);
            
            $this->__initConfig = $this->extend(TRUE, $this->__initConfig, self::$__defaultOptions, $__options);
            
            TRUE === $this->__initConfig[I_Proto::DI_RUN]
                ? $__exec()
                : $this->__initConfig[I_Proto::DI_BOOT_EXEC] = $__exec;
            
            unset($__boot);
            unset($__init);
            unset($__exec);
        }
        
        public function run()
        {
            if(isset($this->__initConfig[I_Proto::DI_BOOT_EXEC]))
                $this->__initConfig[I_Proto::DI_BOOT_EXEC]();
                
            return $this;
        }
        
        public function propertySet($property, $value)
        {
            $_ = self::$__Core_Proto_T_Boot_Static[get_called_class()];
            $c = $_[I_Proto::PROP_DEFINE_CONFIGURABLE];
            
            if(!isset($c[$property]))
                throw new Exception('{:property} is not public.', compact('property'));
                
            $this->$property = $value;
            return $this;
        }
        
        public function extend()
        {
            $a = func_get_args();
            $t = $a[0];
            $i = 1;
            $l = count($a);
            $r = FALSE;
            
            if(is_bool($t))
            {
                $r = $t;
                $t = isset($a[1]) ? $a[1] : [];
                $i = 2;
            }
            
            if(FALSE === is_array($t)
            && FALSE === is_object($t)
            && FALSE === is_string($t))
                $t = [];
                
            if($l === $i)
            {
                $t = $this;
                --$i;
            }
            
            for( ; $i < $l; $i++)
            {
                if(NULL === ($o = $a[$i]))
                    continue;
                
                foreach($o as $p => $v)
                {
                    switch(TRUE):
                        case is_array($t):
                            $t[$p] = (TRUE === $r && is_array($v) && isset($t[$p]) && is_array($t[$p]))
                                ? $this->extend($r, $t[$p], $v)
                                : $v;
                            break;
                        case is_object($t):
                            $t->$p = (TRUE === $r && is_array($v) && isset($t->$p) && is_array($t->$p))
                                ? $this->extend($r, $t->$p, $v)
                                : $v;
                            break;
                        case is_string($t):
                            if(FALSE === class_exists($t))
                                throw new Exception('Class {:t} not found.', compact('t'));
                                
                            if(FALSE === property_exists($t, $p))
                                throw new Exception('Property {:t}::${:p} not found.', compact('t', 'p'));
                                
                            $t::$$p = (TRUE === $r && is_array($v) && is_array($t::${$p}))
                                ? $this->extend($r, $t::$$p, $v)
                                : $v;
                            break;
                        default:
                            throw new Exception('Target not writable.');
                    endswitch;
                }
            }
            
            return $t;
        }
        
        public function dump()
        {
            return self::$__Core_Proto_T_Boot_Static;
        }
    }

Comments