<?PHP
NAMESPACE ILLI\Core\Std\Def;
USE ILLI\Core\Std\Exception\ArgumentExpectedException;
USE ILLI\Core\Std\Def;
USE ILLI\Core\Std\Def\__const_Type;
USE ILLI\Core\Std\Def\ADV;
USE ILLI\Core\Std\Def\ADVArrayKeyValue\ComponentMethodCallException;
USE ILLI\Core\Std\Def\ADVArrayKeyValue\ComponentInitializationException;
USE ILLI\Core\Std\Spl\FsbCollection;
USE ILLI\Core\Util\Spl;
CLASS ADVArrayKeyValue EXTENDS \ILLI\Core\Std\Def\ADV
{
/**
* cache ADT for key and value
*
* :index<long>
* 0 key
* 1 value
*
* :hashAddr<string>
* instance of get_called_class(): ILLI\Core\Std\Def\ADV*
* instance of __CLASS__: ILLI\Core\Std\Def\ADVArrayKeyValue<hash>
*
* :ADT<ILLI\Core\Std\Def\ADT>
* the ADT for {:index}
*
* @var array [{:hashAddr} => ILLI\Core\Std\Spl\FsbCollection[{:index} => ILLI\Core\Std\Spl\FsbCollection[long offset => {:ADT}]]]
*/
private static $__kvgc = NULL;
#:ILLI\Core\Std\Def\ADV:
/**
* Instantiate a new ADVArray with ADT for key and value.
*
* The base-type for this ADV is an array. The difference to ADVArray is an ADT definition for offset-key and -value.
*
* @param string $__defineKeyType {:gcType}
* @param array $__defineKeyType [{:offset} => {:gcType}]
* @param string $__defineValType {:gcType}
* @param array $__defineValType [{:offset} => {:gcType}]
* @param array $__data initial-array
* @catchable ILLI\Core\Std\Def\ADVArrayKeyValue\ComponentInitializationException
* @see ILLI\Core\Std\Def\ADV::__construct()
* @see ILLI\Core\Std\Def::types()
*/
public function __construct($__defineKeyType = NULL, $__defineValType = NULL, $__data = NULL)
{
try
{
parent::__construct([__const_Type::SPL_ARRAY]);
$t = &self::$__kvgc[$this->getName()];
if(FALSE === isset($t))
{
$t = FsbCollection::fromArray([
FsbCollection::fromArray(NULL === $__defineKeyType ? [] : Def::types((array) $__defineKeyType)),
FsbCollection::fromArray(NULL === $__defineValType ? [] : Def::types((array) $__defineValType))]);
}
if(NULL !== $__data)
$this->set($__data);
}
catch(\Exception $E)
{
$c = get_called_class();
$e = $c.'\ComponentInitializationException';
throw ($c === __CLASS__ || FALSE === class_exists($e))
? new ComponentInitializationException($E, ['class' => get_called_class()])
: new $e($E, ['class' => get_called_class()]);
}
}
/**
* Destroy anonymous ATV definitions
*
* @catchable ILLI\Core\Std\Def\ADVArrayKeyValue\ComponentMethodCallException ComponentMethodCallException::ERROR_DTOR
* @void
*/
public function __destruct()
{
try
{
if(($c = get_called_class()) === __CLASS__)
unset(self::$__kvgc[$this->getName()]);
parent::__destruct();
}
catch(\Exception $E)
{
$c = get_called_class();
$e = $c.'\ComponentMethodCallException';
throw ($c === __CLASS__ || FALSE === class_exists($e))
? new ComponentMethodCallException($E, ComponentMethodCallException::ERROR_DTOR, ['method' => __METHOD__])
: new $e($E, $e::ERROR_DTOR, ['method' => __METHOD__]);
}
}
/**
* value-validation, offset-validation
*
* use gc-ADT to validate the value; use kvgc-ADT to validate the offset-name and the offset-value
*
* @param mixed $__value
* @return boolean
* @catchable ILLI\Core\Std\Exception\ADVArrayKeyValue\ComponentMethodCallException
* @see ILLI\Core\Std\Def\ADT::validate()
* @see ILLI\Core\Std\Def\ADV::validate()
*/
public function validate($__value)
{
try
{
if(FALSE === $this->getGC()->evaluate('validate', [$__value]))
return FALSE;
foreach($__value as $k => $v)
{
if(FALSE === $this->validateKey($k))
return FALSE;
if(FALSE === $this->validateVal($v))
return FALSE;
}
return TRUE;
}
catch(\Exception $E)
{
$c = get_called_class();
$e = $c.'\ComponentMethodCallException';
throw ($c === __CLASS__ || FALSE === class_exists($e))
? new ComponentMethodCallException($E, ComponentMethodCallException::ERROR_VALIDATE, ['method' => __METHOD__])
: new $e($E, $e::ERROR_VALIDATE, ['method' => __METHOD__]);
}
}
/**
* store data when value-type equals with gc-ADT, when offset-type equals with kvgc-ADT and when offset-value equals with kvgc-ADT
*
* @param mixed $__value
* @return this
* @throws ILLI\Core\Std\Exception\ArgumentExpectedException on validation-fail
* @catchable ILLI\Core\Std\Exception\ADV\ComponentMethodCallException
* @see ::validate()
*/
public function set($__value)
{
$c = get_called_class();
$e = $c.'\ComponentMethodCallException';
try
{
if(FALSE === parent::validate($__value))
{
$E = new ArgumentExpectedException
([
'target' => get_called_class(),
'expected' => implode('|', array_unique($this->getGC()->invoke('toString'))),
'detected' => $t = getType($v = $__value),
'value' => is_object($v) ? get_class($v) : (is_scalar($v) ? $v : NULL)
]);
throw ($c === __CLASS__ || FALSE === class_exists($e))
? new ComponentMethodCallException($E, ['method' => __METHOD__], ComponentMethodCallException::ERROR_SET_TYPE_EXPECTED)
: new $e($E, ['method' => __METHOD__], $e::ERROR_SET_TYPE_EXPECTED);
}
$i = 0;
foreach($__value as $k => $v)
{
if(FALSE === $this->validateKey($k))
{
$E = new ArgumentExpectedException([
'target' => $this->getName().'['.$i.']',
'expected' => implode('|', array_unique($this->getKeyGC()->invoke('toString'))),
'detected' => $t = getType($k),
'value' => is_object($k) ? get_class($k) : (is_scalar($k) ? $k : NULL)
]);
$a =
[
'offset' => $i,
'class' => get_called_class()
];
throw ($c === __CLASS__ || FALSE === class_exists($e))
? new ComponentMethodCallException($E, $a, ComponentMethodCallException::SET_OFFSET_KEY_TYPE_EXPECTED)
: new $e($E, $a, $e::SET_OFFSET_KEY_TYPE_EXPECTED);
}
if(FALSE === $this->validateVal($v))
{
$E = new ArgumentExpectedException([
'target' => $this->getName().'['.$i.']',
'expected' => implode('|', array_unique($this->getValGC()->invoke('toString'))),
'detected' => $t = getType($v),
'value' => is_object($v) ? get_class($v) : (is_scalar($v) ? $v : NULL)
]);
$a =
[
'offset' => $i,
'class' => get_called_class()
];
throw ($c === __CLASS__ || FALSE === class_exists($e))
? new ComponentMethodCallException($E, $a, ComponentMethodCallException::SET_OFFSET_VAL_TYPE_EXPECTED)
: new $e($E, $a, $e::SET_OFFSET_VAL_TYPE_EXPECTED);
}
$i++;
}
$this->__data = $__value;
return $this;
}
catch(ComponentMethodCallException $E)
{
throw $E;
}
catch(\Exception $E)
{
throw ($c === __CLASS__ || FALSE === class_exists($e))
? new ComponentMethodCallException($E, ComponentMethodCallException::ERROR_SET, ['method' => __METHOD__])
: new $e($E, $e::ERROR_SET, $e::ERROR_SET, ['method' => __METHOD__]);
}
}
protected function createHashAddr(array $__defineTypes = [])
{
try
{
#~ performanced ADT: cache request by called-class; otherwise by hash
return ($c = get_called_class()) === __CLASS__ ? Spl::nameWithHash($c, $this) : $c;
}
catch(\Exception $E)
{
$c = get_called_class();
$e = $c.'\ComponentMethodCallException';
throw ($c === __CLASS__ || FALSE === class_exists($e))
? new ComponentMethodCallException($E, ComponentMethodCallException::ERROR_CREATE_HASH_ADDR, ['method' => __METHOD__])
: new $e($E, $e::ERROR_CREATE_HASH_ADDR, ['method' => __METHOD__]);
}
}
#::
/**
* offset key validation
*
* use kvgc-ADT to validate the offset-name
*
* @param mixed $__value
* @return boolean
* @catchable ILLI\Core\Std\Exception\ADVArrayKeyValue\ComponentMethodCallException
* @see ILLI\Core\Std\Def\ADT::validate()
*/
public function validateKey($__value)
{
try
{
return $this->getKeyGC()->evaluate('validate', [$__value]);
}
catch(\Exception $E)
{
$c = get_called_class();
$e = $c.'\ComponentMethodCallException';
throw ($c === __CLASS__ || FALSE === class_exists($e))
? new ComponentMethodCallException($E, ComponentMethodCallException::ERROR_VALIDATE_OFFSET_KEY, ['method' => __METHOD__])
: new $e($E, $e::ERROR_VALIDATE_OFFSET_KEY, ['method' => __METHOD__]);
}
}
/**
* offset value validation
*
* use kvgc-ADT to validate the offset-value
*
* @param mixed $__value
* @return boolean
* @catchable ILLI\Core\Std\Exception\ADVArrayKeyValue\ComponentMethodCallException
* @see ILLI\Core\Std\Def\ADT::validate()
*/
public function validateVal($__value)
{
try
{
return $this->getValGC()->evaluate('validate', [$__value]);
}
catch(\Exception $E)
{
$c = get_called_class();
$e = $c.'\ComponentMethodCallException';
throw ($c === __CLASS__ || FALSE === class_exists($e))
? new ComponentMethodCallException($E, ComponentMethodCallException::ERROR_VALIDATE_OFFSET_VAL, ['method' => __METHOD__])
: new $e($E, $e::ERROR_VALIDATE_OFFSET_VAL, ['method' => __METHOD__]);
}
}
/**
* get ADT definition for offset-key
*
* @return ILLI\Core\Std\Spl\FsbCollection
* @catchable ILLI\Core\Std\Exception\ADV\ComponentMethodCallException
*/
public function getKeyGC()
{
try
{
return self::$__kvgc[$this->getName()]->offsetGet(0);
}
catch(\Exception $E)
{
$c = get_called_class();
$e = $c.'\ComponentMethodCallException';
throw ($c === __CLASS__ || FALSE === class_exists($e))
? new ComponentMethodCallException($E, ComponentMethodCallException::ERROR_GET_GC_KEY, ['method' => __METHOD__])
: new $e($E, $e::ERROR_GET_GC_KEY, ['method' => __METHOD__]);
}
}
/**
* get ADT definition for offset-value
*
* @return ILLI\Core\Std\Spl\FsbCollection
* @catchable ILLI\Core\Std\Exception\ADV\ComponentMethodCallException
*/
public function getValGC()
{
try
{
return self::$__kvgc[$this->getName()]->offsetGet(1);
}
catch(\Exception $E)
{
$c = get_called_class();
$e = $c.'\ComponentMethodCallException';
throw ($c === __CLASS__ || FALSE === class_exists($e))
? new ComponentMethodCallException($E, ComponentMethodCallException::ERROR_GET_GC_VAL, ['method' => __METHOD__])
: new $e($E, $e::ERROR_GET_GC_VAL, ['method' => __METHOD__]);
}
}
}
Comments