<?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