public function load()
    {

        $response = $this->call($this->getMethod(), $this->getArgs());
        $this->_list = array();
        $key = $this->getResponseKey();
        foreach ($response[$key] as $value) {

            $this->appendToList($value);
        }

        $this->setLimit($response['pagination']->limit);
        $this->setOffset($response['pagination']->offset);
        $this->setTotal($response['pagination']->total);
    }

public function load ( ) { $ response = $ this -> call ( $ this -> getMethod ( ) , $ this -> getArgs ( ) ) ; $ this -> _list = array ( ) ; $ key = $ this -> getResponseKey ( ) ; foreach ( $ response [ $ key ] as $ value ) { $ this -> appendToList ( $ value ) ; } $ this -> setLimit ( $ response [ 'pagination' ] -> limit ) ; $ this -> setOffset ( $ response [ 'pagination' ] -> offset ) ; $ this -> setTotal ( $ response [ 'pagination' ] -> total ) ; }


protected function setCitiesFromArray($cities = array())
    {
        $this->_cities = array();
        foreach ($cities as $city) {
            $city = new City((array)$city);
            $city->setCountry($this);
            $this->_cities[$city->getCityId()] = $city;
        }
    }

protected function setCitiesFromArray ( $ cities = array ( ) ) { $ this -> _cities = array ( ) ; foreach ( $ cities as $ city ) { $ city = new City ( ( array ) $ city ) ; $ city -> setCountry ( $ this ) ; $ this -> _cities [ $ city -> getCityId ( ) ] = $ city ; } }

method to build City objects from multidimension array
@param array $cities
@return void


protected function setPSTNNetworksFromArray($networks = array())
    {
        $this->_pstnNetworks = array();
        foreach ($networks as $network) {
            $network = new PSTNNetwork((array)$network);
            $network->setCountry($this);
            $this->_pstnNetworks[] = $network;
        }
    }

protected function setPSTNNetworksFromArray ( $ networks = array ( ) ) { $ this -> _pstnNetworks = array ( ) ; foreach ( $ networks as $ network ) { $ network = new PSTNNetwork ( ( array ) $ network ) ; $ network -> setCountry ( $ this ) ; $ this -> _pstnNetworks [ ] = $ network ; } }

method to build PSTNNetwork objects from multidimension array
@param array $networks
@return void


public function loadPSTNNetworks($networkPrefix = NULL)
    {
        if (!$this->getCountryIso()) {
            throw new CountryException("ISO code is undefined");
        }
        if (!$this->_loadedNetworks) {

            $response = $this->call("getdidwwpstnrates", array(
                "country_iso" => $this->getCountryIso(),
                "pstn_prefix" => $networkPrefix
            ));
            $country = reset($response);
            $this->fromArray((array)$country);
            $this->_loadedNetworks = true;
        }
        return $this;
    }

public
function
loadPSTNNetworks
(
$
networkPrefix
=
)
{
if
(
!
$
this
->
getCountryIso
(
)
)
{
throw
new
CountryException
(
"ISO code is undefined"
)
;
}
if
(
!
$
this
->
_loadedNetworks
)
{
$
response
=
$
this
->
call
(
"getdidwwpstnrates"
,
array
(
"country_iso"
=>
$
this
->
getCountryIso
(
)
,
"pstn_prefix"
=>
$
networkPrefix
)
)
;
$
country
=
reset
(
$
response
)
;
$
this
->
fromArray
(
(
array
)
$
country
)
;
$
this
->
_loadedNetworks
=
true
;
}
return
$
this
;
}

method to load pstn networks from API2
@link http://open.didww.com/index.php/2._Get_DIDWW_PSTN_Rates read for details of API method
@param string $networkPrefix
@return \Didww\API2\Country


public function loadCities($prefix = NULL)
    {
        if (!$this->getCountryIso()) {
            throw new CountryException("ISO code is undefined");
        }

        if (!$this->_loadedCities) {
            $response = $this->call("getdidwwregions", array(
                "country_iso" => $this->getCountryIso(),
                "city_prefix" => $prefix
            ));

            $country = reset($response);
            $this->fromArray((array)$country);
            $this->_loadedCities = true;
        }
        return $this;
    }

public
function
loadCities
(
$
prefix
=
)
{
if
(
!
$
this
->
getCountryIso
(
)
)
{
throw
new
CountryException
(
"ISO code is undefined"
)
;
}
if
(
!
$
this
->
_loadedCities
)
{
$
response
=
$
this
->
call
(
"getdidwwregions"
,
array
(
"country_iso"
=>
$
this
->
getCountryIso
(
)
,
"city_prefix"
=>
$
prefix
)
)
;
$
country
=
reset
(
$
response
)
;
$
this
->
fromArray
(
(
array
)
$
country
)
;
$
this
->
_loadedCities
=
true
;
}
return
$
this
;
}

method load cities from API2
@link http://open.didww.com/index.php/1._Get_DIDWW_Regions} read for details of API method
@param string $prefix
@return \Didww\API2\Country


public static function getAll($iso = NULL)
    {
        $countries = array();
        $response = self::getClientInstance()->call("getdidwwcountries", array('country_iso' => $iso)
        );
        foreach ($response as $c) {
            $country = new Country((array)$c);
            $countries[$country->getCountryIso()] = $country;
        }
        return $countries;
    }

public static function getAll ( $ iso = NULL ) { $ countries = array ( ) ; $ response = self :: getClientInstance ( ) -> call ( "getdidwwcountries" , array ( 'country_iso' => $ iso ) ) ; foreach ( $ response as $ c ) { $ country = new Country ( ( array ) $ c ) ; $ countries [ $ country -> getCountryIso ( ) ] = $ country ; } return $ countries ; }

Method to get regions from DIDWW API

@link http://open.didww.com/index.php/1._Get_DIDWW_Regions} read for details of API method
@param string $iso if isset, returns only this country
@return \Didww\API2\Country[]


public function getCity($id)
    {
        $this->loadCities();
        if (isset($this->_cities[$id])) {
            return $this->_cities[$id];
        }
        throw new CountryException("City not found");
    }

public
function
getCity
(
$
id
)
{
$
this
->
loadCities
(
)
;
if
(
isset
(
$
this
->
_cities
[
$
id
]
)
)
{
return
$
this
->
_cities
[
$
id
]
;
}
throw
new
CountryException
(
"City not found"
)
;
}

method get city by id
@param int $id
@return \Didww\API2\City
@throws CountryException


private function pkcs5_pad($text, $blocksize)
    {
        $pad = $blocksize - (strlen($text) % $blocksize);
        return $text . str_repeat(chr($pad), $pad);
    }

private function pkcs5_pad ( $ text , $ blocksize ) { $ pad = $ blocksize - ( strlen ( $ text ) % $ blocksize ) ; return $ text . str_repeat ( chr ( $ pad ) , $ pad ) ; }

Fix of encryption
@param $text
@param $blocksize
@return string


public static function getAll($lastRequestGmt = NULL)
    {
        $countries = array();
        $response = self::getClientInstance()->call("getdidwwpstnrates",
            array('last_request_gmt' => $lastRequestGmt)
        );

        foreach ($response as $countryWithNetworks) {

            $countries[trim($countryWithNetworks->country_iso)] = new \Didww\API2\Country((array)$countryWithNetworks);
        }
        return $countries;
    }

public static function getAll ( $ lastRequestGmt = NULL ) { $ countries = array ( ) ; $ response = self :: getClientInstance ( ) -> call ( "getdidwwpstnrates" , array ( 'last_request_gmt' => $ lastRequestGmt ) ) ; foreach ( $ response as $ countryWithNetworks ) { $ countries [ trim ( $ countryWithNetworks -> country_iso ) ] = new \ Didww \ API2 \ Country ( ( array ) $ countryWithNetworks ) ; } return $ countries ; }

get collection of pstn rates
@link http://open.didww.com/index.php/2._Get_DIDWW_PSTN_Rates
@param string $lastRequestGmt
@return \Didww\API2\Countries[]


public static function updateAll($countries = array())
    {
        $networks = array();
        foreach ($countries as $country) {
            if ($country instanceof \Didww\API2\Country) {
                $networks = array_merge($networks, $country->getPSTNNetworks());
            } else {
                throw  new PSTNNetworkException("Country expected but type " .
                    \Didww\Utils\Util::getType($country) .
                    " found");
            }
        }
        self::updateNetworks($networks);
    }

public
static
function
updateAll
(
$
countries
=
array
(
)
)
{
$
networks
=
array
(
)
;
foreach
(
$
countries
as
$
country
)
{
if
(
$
country
instanceof
\
Didww
\
API2
\
Country
)
{
$
networks
=
array_merge
(
$
networks
,
$
country
->
getPSTNNetworks
(
)
)
;
}
else
{
throw
new
PSTNNetworkException
(
"Country expected but type "
.
\
Didww
\
Utils
\
Util
::
getType
(
$
country
)
.
" found"
)
;
}
}
self
::
updateNetworks
(
$
networks
)
;
}

update pstn rates from countries collection
@link http://open.didww.com/index.php/3._Update_PSTN_Rates
@param \Didww\API2\Countries[] $countries


public static function updateNetworks($networks = array())
    {
        $request = array();

        foreach ($networks as $network) {
            if ($network instanceof \Didww\API2\PSTNNetwork) {

                $request[] = array(
                    "network_prefix" => trim($network->getNetworkPrefix()),
                    "sell_rate" => $network->getSellRate()
                );

            } else {
                throw  new PSTNNetworkException("PSTNNetwork expected but type " .
                    \Didww\Utils\Util::getType($network) .
                    " found");
            }
        }

        self::updateNetworksFromArray($request);
    }

public
static
function
updateNetworks
(
$
networks
=
array
(
)
)
{
$
request
=
array
(
)
;
foreach
(
$
networks
as
$
network
)
{
if
(
$
network
instanceof
\
Didww
\
API2
\
PSTNNetwork
)
{
$
request
[
]
=
array
(
"network_prefix"
=>
trim
(
$
network
->
getNetworkPrefix
(
)
)
,
"sell_rate"
=>
$
network
->
getSellRate
(
)
)
;
}
else
{
throw
new
PSTNNetworkException
(
"PSTNNetwork expected but type "
.
\
Didww
\
Utils
\
Util
::
getType
(
$
network
)
.
" found"
)
;
}
}
self
::
updateNetworksFromArray
(
$
request
)
;
}

update pstn rates from pstnnetworks collection
@link http://open.didww.com/index.php/3._Update_PSTN_Rates
@param \Didww\API2\PSTNNetwork[] $networks


public static function create($params = array())
    {
        if (isset($params['type'])) {
            $className = "Didww\API2\Mapping\\" . $params['type'];
            $mapping = new $className();
            unset($params['type']);
        } else {
            $mapping = new Mapping();
        }
        $mapping->fromArray($params);

        return $mapping;
    }

public static function create ( $ params = array ( ) ) { if ( isset ( $ params [ 'type' ] ) ) { $ className = "Didww\API2\Mapping\\" . $ params [ 'type' ] ; $ mapping = new $ className ( ) ; unset ( $ params [ 'type' ] ) ; } else { $ mapping = new Mapping ( ) ; } $ mapping -> fromArray ( $ params ) ; return $ mapping ; }

factory to build mapping object by params array
@param array $params array of key=>value properties
@return Mapping


public function decodeDelay()
    {
        if ($this->graphicsControlExtension) {
            $byte = substr($this->graphicsControlExtension, 2, 2);
            return (int) unpack('v', $byte)[1];
        }

        return false;
    }

public function decodeDelay ( ) { if ( $ this -> graphicsControlExtension ) { $ byte = substr ( $ this -> graphicsControlExtension , 2 , 2 ) ; return ( int ) unpack ( 'v' , $ byte ) [ 1 ] ; } return false ; }

Returns delay of current instance

@return int


public function hasTransparentColor()
    {
        if ($this->graphicsControlExtension) {
            $byte = substr($this->graphicsControlExtension, 1, 1);
            $byte = unpack('C', $byte)[1];
            $bit = $byte & bindec('00000001');

            return (bool) $bit;
        }

        return false;
    }

public function hasTransparentColor ( ) { if ( $ this -> graphicsControlExtension ) { $ byte = substr ( $ this -> graphicsControlExtension , 1 , 1 ) ; $ byte = unpack ( 'C' , $ byte ) [ 1 ] ; $ bit = $ byte & bindec ( '00000001' ) ; return ( bool ) $ bit ; } return false ; }

Determines if instance has transparent colors

@return boolean


public function decodeDisposalMethod()
    {
        if ($this->graphicsControlExtension) {
            $byte = substr($this->graphicsControlExtension, 1, 1);
            $byte = unpack('C', $byte)[1];
            $method = $byte >> 2 & bindec('00000111');

            return $method;
        }

        return 0;
    }

public function decodeDisposalMethod ( ) { if ( $ this -> graphicsControlExtension ) { $ byte = substr ( $ this -> graphicsControlExtension , 1 , 1 ) ; $ byte = unpack ( 'C' , $ byte ) [ 1 ] ; $ method = $ byte >> 2 & bindec ( '00000111' ) ; return $ method ; } return 0 ; }

Decodes disposal method of frame

@return integer


public function getSize()
    {
        $size = new \StdClass;
        $size->width = $this->decodeWidth();
        $size->height = $this->decodeHeight();

        return $size;
    }

public function getSize ( ) { $ size = new \ StdClass ; $ size -> width = $ this -> decodeWidth ( ) ; $ size -> height = $ this -> decodeHeight ( ) ; return $ size ; }

Decodes width and height of frame to size object

@return StdClass


public function getOffset()
    {
        $offset = new \StdClass;
        $offset->left = $this->decodeOffsetLeft();
        $offset->top = $this->decodeOffsetTop();

        return $offset;
    }

public function getOffset ( ) { $ offset = new \ StdClass ; $ offset -> left = $ this -> decodeOffsetLeft ( ) ; $ offset -> top = $ this -> decodeOffsetTop ( ) ; return $ offset ; }

Decodes offsets into object

@return StdClass


public function setOffset($left, $top)
    {
        $offset = new \StdClass;
        $offset->left = $left;
        $offset->top = $top;
        $this->offset = $offset;

        return $this;
    }

public function setOffset ( $ left , $ top ) { $ offset = new \ StdClass ; $ offset -> left = $ left ; $ offset -> top = $ top ; $ this -> offset = $ offset ; return $ this ; }

Sets frame offset

@param integer $left
@param integer $top


public function getCountry()
    {
        if (!($this->_country instanceof Country)) {
            $this->_country = new Country();
            $this->_country->setCountryIso($this->getCountryIso());
        }
        return $this->_country;
    }

public function getCountry ( ) { if ( ! ( $ this -> _country instanceof Country ) ) { $ this -> _country = new Country ( ) ; $ this -> _country -> setCountryIso ( $ this -> getCountryIso ( ) ) ; } return $ this -> _country ; }


public function toArray($options = array())
    {

        $includeNumber = true;
        if (isset($options['includeNumber'])) {
            $includeNumber = (bool)$options['includeNumber'];
            unset($options['includeNumber']);
        }

        return array_merge(parent::toArray($options), $includeNumber ? $this->_ensureNumber()->toArray() : array());
    }

public function toArray ( $ options = array ( ) ) { $ includeNumber = true ; if ( isset ( $ options [ 'includeNumber' ] ) ) { $ includeNumber = ( bool ) $ options [ 'includeNumber' ] ; unset ( $ options [ 'includeNumber' ] ) ; } return array_merge ( parent :: toArray ( $ options ) , $ includeNumber ? $ this -> _ensureNumber ( ) -> toArray ( ) : array ( ) ) ; }

get object state as array
@see parent::toArray()
@param array $options
@return array


public function  fromFlatList($array)
    {
        //try to load order properties
        $assignType = $this->getAssignType();
        $this->setAssignType(\Didww\API2\Object::ASSIGN_IGNORE);
        $array = parent::fromArray($array);
        $this->setAssignType($assignType);

        //try to load number properties
        $number = $this->_ensureNumber();
        $assignType = $number->getAssignType();
        $number->setAssignType(\Didww\API2\Object::ASSIGN_IGNORE);
        $array = $number->fromArray($array);
        $number->setAssignType($assignType);

        //finally create mapping object
        $mapping = Mapping::create($array);

        $this->setMapData($mapping);
    }

public
function
fromFlatList
(
$
array
)
{
//try to load order properties
$
assignType
=
$
this
->
getAssignType
(
)
;
$
this
->
setAssignType
(
\
Didww
\
API2
\
Object
::
ASSIGN_IGNORE
)
;
$
array
=
parent
::
fromArray
(
$
array
)
;
$
this
->
setAssignType
(
$
assignType
)
;
//try to load number properties
$
number
=
$
this
->
_ensureNumber
(
)
;
$
assignType
=
$
number
->
getAssignType
(
)
;
$
number
->
setAssignType
(
\
Didww
\
API2
\
Object
::
ASSIGN_IGNORE
)
;
$
array
=
$
number
->
fromArray
(
$
array
)
;
$
number
->
setAssignType
(
$
assignType
)
;
//finally create mapping object
$
mapping
=
Mapping
::
create
(
$
array
)
;
$
this
->
setMapData
(
$
mapping
)
;
}

create object from flat array
@see parent::fromList()
@param array $array


public function fromArray($array)
    {

        if (!empty($array['number'])) {
            $this->_ensureNumber()->fromArray($array['number']);
            unset($array['number']);
        }

        if (!empty($array['map_data'])) {
            $this->setMapData(Mapping::create($array['map_data']));
            unset($array['map_data']);
        }

        parent::fromArray($array);
    }

public function fromArray ( $ array ) { if ( ! empty ( $ array [ 'number' ] ) ) { $ this -> _ensureNumber ( ) -> fromArray ( $ array [ 'number' ] ) ; unset ( $ array [ 'number' ] ) ; } if ( ! empty ( $ array [ 'map_data' ] ) ) { $ this -> setMapData ( Mapping :: create ( $ array [ 'map_data' ] ) ) ; unset ( $ array [ 'map_data' ] ) ; } parent :: fromArray ( $ array ) ; }

create object from  array
@see parent::fromArray
@param array $array


function createNumber()
    {
        if (!($this->getNumber() instanceof DIDNumber) || !$this->getNumber()->getDIDNumber()) {
            $tmpHash = false;
            if (!$this->uniqHash) {
                $tmpHash = true;
                $this->uniqHash = $this->generateUniqueHash();
            }
            $this->_number = DIDNumber::create($this);

            if ($tmpHash) {
                $this->uniqHash = NULL;
            }
        }
        return $this;
    }

function createNumber ( ) { if ( ! ( $ this -> getNumber ( ) instanceof DIDNumber ) || ! $ this -> getNumber ( ) -> getDIDNumber ( ) ) { $ tmpHash = false ; if ( ! $ this -> uniqHash ) { $ tmpHash = true ; $ this -> uniqHash = $ this -> generateUniqueHash ( ) ; } $ this -> _number = DIDNumber :: create ( $ this ) ; if ( $ tmpHash ) { $ this -> uniqHash = NULL ; } } return $ this ; }

create DIDNumber using DIDWW API2
@return Order


public function generateUniqueHash()
    {
        return md5(sprintf("%s.%s.%s.%s.%s.%s.%s",
            $this->getCustomerId(),
            $this->getCountryIso(),
            $this->getCityId(),
            $this->getCityPrefix(),
            $this->getMapData()->getMapDetail(),
            $this->getAutorenewEnable(),
            date("YmdHis")
        ));
    }

public function generateUniqueHash ( ) { return md5 ( sprintf ( "%s.%s.%s.%s.%s.%s.%s" , $ this -> getCustomerId ( ) , $ this -> getCountryIso ( ) , $ this -> getCityId ( ) , $ this -> getCityPrefix ( ) , $ this -> getMapData ( ) -> getMapDetail ( ) , $ this -> getAutorenewEnable ( ) , date ( "YmdHis" ) ) ) ; }

generte uniqueHash for order create API call
@return string


protected function generateAuthString()
    {
        if (empty($this->password) || empty($this->userName)) {
            throw new ApiCredentialsException(" Undefined userName and/or password ");
        }

        $this->authString = $this->getTestMode() ? sha1($this->userName . $this->password . 'sandbox') : sha1($this->userName . $this->password);
    }

protected
function
generateAuthString
(
)
{
if
(
empty
(
$
this
->
password
)
||
empty
(
$
this
->
userName
)
)
{
throw
new
ApiCredentialsException
(
" Undefined userName and/or password "
)
;
}
$
this
->
authString
=
$
this
->
getTestMode
(
)
sha1
(
$
this
->
userName
.
$
this
->
password
.
'sandbox'
)
:
sha1
(
$
this
->
userName
.
$
this
->
password
)
;
}

method to generate authString property from userName and password properties
@throws ApiCredentialsException
@see http://open.didww.com/index.php/Authentication_Key


public function load()
    {
        $response = $this->call('callhistory_invoices', array(
            'customer_id' => $this->getCustomerId(),
            'from_date' => $this->getFromDate(),
            'to_date' => $this->getToDate()
        ));
        $this->fromArray($response);
        return $this;
    }

public function load ( ) { $ response = $ this -> call ( 'callhistory_invoices' , array ( 'customer_id' => $ this -> getCustomerId ( ) , 'from_date' => $ this -> getFromDate ( ) , 'to_date' => $ this -> getToDate ( ) ) ) ; $ this -> fromArray ( $ response ) ; return $ this ; }

load amount from API2
@return \Didww\API2\CDRInvoice


public function call($method, $arguments = array())
    {
        $arguments = array_merge(array('auth_string' => self::getCredentials()->getAuthString()), $arguments);
        $method = 'didww_' . $method;
        $timeStart = microtime(true);

        try {
            $result = $this->_client->__soapCall($method, $arguments);

        } catch (\Exception $e) {
            if (self::$_debug) {
                $this->debug("raw request", $this->_client->__getLastRequest());
                $this->debug("raw response", $this->_client->__getLastResponse());
            }
            throw $e;
        }

        if (self::$_debug) {
            $this->debug("raw request", $this->_client->__getLastRequest());
            $this->debug("raw response", $this->_client->__getLastResponse());
        }

        /**
         * check if api returned error and throw exception
         */
        if (isset($result->error) && $result->error > 0) {
            $message = isset (self::$_errorCodes[$result->error]) ? self::$_errorCodes[$result->error] :
                'Unknown error with code : ' . $result->error;
            throw new ApiClientException($message);
        }

        $timeFinish = microtime(true);
        $this->time = $timeFinish - $timeStart;
        if (self::$_debug) {
            $this->debug("response from $method:", $result);
        }

        return (array)$result;
    }

method to call didww api 2 soap method
@param string $method
@param array $arguments
@return mixed
@throws ApiClientException


public function getFrame($index = 0)
    {
        if (array_key_exists($index, $this->frames)) {
            return $this->frames[$index];
        }

        throw new RuntimeException(
            "Frame with index ({$index}) does not exists."
        );
    }

Returns particular frame

@param  integer $index
@return \Intervention\Image\Gd\Gif\Frame


public function addOffset($left, $top)
    {
        $offset = new \StdClass;
        $offset->left = $left;
        $offset->top = $top;

        $this->addToFirstFrameWithoutProperty($offset, 'offset');
    }

public function addOffset ( $ left , $ top ) { $ offset = new \ StdClass ; $ offset -> left = $ left ; $ offset -> top = $ top ; $ this -> addToFirstFrameWithoutProperty ( $ offset , 'offset' ) ; }

Adds offset to first frame without offset

@param integer $left
@param integer $top


public function addSize($width, $height)
    {
        $size = new \StdClass;
        $size->width = $width;
        $size->height = $height;

        $this->addToFirstFrameWithoutProperty($size, 'size');
    }

public function addSize ( $ width , $ height ) { $ size = new \ StdClass ; $ size -> width = $ width ; $ size -> height = $ height ; $ this -> addToFirstFrameWithoutProperty ( $ size , 'size' ) ; }

Adds size to first frame without size

@param integer $width
@param integer $height


public function getLoops()
    {
        if ($this->netscapeExtension) {
            $loops = substr($this->netscapeExtension, 14, 2);
            $loops = unpack('C', $loops)[1];

            return $loops;
        }

        return null;
    }

public function getLoops ( ) { if ( $ this -> netscapeExtension ) { $ loops = substr ( $ this -> netscapeExtension , 14 , 2 ) ; $ loops = unpack ( 'C' , $ loops ) [ 1 ] ; return $ loops ; } return null ; }

Returns loops of animation

@return integer|null


public function hasGlobalColorTable()
    {
        $byte = substr($this->logicalScreenDescriptor, 4, 1);

        if (strlen($byte) == 1) {
            $byte = unpack('C', $byte)[1];
            $bit = $byte & bindec('10000000');
        }

        return isset($bit) ? (bool) $bit : false;
    }

public function hasGlobalColorTable ( ) { $ byte = substr ( $ this -> logicalScreenDescriptor , 4 , 1 ) ; if ( strlen ( $ byte ) == 1 ) { $ byte = unpack ( 'C' , $ byte ) [ 1 ] ; $ bit = $ byte & bindec ( '10000000' ) ; } return isset ( $ bit ) ? ( bool ) $ bit : false ; }

Determines if image has global color table

@return boolean


public function countGlobalColors()
    {
        $byte = substr($this->logicalScreenDescriptor, 4, 1);

        if (strlen($byte) == 1) {
            $byte = unpack('C', $byte)[1];
            $bit = $byte & bindec('00000111');
        }

        // length of the global color table is 2^(N+1)
        return isset($bit) ? pow(2, $bit + 1) : 0;
    }

Get number colors in global color palette

@return int


public function getBackgroundColorIndex()
    {
        if ($this->logicalScreenDescriptor) {
            $index = substr($this->logicalScreenDescriptor, 5, 1);
            $index = unpack('C', $index)[1];

            return $index;
        }

        return 0;
    }

public function getBackgroundColorIndex ( ) { if ( $ this -> logicalScreenDescriptor ) { $ index = substr ( $ this -> logicalScreenDescriptor , 5 , 1 ) ; $ index = unpack ( 'C' , $ index ) [ 1 ] ; return $ index ; } return 0 ; }

Returns background color index

@return integer


private function addToFirstFrameWithoutProperty($value, $property)
    {
        $added = false;

        foreach ($this->frames as $key => $frame) {
            if ( ! $frame->propertyIsSet($property)) {
                $frame->setProperty($property, $value);
                $added = true;
                break;
            }
        }

        if ( ! $added) {
            $this->newFrameWithProperty($property, $value);
        }

        return $added;
    }

private function addToFirstFrameWithoutProperty ( $ value , $ property ) { $ added = false ; foreach ( $ this -> frames as $ key => $ frame ) { if ( ! $ frame -> propertyIsSet ( $ property ) ) { $ frame -> setProperty ( $ property , $ value ) ; $ added = true ; break ; } } if ( ! $ added ) { $ this -> newFrameWithProperty ( $ property , $ value ) ; } return $ added ; }

Adds value to first frame without this particular value

@param mixed $value
@param mixed $property


private function newFrameWithProperty($property, $value)
    {
        $frame = new Frame;
        $this->frames[] = $frame->setProperty($property, $value);
    }

private function newFrameWithProperty ( $ property , $ value ) { $ frame = new Frame ; $ this -> frames [ ] = $ frame -> setProperty ( $ property , $ value ) ; }

Adds new frame with given property

@param  mixed $property
@param  mixed $value
@return void


public function toArray($options = array())
    {
        $result = array();
        foreach (get_object_vars($this) as $key => $value) {
            if ($key[0] == '_') {
                continue;
            }
            if ($value instanceof Object) {
                $value = $value->toArray($options);
            }
            $result[\Didww\Utils\StringUtil::snakeCase($key)] = $value;
        }
        return $result;
    }

public function toArray ( $ options = array ( ) ) { $ result = array ( ) ; foreach ( get_object_vars ( $ this ) as $ key => $ value ) { if ( $ key [ 0 ] == '_' ) { continue ; } if ( $ value instanceof Object ) { $ value = $ value -> toArray ( $ options ) ; } $ result [ \ Didww \ Utils \ StringUtil :: snakeCase ( $ key ) ] = $ value ; } return $ result ; }

convert object to array with snaked keys
@param array $options
@return array


protected static function _getAllBalances()
    {
        $result = self::getClientInstance()->call('getprepaidbalancelist', array(
            "customer_id" => '0'
        ));
        $resellerSubAccount = (object)array('customer_id' => '0', 'prepaid_balance_amount' => '0.0000'); // 0 - is reseller's sub account
        array_unshift($result, $resellerSubAccount);
        return $result;
    }

protected
static
function
_getAllBalances
(
)
{
$
result
=
self
::
getClientInstance
(
)
->
call
(
'getprepaidbalancelist'
,
array
(
"customer_id"
=>
'0'
)
)
;
$
resellerSubAccount
=
(
object
)
array
(
'customer_id'
=>
'0'
,
'prepaid_balance_amount'
=>
'0.0000'
)
;
// 0 - is reseller's sub account
array_unshift
(
$
result
,
$
resellerSubAccount
)
;
return
$
result
;
}

method to return list of all balances from API
@return array


public static function getBalanceArray()
    {
        $balances = array();
        foreach (self::_getAllBalances() as $value) {
            $balances[$value->customer_id] = $value->prepaid_balance_amount;
        }
        return $balances;
    }

public static function getBalanceArray ( ) { $ balances = array ( ) ; foreach ( self :: _getAllBalances ( ) as $ value ) { $ balances [ $ value -> customer_id ] = $ value -> prepaid_balance_amount ; } return $ balances ; }

method to return list of all balances indexed by customer id
@link http://open.didww.com/index.php/16._Get_Prepaid_Balance_List
@todo change name to getArray
@return array


public static function getBalanceList()
    {
        $balances = array();
        foreach (self::_getAllBalances() as $value) {
            $value = (array)$value;
            unset($value['result']);
            unset($value['error']);
            $balance = new Balance(array("prepaid_balance" => $value['prepaid_balance_amount'], "customer_id" => $value["customer_id"]));
            $balances[$value['customer_id']] = $balance;
        }
        return $balances;
    }

public static function getBalanceList ( ) { $ balances = array ( ) ; foreach ( self :: _getAllBalances ( ) as $ value ) { $ value = ( array ) $ value ; unset ( $ value [ 'result' ] ) ; unset ( $ value [ 'error' ] ) ; $ balance = new Balance ( array ( "prepaid_balance" => $ value [ 'prepaid_balance_amount' ] , "customer_id" => $ value [ "customer_id" ] ) ) ; $ balances [ $ value [ 'customer_id' ] ] = $ balance ; } return $ balances ; }

method to return list of DidwwBalance objects from API
@link http://open.didww.com/index.php/16._Get_Prepaid_Balance_List
@todo change name to getList
@return array


function changeBalance($funds, $transactionId = NULL)
    {
        if (!$this->getCustomerId() > 0) {
            throw new BalanceException("Customer is invalid");
        }

        if (!(is_numeric($funds))) {
            throw new BalanceException("Funds value is invalid");
        }

        $this->_funds = $funds;
        $this->_transactionId = ($transactionId ? $transactionId : $this->generateTransactionId());

        if (!is_string($this->_transactionId) || strlen($this->_transactionId) != 32) {
            throw new BalanceException(" TransactionId value is invalid");
        }

        $response = $this->call('updateprepaidbalance', array(
            "customer_id" => $this->getCustomerId(),
            "prepaid_funds" => $this->_funds,
            "operation_type" => ($this->_funds > 0) ? self::OP_ADD : self::OP_REMOVE,
            "uniq_hash" => $this->_transactionId
        ));
        //set prepaid balance value

        $this->setPrepaidBalance($response['prepaid_balance']);
        return $this;
    }

function
changeBalance
(
$
funds
,
$
transactionId
=
)
{
if
(
!
$
this
->
getCustomerId
(
)
>
0
)
{
throw
new
BalanceException
(
"Customer is invalid"
)
;
}
if
(
!
(
is_numeric
(
$
funds
)
)
)
{
throw
new
BalanceException
(
"Funds value is invalid"
)
;
}
$
this
->
_funds
=
$
funds
;
$
this
->
_transactionId
=
(
$
transactionId
$
transactionId
:
$
this
->
generateTransactionId
(
)
)
;
if
(
!
is_string
(
$
this
->
_transactionId
)
||
strlen
(
$
this
->
_transactionId
)
!=
32
)
{
throw
new
BalanceException
(
" TransactionId value is invalid"
)
;
}
$
response
=
$
this
->
call
(
'updateprepaidbalance'
,
array
(
"customer_id"
=>
$
this
->
getCustomerId
(
)
,
"prepaid_funds"
=>
$
this
->
_funds
,
"operation_type"
=>
(
$
this
->
_funds
>
0
)
self
::
OP_ADD
:
self
::
OP_REMOVE
,
"uniq_hash"
=>
$
this
->
_transactionId
)
)
;
//set prepaid balance value
$
this
->
setPrepaidBalance
(
$
response
[
'prepaid_balance'
]
)
;
return
$
this
;
}

method to change customer balance with funds value
@link http://open.didww.com/index.php/10._Update_Prepaid_Balance
@param float $funds
@param string $transactionId d5 hash of transaction to avoid duplications
@return Balance
@throws BalanceException


function synchronizePrepaidBalance()
    {
        if (!$this->getCustomerId()) {
            throw new BalanceException("Customer Id is undefined");
        }

        $response = $this->call('getprepaidbalance', array(
            "customer_id" => $this->getCustomerId()
        ));

        $this->setPrepaidBalance($response['prepaid_balance']);
        return $this;
    }

function
synchronizePrepaidBalance
(
)
{
if
(
!
$
this
->
getCustomerId
(
)
)
{
throw
new
BalanceException
(
"Customer Id is undefined"
)
;
}
$
response
=
$
this
->
call
(
'getprepaidbalance'
,
array
(
"customer_id"
=>
$
this
->
getCustomerId
(
)
)
)
;
$
this
->
setPrepaidBalance
(
$
response
[
'prepaid_balance'
]
)
;
return
$
this
;
}

method to set current value of customer balance from API
@link http://open.didww.com/index.php/9._Get_Prepaid_Balance
@return Balance


public function setCanvas($width, $height)
    {
        $this->canvasWidth = $width;
        $this->canvasHeight = $height;

        return $this;
    }

public function setCanvas ( $ width , $ height ) { $ this -> canvasWidth = $ width ; $ this -> canvasHeight = $ height ; return $ this ; }

Set canvas dimensions

@param  int $width
@param  int $height
@return \Intervention\Image\Gd\Gif\Encoder


public function setFromDecoded(Decoded $decoded, $frameIndex = null)
    {
        if (is_null($frameIndex)) {
            // setup from all decoded data
            $width = $decoded->getCanvasWidth();
            $height = $decoded->getCanvasHeight();
            $colorTable = $decoded->getGlobalColorTable();
            $loops = $decoded->getLoops();
            $frames = $decoded->getFrames();
        } else {
            // setup only one specific frame
            $frame = $decoded->getFrame($frameIndex);
            $frame->setOffset(0, 0);
            $width = $frame->decodeWidth();
            $height = $frame->decodeHeight();
            $colorTable = $frame->hasLocalColorTable() ? $frame->getLocalColorTable() : $decoded->getGlobalColorTable();
            $loops = 0;
            $frames = array($frame);
        }

        // setup
        $this->setCanvas($width, $height);
        $this->setGlobalColorTable($colorTable);
        $this->setBackgroundColorIndex($decoded->getBackgroundColorIndex());
        $this->setLoops($loops);
        $this->setFrames($frames);

        return $this;
    }

public
function
setFromDecoded
(
Decoded
$
decoded
,
$
frameIndex
=
)
{
if
(
is_null
(
$
frameIndex
)
)
{
// setup from all decoded data
$
width
=
$
decoded
->
getCanvasWidth
(
)
;
$
height
=
$
decoded
->
getCanvasHeight
(
)
;
$
colorTable
=
$
decoded
->
getGlobalColorTable
(
)
;
$
loops
=
$
decoded
->
getLoops
(
)
;
$
frames
=
$
decoded
->
getFrames
(
)
;
}
else
{
// setup only one specific frame
$
frame
=
$
decoded
->
getFrame
(
$
frameIndex
)
;
$
frame
->
setOffset
(
0
,
0
)
;
$
width
=
$
frame
->
decodeWidth
(
)
;
$
height
=
$
frame
->
decodeHeight
(
)
;
$
colorTable
=
$
frame
->
hasLocalColorTable
(
)
$
frame
->
getLocalColorTable
(
)
:
$
decoded
->
getGlobalColorTable
(
)
;
$
loops
=
0
;
$
frames
=
array
(
$
frame
)
;
}
// setup
$
this
->
setCanvas
(
$
width
,
$
height
)
;
$
this
->
setGlobalColorTable
(
$
colorTable
)
;
$
this
->
setBackgroundColorIndex
(
$
decoded
->
getBackgroundColorIndex
(
)
)
;
$
this
->
setLoops
(
$
loops
)
;
$
this
->
setFrames
(
$
frames
)
;
return
$
this
;
}

Setup encoder from Decoded object

@param Decoded  $decoded
@param int|null $frameIndex
@return \Intervention\Image\Gd\Gif\Encoder


public function createFrameFromGdResource($resource, $delay = null)
    {
        // get imagedata from resource
        $gifdata = $this->encodeGdResource($resource);
        $decoder = new Decoder;
        $gif = $decoder->initFromData($gifdata)->decode();

        $frame = $gif->getFrames()[0];
        $frame->setLocalColorTable($gif->getGlobalColorTable());
        $frame->setDelay($delay);

        $this->frames[] = $frame;
    }

public
function
createFrameFromGdResource
(
$
resource
,
$
delay
=
)
{
// get imagedata from resource
$
gifdata
=
$
this
->
encodeGdResource
(
$
resource
)
;
$
decoder
=
new
Decoder
;
$
gif
=
$
decoder
->
initFromData
(
$
gifdata
)
->
decode
(
)
;
$
frame
=
$
gif
->
getFrames
(
)
[
0
]
;
$
frame
->
setLocalColorTable
(
$
gif
->
getGlobalColorTable
(
)
)
;
$
frame
->
setDelay
(
$
delay
)
;
$
this
->
frames
[
]
=
$
frame
;
}

Create and add new frame from GD resource

@param  resource $resource
@param  integer  $delay
@return void


public function encode()
    {
        // create gif
        $encoded = $this->buildLogicalScreenDescriptor();

        if ($this->hasGlobalColorTable()) {
            $encoded .= $this->getGlobalColorTable();
        }

        // netscape extension
        if ($this->isAnimated() && $this->doesLoop()) {
            $encoded .= $this->buildNetscapeExtension();
        }

        // add frame(s)
        foreach ($this->frames as $frame) {
            $encoded .= $this->buildFrame($frame);
        }

        // EOF
        $encoded .= "\x3B";

        return $encoded;
    }

public
function
encode
(
)
{
// create gif
$
encoded
=
$
this
->
buildLogicalScreenDescriptor
(
)
;
if
(
$
this
->
hasGlobalColorTable
(
)
)
{
$
encoded
.=
$
this
->
getGlobalColorTable
(
)
;
}
// netscape extension
if
(
$
this
->
isAnimated
(
)
&&
$
this
->
doesLoop
(
)
)
{
$
encoded
.=
$
this
->
buildNetscapeExtension
(
)
;
}
// add frame(s)
foreach
(
$
this
->
frames
as
$
frame
)
{
$
encoded
.=
$
this
->
buildFrame
(
$
frame
)
;
}
// EOF
$
encoded
.=
"\x3B"
;
return
$
encoded
;
}


private function buildLogicalScreenDescriptor()
    {
        // gif header
        $descriptor = 'GIF89a';

        // canvas width/height
        $descriptor .= pack('v*', $this->canvasWidth);
        $descriptor .= pack('v*', $this->canvasHeight);

        // packed field
        $colorResolution = 111;
        $sortFlag = 0;

        if ($this->hasGlobalColorTable()) {

            $globalColorTableFlag = 1;
            $globalColorTableSize = log(strlen($this->getGlobalColorTable()) / 3, 2) - 1;
            $globalColorTableSize = decbin($globalColorTableSize);
            $globalColorTableSize = str_pad($globalColorTableSize, 3, 0, STR_PAD_LEFT);

        } else {
            $globalColorTableFlag = 0;
            $globalColorTableSize = 0;
        }

        $packed = $globalColorTableFlag.$colorResolution.$sortFlag.$globalColorTableSize;

        $descriptor .= pack('C', bindec($packed));

        // background color index
        $descriptor .= pack('C', $this->backgroundColorIndex);

        // pixel aspect ratio
        $descriptor .= "\x00";

        return $descriptor;
    }

private
function
buildLogicalScreenDescriptor
(
)
{
// gif header
$
descriptor
=
'GIF89a'
;
// canvas width/height
$
descriptor
.=
pack
(
'v*'
,
$
this
->
canvasWidth
)
;
$
descriptor
.=
pack
(
'v*'
,
$
this
->
canvasHeight
)
;
// packed field
$
colorResolution
=
111
;
$
sortFlag
=
0
;
if
(
$
this
->
hasGlobalColorTable
(
)
)
{
$
globalColorTableFlag
=
1
;
$
globalColorTableSize
=
log
(
strlen
(
$
this
->
getGlobalColorTable
(
)
)
/
3
,
2
)
1
;
$
globalColorTableSize
=
decbin
(
$
globalColorTableSize
)
;
$
globalColorTableSize
=
str_pad
(
$
globalColorTableSize
,
3
,
0
,
STR_PAD_LEFT
)
;
}
else
{
$
globalColorTableFlag
=
0
;
$
globalColorTableSize
=
0
;
}
$
packed
=
$
globalColorTableFlag
.
$
colorResolution
.
$
sortFlag
.
$
globalColorTableSize
;
$
descriptor
.=
pack
(
'C'
,
bindec
(
$
packed
)
)
;
// background color index
$
descriptor
.=
pack
(
'C'
,
$
this
->
backgroundColorIndex
)
;
// pixel aspect ratio
$
descriptor
.=
"\x00"
;
return
$
descriptor
;
}

Build logical screen descriptor

@return string


private function buildNetscapeExtension()
    {
        $extension = "\x21";
        $extension .= "\xFF";
        $extension .= "\x0B";
        $extension .= 'NETSCAPE2.0';
        $extension .= "\x03";
        $extension .= "\x01";
        $extension .= pack('v', $this->loops);
        $extension .= "\x00";

        return $extension;
    }

private function buildNetscapeExtension ( ) { $ extension = "\x21" ; $ extension .= "\xFF" ; $ extension .= "\x0B" ; $ extension .= 'NETSCAPE2.0' ; $ extension .= "\x03" ; $ extension .= "\x01" ; $ extension .= pack ( 'v' , $ this -> loops ) ; $ extension .= "\x00" ; return $ extension ; }

Build Netscape extension

@return string


private function buildFrame(Frame $frame)
    {
        // graphics control extensions
        $encoded = $this->buildGraphicsControlExtension($frame);

        // image descriptor
        $encoded .= $this->buildImageDescriptor($frame);

        // add image data
        $encoded .= $frame->getImageData();

        return $encoded;
    }

private
function
buildFrame
(
Frame
$
frame
)
{
// graphics control extensions
$
encoded
=
$
this
->
buildGraphicsControlExtension
(
$
frame
)
;
// image descriptor
$
encoded
.=
$
this
->
buildImageDescriptor
(
$
frame
)
;
// add image data
$
encoded
.=
$
frame
->
getImageData
(
)
;
return
$
encoded
;
}

Build encoded Frame

@param  Frame  $frame
@return string


private function buildGraphicsControlExtension(Frame $frame)
    {
        // start
        $extension = "\x21\xF9";

        // byte size
        $extension .= "\x04";

        // packed field
        $disposalMethod = decbin($frame->getDisposalMethod());
        $disposalMethod = str_pad($disposalMethod, 3, 0, STR_PAD_LEFT);
        $userInputFlat = 0;
        $transparentColorFlag = $frame->hasTransparentColor() ? 1 : 0;
        $packed = $disposalMethod.$userInputFlat.$transparentColorFlag;
        $packed = str_pad($packed, 3, 0, STR_PAD_LEFT);
        $extension .= pack('C', bindec($packed));

        // delay
        $extension .= pack('v*', $frame->getDelay());

        // transparent color index
        if ($frame->hasTransparentColor()) {
            $extension .= $frame->getTransparentColorIndex();
        } else {
            $extension .= "\x00";
        }

        // block terminator
        $extension .= "\x00";

        return $extension;
    }

private
function
buildGraphicsControlExtension
(
Frame
$
frame
)
{
// start
$
extension
=
"\x21\xF9"
;
// byte size
$
extension
.=
"\x04"
;
// packed field
$
disposalMethod
=
decbin
(
$
frame
->
getDisposalMethod
(
)
)
;
$
disposalMethod
=
str_pad
(
$
disposalMethod
,
3
,
0
,
STR_PAD_LEFT
)
;
$
userInputFlat
=
0
;
$
transparentColorFlag
=
$
frame
->
hasTransparentColor
(
)
1
:
0
;
$
packed
=
$
disposalMethod
.
$
userInputFlat
.
$
transparentColorFlag
;
$
packed
=
str_pad
(
$
packed
,
3
,
0
,
STR_PAD_LEFT
)
;
$
extension
.=
pack
(
'C'
,
bindec
(
$
packed
)
)
;
// delay
$
extension
.=
pack
(
'v*'
,
$
frame
->
getDelay
(
)
)
;
// transparent color index
if
(
$
frame
->
hasTransparentColor
(
)
)
{
$
extension
.=
$
frame
->
getTransparentColorIndex
(
)
;
}
else
{
$
extension
.=
"\x00"
;
}
// block terminator
$
extension
.=
"\x00"
;
return
$
extension
;
}

Build encoded graphics control extension for frame

@param  Frame  $frame
@return string


private function buildImageDescriptor(Frame $frame)
    {
        // seperator
        $descriptor = "\x2C";

        // image left/top
        $descriptor .= pack('v*',
            $frame->offset->left,
            $frame->offset->top
        );

        // image width/height
        $descriptor .= pack('v*',
            $frame->size->width,
            $frame->size->height
        );

        $interlacedFlag = $frame->isInterlaced() ? 1 : 0;
        $reserved1 = 0;
        $reserved2 = 0;

        if ($frame->hasLocalColorTable()) {
            $colorTableFlag = 1;
            $colorTableSize = log(strlen($frame->getLocalColorTable()) / 3, 2) - 1;
            $colorTableSize = decbin($colorTableSize);
            $sortFlag = 0;
        } else {
            $colorTableFlag = 0;
            $colorTableSize = 0;
            $sortFlag = 0;
        }

        $colorTableSize = str_pad($colorTableSize, 3, 0, STR_PAD_LEFT);

        // packed field
        $packed = $colorTableFlag.$interlacedFlag.$sortFlag.$reserved1.$reserved2.$colorTableSize;
        $descriptor .= pack('C', bindec($packed));

        if ($frame->hasLocalColorTable()) {
            // add local color table
            $descriptor .= $frame->getLocalColorTable();
        }

        return $descriptor;
    }

private
function
buildImageDescriptor
(
Frame
$
frame
)
{
// seperator
$
descriptor
=
"\x2C"
;
// image left/top
$
descriptor
.=
pack
(
'v*'
,
$
frame
->
offset
->
left
,
$
frame
->
offset
->
top
)
;
// image width/height
$
descriptor
.=
pack
(
'v*'
,
$
frame
->
size
->
width
,
$
frame
->
size
->
height
)
;
$
interlacedFlag
=
$
frame
->
isInterlaced
(
)
1
:
0
;
$
reserved1
=
0
;
$
reserved2
=
0
;
if
(
$
frame
->
hasLocalColorTable
(
)
)
{
$
colorTableFlag
=
1
;
$
colorTableSize
=
log
(
strlen
(
$
frame
->
getLocalColorTable
(
)
)
/
3
,
2
)
1
;
$
colorTableSize
=
decbin
(
$
colorTableSize
)
;
$
sortFlag
=
0
;
}
else
{
$
colorTableFlag
=
0
;
$
colorTableSize
=
0
;
$
sortFlag
=
0
;
}
$
colorTableSize
=
str_pad
(
$
colorTableSize
,
3
,
0
,
STR_PAD_LEFT
)
;
// packed field
$
packed
=
$
colorTableFlag
.
$
interlacedFlag
.
$
sortFlag
.
$
reserved1
.
$
reserved2
.
$
colorTableSize
;
$
descriptor
.=
pack
(
'C'
,
bindec
(
$
packed
)
)
;
if
(
$
frame
->
hasLocalColorTable
(
)
)
{
// add local color table
$
descriptor
.=
$
frame
->
getLocalColorTable
(
)
;
}
return
$
descriptor
;
}

Build encoded image descriptor for frame

@param  Frame  $frame
@return string


public static function create(Order $order)
    {
        $properties = self::getClientInstance()->call('ordercreate', $order->toArray(array('includeNumber' => false)));
        $did = new DIDNumber($order);
        $did->getOrder()->setCityId($properties['city_id']);
        unset($properties['result'], $properties['autorenew_enable'], $properties['city_prefix'], $properties['country_iso'], $properties['country_iso'], $properties['city_id']);
        $did->fromArray($properties);
        return $did;
    }

public static function create ( Order $ order ) { $ properties = self :: getClientInstance ( ) -> call ( 'ordercreate' , $ order -> toArray ( array ( 'includeNumber' => false ) ) ) ; $ did = new DIDNumber ( $ order ) ; $ did -> getOrder ( ) -> setCityId ( $ properties [ 'city_id' ] ) ; unset ( $ properties [ 'result' ] , $ properties [ 'autorenew_enable' ] , $ properties [ 'city_prefix' ] , $ properties [ 'country_iso' ] , $ properties [ 'country_iso' ] , $ properties [ 'city_id' ] ) ; $ did -> fromArray ( $ properties ) ; return $ did ; }

create did number for order
@link http://open.didww.com/index.php/5._Order_Create
@param Order $order
@return DIDNumber


function changeAutorenew($flag)
    {
        $this->call('order_autorenew_status', array(
            "customer_id" => $this->_order->getCustomerId(),
            "did_number" => $this->getDIDNumber(),
            "status" => (int)$flag
        ));
        $this->_order->setAutorenewEnable($flag);
    }

function changeAutorenew ( $ flag ) { $ this -> call ( 'order_autorenew_status' , array ( "customer_id" => $ this -> _order -> getCustomerId ( ) , "did_number" => $ this -> getDIDNumber ( ) , "status" => ( int ) $ flag ) ) ; $ this -> _order -> setAutorenewEnable ( $ flag ) ; }

change API2 order autorenew enable
@param bool $flag


public function renew()
    {
        $properties = $this->call('orderautorenew', array(
            "customer_id" => $this->_order->getCustomerId(),
            "did_number" => $this->getDIDNumber(),
            "period" => $this->_order->getPeriod(),
            "uniq_hash" => $this->generateUniqueHash()
        ));

        $this->getOrder()->setCityId($properties['city_id']);
        unset($properties['result'], $properties['autorenew_enable'], $properties['city_prefix'], $properties['country_iso'], $properties['city_id']);

        unset($properties['result'], $properties['autorenew_enable']);
        $this->fromArray($properties);
        return $this;
    }

public function renew ( ) { $ properties = $ this -> call ( 'orderautorenew' , array ( "customer_id" => $ this -> _order -> getCustomerId ( ) , "did_number" => $ this -> getDIDNumber ( ) , "period" => $ this -> _order -> getPeriod ( ) , "uniq_hash" => $ this -> generateUniqueHash ( ) ) ) ; $ this -> getOrder ( ) -> setCityId ( $ properties [ 'city_id' ] ) ; unset ( $ properties [ 'result' ] , $ properties [ 'autorenew_enable' ] , $ properties [ 'city_prefix' ] , $ properties [ 'country_iso' ] , $ properties [ 'city_id' ] ) ; unset ( $ properties [ 'result' ] , $ properties [ 'autorenew_enable' ] ) ; $ this -> fromArray ( $ properties ) ; return $ this ; }

renew order for current period
@link http://open.didww.com/index.php/7._Order_Autorenew
@return DIDNumber


protected function _reload($didNumber = NULL, $orderId = NULL)
    {
        $properties = $this->call('getservicedetails', array(
            "customer_id" => $this->_order->getCustomerId(),
            "order_id" => $orderId,
            "did_number" => $didNumber
        ));
        unset($properties['result']);
        $this->fromServiceData($properties);
    }

protected function _reload ( $ didNumber = NULL , $ orderId = NULL ) { $ properties = $ this -> call ( 'getservicedetails' , array ( "customer_id" => $ this -> _order -> getCustomerId ( ) , "order_id" => $ orderId , "did_number" => $ didNumber ) ) ; unset ( $ properties [ 'result' ] ) ; $ this -> fromServiceData ( $ properties ) ; }

reload didnumber by number or order id
@param string $didNumber
@param string $orderId


public function updateMapping(Mapping $newMapping = NULL)
    {
        $mapping = empty($newMapping) ? $this->_order->getMapData() : $newMapping;
        $this->call('updatemapping', array(
            "customer_id" => $this->_order->getCustomerId(),
            "did_number" => $this->getDIDNumber(),
            "map_data" => $mapping->toArray()
        ));
        $this->_order->setMapData($newMapping);
        return true;
    }

public function updateMapping ( Mapping $ newMapping = NULL ) { $ mapping = empty ( $ newMapping ) ? $ this -> _order -> getMapData ( ) : $ newMapping ; $ this -> call ( 'updatemapping' , array ( "customer_id" => $ this -> _order -> getCustomerId ( ) , "did_number" => $ this -> getDIDNumber ( ) , "map_data" => $ mapping -> toArray ( ) ) ) ; $ this -> _order -> setMapData ( $ newMapping ) ; return true ; }

update mapping of did number
@link http://open.didww.com/index.php/8._Update_Mapping
@param Mapping $newMapping


protected function generateUniqueHash()
    {
        return $this->_order->getUniqHash() ?:
            md5(sprintf("%s.%s.%s.%s.%s.%s",
                $this->getDIDExpireDateGmt(),
                $this->getOrderId(),
                $this->getDIDMappingFormat(),
                $this->getDIDPeriod(),
                $this->getDIDTimeLeft(),
                $this->getDIDNumber()
            ));
    }

protected function generateUniqueHash ( ) { return $ this -> _order -> getUniqHash ( ) ? : md5 ( sprintf ( "%s.%s.%s.%s.%s.%s" , $ this -> getDIDExpireDateGmt ( ) , $ this -> getOrderId ( ) , $ this -> getDIDMappingFormat ( ) , $ this -> getDIDPeriod ( ) , $ this -> getDIDTimeLeft ( ) , $ this -> getDIDNumber ( ) ) ) ; }

generate unique hash for did renew operation
@return string


protected function isIpInRange($targetIp, $rangeIp, $cidrMask)
    {
        $target = sprintf('%032b', ip2long($targetIp));
        $range = sprintf('%032b', ip2long($rangeIp));

        return 0 === substr_compare($target, $range, 0, $cidrMask);
    }

protected function isIpInRange ( $ targetIp , $ rangeIp , $ cidrMask ) { $ target = sprintf ( '%032b' , ip2long ( $ targetIp ) ) ; $ range = sprintf ( '%032b' , ip2long ( $ rangeIp ) ) ; return 0 === substr_compare ( $ target , $ range , 0 , $ cidrMask ) ; }

Determines if a target IP address is within a particular IP address range.

@param string $targetIp The IP address to check
@param string $rangeIp  The IP address defining the range
@param int    $cidrMask The CIDR notation net mask defining the range

@return bool True if the target IP falls within the specified range. Otherwise false.

Determines if a target IP address is within a particular IP address range .


public function getParameter(string $name, $default = null)
    {
        return $this->hasParameter($name) ? $this->parameters[$name] : $default;
    }

public function getParameter ( string $ name , $ default = null ) { return $ this -> hasParameter ( $ name ) ? $ this -> parameters [ $ name ] : $ default ; }

Get the parameter with the the given name, or return the default
value if the parameter is not set.

@param string            $name The parameter name.
@param mixed             $default The returned default value if the parameter is not set.
@return mixed

Get the parameter with the the given name or return the default value if the parameter is not set .


private function linkMetaService(string $serviceName, string $key)
    {
        // make sure the service link is there
        if (!isset($this->metadataService[$serviceName])) {
            $this->metadataService[$serviceName] = [];
        }

        if (!in_array($key, $this->metadataService[$serviceName])) {
            $this->metadataService[$serviceName][] = $key;
        }
    }

private
function
linkMetaService
(
string
$
serviceName
,
string
$
key
)
{
// make sure the service link is there
if
(
!
isset
(
$
this
->
metadataService
[
$
serviceName
]
)
)
{
$
this
->
metadataService
[
$
serviceName
]
=
[
]
;
}
if
(
!
in_array
(
$
key
,
$
this
->
metadataService
[
$
serviceName
]
)
)
{
$
this
->
metadataService
[
$
serviceName
]
[
]
=
$
key
;
}
}

Make sure the metadata and key are linked both ways.

@param string            $serviceName
@param string            $key
@return void

Make sure the metadata and key are linked both ways .


public function setMetaData(string $serviceName, string $key, array $values)
    {
        // make sure the service exists
        if (!$this->has($serviceName)) {
            throw new UnknownServiceException('There is no service named "' . $serviceName . '" specified.');
        }

        // make sure all elements are arrays
        foreach($values as $value)
        {
            if (!is_array($value)) {
                throw new ContainerException('Every meta data value must be an array. "' . gettype($value) . '" given.');
            }
        }

        // make sure the metadata key is allocated
        if (!isset($this->metadata[$key])) {
            $this->metadata[$key] = [];
        }

        // write
        $this->metadata[$key][$serviceName] = $values;
        $this->linkMetaService($serviceName, $key);
    }

Set metadata for a specific service
This will override all meta data matching service and key.

@param string            $serviceName
@param string            $key
@param array             $values multidimensional array

@return void

Set metadata for a specific service This will override all meta data matching service and key .


public function addMetaData(string $serviceName, string $key, array $values)
    {
        // make sure the service exists
        if (!$this->has($serviceName)) {
            throw new UnknownServiceException('There is no service named "' . $serviceName . '" specified.');
        }

        // make sure the metadata key is allocated
        if (!isset($this->metadata[$key])) {
            $this->metadata[$key] = [];
        }

        // make sure the service key is allocated
        if (!isset($this->metadata[$key][$serviceName])) {
            $this->metadata[$key][$serviceName] = [];
        }

        // append
        $this->metadata[$key][$serviceName][] = $values;
        $this->linkMetaService($serviceName, $key);
    }

Same as `setMetaData` but will append the data instead of overriding.

@param string            $serviceName
@param string            $key
@param array             $values

@return void

Same as setMetaData but will append the data instead of overriding .


public function remove(string $serviceName) : bool
    {
        if (!$this->has($serviceName)) {
            return false; // can only remove services that exist
        }

        if ($serviceName === 'container') {
            return false; // the container itself cannot be removed
        }

        // remove the already shared instnace if set
        if (isset($this->resolvedSharedServices[$serviceName])) {
            unset($this->resolvedSharedServices[$serviceName]);
        }

        // remove the service type
        if (isset($this->serviceResolverType[$serviceName])) {
            unset($this->serviceResolverType[$serviceName]);
        }

        // remove all possible references
        if (isset($this->serviceProviders[$serviceName])) {
            unset($this->serviceProviders[$serviceName]);
        }
        if (isset($this->resolverMethods[$serviceName])) {
            unset($this->resolverMethods[$serviceName]);
        }
        if (isset($this->resolverFactories[$serviceName])) {
            unset($this->resolverFactories[$serviceName]);
        }

        return true;
    }

Removes a service from the container and releases the shared instance
if it has been loaded.

@param string            $serviceName The name / Identifier of the service to look for.

@return bool Returns true if the service has been removed.

Removes a service from the container and releases the shared instance if it has been loaded .


public function release(string $serviceName) : bool
    {
        if (isset($this->resolvedSharedServices[$serviceName]))
        {
            unset($this->resolvedSharedServices[$serviceName]); return true;
        }

        return false;
    }

public function release ( string $ serviceName ) : bool { if ( isset ( $ this -> resolvedSharedServices [ $ serviceName ] ) ) { unset ( $ this -> resolvedSharedServices [ $ serviceName ] ) ; return true ; } return false ; }

Release a shared resolved service from the container. This
will force the service to reload when accessed again.

@param string                $serviceName

@return bool Return false on failure.

Release a shared resolved service from the container . This will force the service to reload when accessed again .


public function get(string $serviceName)
    {
        // if the service container itself is requested
        if ($serviceName === 'container') {
            return $this;
        }

        // check if the service name has a registered service type
        if (!isset($this->serviceResolverType[$serviceName]))
        {
            throw new UnknownServiceException('Could not find service named "' . $serviceName . '" registered in the container.');
        }
        $serviceResolverType = $this->serviceResolverType[$serviceName];

        // check if a service instance already exists
        if (
            isset($this->resolvedSharedServices[$serviceName]) &&
            $serviceResolverType !== static::RESOLVE_FACTORY
        ) {
            return $this->resolvedSharedServices[$serviceName];
        }

        switch ($serviceResolverType)
        {
            // Default resolver for all services that are defined
            // directly in the container. We can skip here an unnecessary method call.
            case static::RESOLVE_METHOD:
                return $this->{$this->resolverMethods[$serviceName]}();
            break;

            case static::RESOLVE_PROVIDER:
                return $this->resolveServiceProvider($serviceName);
            break;

            case static::RESOLVE_FACTORY:
                return $this->resolveServiceFactory($serviceName);
            break;

            case static::RESOLVE_SHARED:
                return $this->resolveServiceShared($serviceName);
            break;

            default:
                throw new UnknownServiceException('Could not resolve service named "' . $serviceName . '", the resolver type is unkown.');
            break;
        }
    }

Retrieve a service from the container.

@throws UnknownServiceException When a service could not be found or is unresolvable.

@param string            $serviceName The name / Identifier of the service to look for.

@return mixed The requested service.


private function createInstanceFromFactory($factory)
    {
        if ($factory instanceof ServiceFactoryInterface)
        {
            return $factory->create($this);
        }
        elseif ($factory instanceof Closure)
        {
            return $factory($this);
        }

        // otherwise throw an exception
        throw new InvalidServiceException('Service could not be resolved, the registered factory is invalid.');
    }

Resolve a service instance from the given factory object.

@param ServiceFactoryInterface|Closure           $factory The factory object.

@return mixed The instance of created by the factory object.

Resolve a service instance from the given factory object .


private function resolveServiceProvider(string $name)
    {
        list($service, $isShared) = $this->serviceProviders[$name]->resolve($name, $this);

        if ($isShared) {
            $this->resolvedSharedServices[$name] = $service;
        }

        return $service;
    }

private function resolveServiceProvider ( string $ name ) { list ( $ service , $ isShared ) = $ this -> serviceProviders [ $ name ] -> resolve ( $ name , $ this ) ; if ( $ isShared ) { $ this -> resolvedSharedServices [ $ name ] = $ service ; } return $ service ; }

Resolves a service instance from a provider and stores the
result inside the shared services if needed.

@param string            $name The service name.

@return mixed The service instance created by the provider.

Resolves a service instance from a provider and stores the result inside the shared services if needed .


public function register(ServiceProviderInterface $provider)
    {
        foreach($provider->provides() as $serviceName)
        {
            $this->setServiceResolverType($serviceName, static::RESOLVE_PROVIDER);
            $this->serviceProviders[$serviceName] = $provider;
        }
    }

public function register ( ServiceProviderInterface $ provider ) { foreach ( $ provider -> provides ( ) as $ serviceName ) { $ this -> setServiceResolverType ( $ serviceName , static :: RESOLVE_PROVIDER ) ; $ this -> serviceProviders [ $ serviceName ] = $ provider ; } }

Register a service provider.
This will call the `provides` method on the given service provider instance.

@param ServiceProviderInterface          $provider The service provider instance.
@return void

Register a service provider . This will call the provides method on the given service provider instance .


public function bind(string $name, $factory, bool $shared = true)
    {
        if (is_string($factory)) {
            return $this->bindClass($name, $factory, [], $shared);
        } elseif ($shared) {
            $this->bindFactoryShared($name, $factory);
        } else {
            $this->bindFactory($name, $factory);
        }
    }

public function bind ( string $ name , $ factory , bool $ shared = true ) { if ( is_string ( $ factory ) ) { return $ this -> bindClass ( $ name , $ factory , [ ] , $ shared ) ; } elseif ( $ shared ) { $ this -> bindFactoryShared ( $ name , $ factory ) ; } else { $ this -> bindFactory ( $ name , $ factory ) ; } }

Binds a service factory to the container.

$container->bind('session', new SessionFactory);

$container->bind('config', function($c) {
return new Config($c->get('config.loader'));
}, false);

$container->bind('router', '\\Routing\\Router')
->addDependencyArgument('config');

@param string            $name The service name.
@param mixed             $factory The service factory instance, the closure or the classname as string
@param bool              $shared Should the service be shared inside the container.

@return Closure|ServiceFactoryInterface The given or generated service factory.

Binds a service factory to the container .


public function bindClass(string $name, string $factory, array $arguments = [], bool $shared = true) : ServiceFactory
    {
        $factory = new ServiceFactory($factory, $arguments);

        if ($shared) {
            $this->bindFactoryShared($name, $factory);
        } else {
            $this->bindFactory($name, $factory);
        }

        return $factory;
    }

public function bindClass ( string $ name , string $ factory , array $ arguments = [ ] , bool $ shared = true ) : ServiceFactory { $ factory = new ServiceFactory ( $ factory , $ arguments ) ; if ( $ shared ) { $ this -> bindFactoryShared ( $ name , $ factory ) ; } else { $ this -> bindFactory ( $ name , $ factory ) ; } return $ factory ; }

Creates and binds a service factory by class name and arguments.

@param string            $name The service name.
@param string            $className The service class name.
@param array             $arguments An array of arguments.
@param bool              $shared Should the service be shared inside the container.

@return ServiceFactory The created service factory

Creates and binds a service factory by class name and arguments .


public function bindFactory(string $name, $factory)
    {
        $this->setServiceResolverType($name, static::RESOLVE_FACTORY);
        $this->resolverFactories[$name] = $factory;
    }

public function bindFactory ( string $ name , $ factory ) { $ this -> setServiceResolverType ( $ name , static :: RESOLVE_FACTORY ) ; $ this -> resolverFactories [ $ name ] = $ factory ; }

Binds an unshared factory instance to the service container.

@param string                            $name The service name.
@param ServiceFactoryInterface|Closure   $factory The service factory instance or closure.
@return void

Binds an unshared factory instance to the service container .


public function bindFactoryShared(string $name, $factory)
    {
        $this->setServiceResolverType($name, static::RESOLVE_SHARED);
        $this->resolverFactories[$name] = $factory;
    }

public function bindFactoryShared ( string $ name , $ factory ) { $ this -> setServiceResolverType ( $ name , static :: RESOLVE_SHARED ) ; $ this -> resolverFactories [ $ name ] = $ factory ; }

Binds a shared factory instance to the service container.

@param string                            $name The service name.
@param ServiceFactoryInterface|Closure   $factory The service factory instance or closure.
@return void

Binds a shared factory instance to the service container .


public function getServiceResolverType(string $serviceName) : int
    {
        if (!isset($this->serviceResolverType[$serviceName]))
        {
            throw new UnknownServiceException('There is no type for the service named "' . $serviceName . '" specified.');
        }

        return $this->serviceResolverType[$serviceName];
    }

Get the resolver type of the given service name.

@param string                $serviceName
@return int

Get the resolver type of the given service name .


private function addArgument($argumentValue, int $argumentType) : ServiceArguments
    {
        $this->arguments[] = [$argumentValue, $argumentType]; return $this;
    }

private function addArgument ( $ argumentValue , int $ argumentType ) : ServiceArguments { $ this -> arguments [ ] = [ $ argumentValue , $ argumentType ] ; return $ this ; }

Add a service argument of type

@param mixed             $argumentValue
@param int               $argumentType
@return self


public function addArgumentsFromArray(array $argumentsArray)
    {
        foreach($argumentsArray as $argument)
        {
            if (is_string($argument) && ($argument[0] === '@' || $argument[0] === ':'))
            {
                if ($argument[0] === '@') {
                    $this->addDependency(substr($argument, 1));
                } elseif ($argument[0] === ':') {
                    $this->addParameter(substr($argument, 1));
                }
            } else  {
                $this->addRaw($argument);
            }
        }
    }

public function addArgumentsFromArray ( array $ argumentsArray ) { foreach ( $ argumentsArray as $ argument ) { if ( is_string ( $ argument ) && ( $ argument [ 0 ] === '@' || $ argument [ 0 ] === ':' ) ) { if ( $ argument [ 0 ] === '@' ) { $ this -> addDependency ( substr ( $ argument , 1 ) ) ; } elseif ( $ argument [ 0 ] === ':' ) { $ this -> addParameter ( substr ( $ argument , 1 ) ) ; } } else { $ this -> addRaw ( $ argument ) ; } } }

Add arguments with a simple array

- @ prefix indicates dependency
- : prefix indicates parameter

@param array                 $argumentsArray
@return void


public function resolve(Container $container) : array
    {
        $resolvedArguments = [];
        foreach($this->arguments as list($argumentValue, $argumentType))
        {
            switch ($argumentType)
            {
                case static::RAW:
                    $resolvedArguments[] = $argumentValue;
                break;
                case static::DEPENDENCY:
                    $resolvedArguments[] = $container->get($argumentValue);
                break;
                case static::PARAMETER:
                    $resolvedArguments[] = $container->getParameter($argumentValue);
                break;
            }
        }

        return $resolvedArguments;
    }

public function resolve ( Container $ container ) : array { $ resolvedArguments = [ ] ; foreach ( $ this -> arguments as list ( $ argumentValue , $ argumentType ) ) { switch ( $ argumentType ) { case static :: RAW : $ resolvedArguments [ ] = $ argumentValue ; break ; case static :: DEPENDENCY : $ resolvedArguments [ ] = $ container -> get ( $ argumentValue ) ; break ; case static :: PARAMETER : $ resolvedArguments [ ] = $ container -> getParameter ( $ argumentValue ) ; break ; } } return $ resolvedArguments ; }

Resolve the current arguments from the given container instance and
return them as array

@param Container             $container
@return array


public function create(Container $container)
    {
        $instance = new $this->className(...$this->constructorArguments->resolve($container));

        foreach($this->methodCallers as list($method, $arguments))
        {
            $instance->{$method}(... $arguments->resolve($container));
        }

        return $instance;
    }

public function create ( Container $ container ) { $ instance = new $ this -> className ( ... $ this -> constructorArguments -> resolve ( $ container ) ) ; foreach ( $ this -> methodCallers as list ( $ method , $ arguments ) ) { $ instance -> { $ method } ( ... $ arguments -> resolve ( $ container ) ) ; } return $ instance ; }

Construct your object, or value based on the given container.

@param Container             $container
@return mixed

Construct your object or value based on the given container .


public function setTokens(array $tokens)
    {
        // reset the keys
        $this->tokens = array_values($tokens);

        // count the real number of tokens
        $this->tokenCount = count($this->tokens);

        // reset the index
        $this->index = 0;
    }

public
function
setTokens
(
array
$
tokens
)
{
// reset the keys
$
this
->
tokens
=
array_values
(
$
tokens
)
;
// count the real number of tokens
$
this
->
tokenCount
=
count
(
$
this
->
tokens
)
;
// reset the index
$
this
->
index
=
0
;
}

Set the tokens of the current parser

@param array[T]             $tokens
@return void


protected function currentToken() : T
    {
        if (!isset($this->tokens[$this->index]))
        {
            throw new ContainerParserException("The current token is of the available tokens range.");
        }

        return $this->tokens[$this->index];
    }

Retrives the current token based on the index

@return T


protected function nextToken(int $i = 1)
    {
        if (!isset($this->tokens[$this->index + $i])) {
            return false;
        }

        return $this->tokens[$this->index + $i];
    }

protected function nextToken ( int $ i = 1 ) { if ( ! isset ( $ this -> tokens [ $ this -> index + $ i ] ) ) { return false ; } return $ this -> tokens [ $ this -> index + $ i ] ; }

Get the next token based on the current index
If the token does not exist because its off index "false" is returend.

@param int             $i
@return T|false

Get the next token based on the current index If the token does not exist because its off index false is returend .


protected function skipTokenOfType(array $types = [])
    {
        while ((!$this->parserIsDone()) && in_array($this->currentToken()->getType(), $types))
        {
            $this->skipToken();
        }
    }

protected function skipTokenOfType ( array $ types = [ ] ) { while ( ( ! $ this -> parserIsDone ( ) ) && in_array ( $ this -> currentToken ( ) -> getType ( ) , $ types ) ) { $ this -> skipToken ( ) ; } }

Skip all upcoming tokens of the given type

@param array[int]         $types
@return void


protected function getRemainingTokens(bool $skip = false) : array
    {
        $tokens = array();

        while (!$this->parserIsDone())
        {
            $tokens[] = $this->currentToken(); $this->skipToken();
        }

        if (!$skip)
        {
            $this->index -= count($tokens);
        }

        return $tokens;
    }

protected function getRemainingTokens ( bool $ skip = false ) : array { $ tokens = array ( ) ; while ( ! $ this -> parserIsDone ( ) ) { $ tokens [ ] = $ this -> currentToken ( ) ; $ this -> skipToken ( ) ; } if ( ! $ skip ) { $ this -> index -= count ( $ tokens ) ; } return $ tokens ; }

Return all remaining tokens

@param string                    $skip
@return array[T]


protected function getTokensUntil(int $type, bool $ignoreScopes = false) : array
    {
        $tokens = array();

        if (!is_array($type)) {
            $type = array($type);
        }

        while (!$this->parserIsDone() && !in_array($this->currentToken()->getType(), $type))
        {
            // if scopes should be ignored, we need to check if the current
            // token opens one an then get all tokens inside the scope
            if ($ignoreScopes && $this->currentToken()->isType(T::TOKEN_SCOPE_OPEN))
            {
                foreach($this->getTokensUntilClosingScope(true, T::TOKEN_SCOPE_OPEN, T::TOKEN_SCOPE_CLOSE) as $token) {
                    $tokens[] = $token;
                }
            } else {
                $tokens[] = $this->currentToken();
                $this->skipToken();
            }
        }

        return $tokens;
    }

Get all tokens until the next token with given type

@param int                $type
@param bool                  $ignoreScopes if enabled, if the token is inside a new scope its ignored.
@return array[T]


protected function getTokensUntilClosingScope(bool $includeScope = false, int $openToken = T::TOKEN_BRACE_OPEN, int $closeToken = T::TOKEN_BRACE_CLOSE) : array
    {
        if ($this->currentToken()->getType() !== $openToken)
        {
            throw $this->errorUnexpectedToken($this->currentToken());
        }

        $tokens = array();

        // include the opening scope
        if ($includeScope) {
            $tokens[] = $this->currentToken();
        }

        $this->skipToken();

        $currentLevel = 0;

        while($this->currentToken() && !($this->currentToken()->getType() === $closeToken && $currentLevel === 0))
        {
            if ($this->currentToken()->getType() === $openToken)
            {
                $currentLevel++;
            }

            if ($this->currentToken()->getType() === $closeToken)
            {
                $currentLevel--;
            }

            $tokens[] = $this->currentToken();
            $this->skipToken();
        }

        // include the closing scope
        if ($includeScope) {
            $tokens[] = $this->currentToken();
        }

        // skip the closing scope
        $this->skipToken();

        return $tokens;
    }

protected
function
getTokensUntilClosingScope
(
bool
$
includeScope
=
false
,
int
$
openToken
=
T
::
TOKEN_BRACE_OPEN
,
int
$
closeToken
=
T
::
TOKEN_BRACE_CLOSE
)
:
array
{
if
(
$
this
->
currentToken
(
)
->
getType
(
)
!==
$
openToken
)
{
throw
$
this
->
errorUnexpectedToken
(
$
this
->
currentToken
(
)
)
;
}
$
tokens
=
array
(
)
;
// include the opening scope
if
(
$
includeScope
)
{
$
tokens
[
]
=
$
this
->
currentToken
(
)
;
}
$
this
->
skipToken
(
)
;
$
currentLevel
=
0
;
while
(
$
this
->
currentToken
(
)
&&
!
(
$
this
->
currentToken
(
)
->
getType
(
)
===
$
closeToken
&&
$
currentLevel
===
0
)
)
{
if
(
$
this
->
currentToken
(
)
->
getType
(
)
===
$
openToken
)
{
$
currentLevel
++
;
}
if
(
$
this
->
currentToken
(
)
->
getType
(
)
===
$
closeToken
)
{
$
currentLevel
;
}
$
tokens
[
]
=
$
this
->
currentToken
(
)
;
$
this
->
skipToken
(
)
;
}
// include the closing scope
if
(
$
includeScope
)
{
$
tokens
[
]
=
$
this
->
currentToken
(
)
;
}
// skip the closing scope
$
this
->
skipToken
(
)
;
return
$
tokens
;
}

Retruns all tokens until the opened scope is closed again

@return array[T]


protected function errorUnexpectedToken($token)
    {
        $class = new \ReflectionClass($token);
        $constants = array_flip($class->getConstants());

        return new ContainerParserException('unexpected "' . $constants[$token->getType()] . '" given at line ' . $token->getLine());
    }

protected
function
errorUnexpectedToken
(
$
token
)
{
$
class
=
new
\
ReflectionClass
(
$
token
)
;
$
constants
=
array_flip
(
$
class
->
getConstants
(
)
)
;
return
new
ContainerParserException
(
'unexpected "'
.
$
constants
[
$
token
->
getType
(
)
]
.
'" given at line '
.
$
token
->
getLine
(
)
)
;
}

Create new unexpected token exception

@param T                 $token
@return ContainerParserException


protected function parseChild(string $parserClassName, $tokens = null, $skip = true)
    {
        if (is_null($tokens))
        {
            $tokens = $this->getRemainingTokens();
        }

        $parser = new $parserClassName($tokens);
        $node = $parser->parse();

        // Update the current index based on the work of the child parser.
        if ($skip)
        {
            $this->skipToken($parser->getParsedTokensCount());
        }

        // finally return the parsed node
        return $node;
    }

Starts a new parser with the remaining or given tokens

@param string                $parserClassName
@param array                 $tokens
@param bool                  $skip
@return Node


public function parse()
    {
        // reset the result
        $this->result = array();

        // start parsing trought the tokens
        while (!$this->parserIsDone())
        {
            $specialNode = $this->next();

            if ($specialNode instanceof Node)
            {
                return $specialNode;
            }
        }

        // return the result after the loop is done
        return $this->node();
    }

Start the code parser and return the result

@return array


public function setContainerName(string $containerName)
    {
        if (empty($containerName) || !(preg_match('/^[a-zA-Z0-9\\\\_]*$/', $containerName)) || is_numeric($containerName[0]))
        {
            throw new ContainerBuilderException('The container name cannot be empty, start with a number or contain sepcial characters except "\\".');
        }

        if ($containerName[0] === "\\")
        {
            $containerName = substr($containerName, 1);
        }

        $this->containerClassName = $this->containerName = $containerName;

        // check if we need to generate a namespace
        if (($pos = strrpos($containerName, "\\")) !== false)
        {
            $this->containerNamespace = substr($containerName, 0, $pos);
            $this->containerClassName = substr($containerName, $pos + 1);
        }
    }

Sets the container name
This will also update the "containerClassName" and "containerNamespace"

@param string            $containerName
@return void

Sets the container name This will also update the containerClassName and containerNamespace


public function add(string $serviceName, string $serviceClass, array $serviceArguments = [], bool $isShared = true) : ServiceDefinition
    {
        $service = new ServiceDefinition($serviceClass, $serviceArguments);
        $this->addService($serviceName, $service, $isShared);

        return $service;
    }

public function add ( string $ serviceName , string $ serviceClass , array $ serviceArguments = [ ] , bool $ isShared = true ) : ServiceDefinition { $ service = new ServiceDefinition ( $ serviceClass , $ serviceArguments ) ; $ this -> addService ( $ serviceName , $ service , $ isShared ) ; return $ service ; }

Add a service by string and arguments array.

@param string            $serviceName
@param string            $serviceClass
@param array             $serviceArguments
@param bool              $shared
@return ServiceDefinition

Add a service by string and arguments array .


public function addArray(array $servicesArray)
    {
        foreach($servicesArray as $serviceName => $serviceConfiguration)
        {
            $this->addService($serviceName, ServiceDefinition::fromArray($serviceConfiguration), $serviceConfiguration['shared'] ?? true);
        }
    }

public function addArray ( array $ servicesArray ) { foreach ( $ servicesArray as $ serviceName => $ serviceConfiguration ) { $ this -> addService ( $ serviceName , ServiceDefinition :: fromArray ( $ serviceConfiguration ) , $ serviceConfiguration [ 'shared' ] ?? true ) ; } }

Add services by an array

@param array             $serviceArray
@return void


public function addService(string $serviceName, ServiceDefinitionInterface $serviceDefinition, bool $isShared = true)
    {
        if ($this->invalidServiceBuilderString($serviceName))
        {
            throw new ContainerBuilderException('The "'.$serviceName.'" servicename must be a string, cannot be numeric, empty or contain any special characters except "." and "_".');
        }

        // add the service definition
        $this->services[$serviceName] = $serviceDefinition;

        // generate the normalized name
        $this->generateNormalizedServiceName($serviceName);

        // set the shared unshared flag
        if ($isShared && (!in_array($serviceName, $this->shared)))
        {
            $this->shared[] = $serviceName;
        }
        elseif ((!$isShared) && in_array($serviceName, $this->shared))
        {
            unset($this->shared[array_search($serviceName, $this->shared)]);
        }
    }

Add a service definition instance to the container builder.

@param string                        $serviceName
@param ServiceDefinitionInterface    $serviceDefinition
@return void

Add a service definition instance to the container builder .


public function importNamespace(ContainerNamespace $namespace)
    {
        // import the parameters
        $this->parameters = array_merge($this->parameters, $namespace->getParameters());

        // import the service definitions
        foreach($namespace->getServices() as $name => $service)
        {
            $this->addService($name, $service);
        }
    }

public
function
importNamespace
(
ContainerNamespace
$
namespace
)
{
// import the parameters
$
this
->
parameters
=
array_merge
(
$
this
->
parameters
,
$
namespace
->
getParameters
(
)
)
;
// import the service definitions
foreach
(
$
namespace
->
getServices
(
)
as
$
name
=>
$
service
)
{
$
this
->
addService
(
$
name
,
$
service
)
;
}
}

Import data from a container namespace

@param ContainerNamespace            $namespace
@return void


private function invalidServiceBuilderString(string $value) : bool
    {
        if (empty($value) || is_numeric($value)) {
            return true;
        }

        // check for trailing / prepending whitespace ect.
        if (trim($value) !== $value) {
            return true;
        }

        // check for other special characters
        if (preg_match('/[^a-zA-Z0-9._]+/', $value))  {
            return true;
        }

        // also check the first character the string contains with a number
        if (is_numeric($value[0]) || $value[0] === '.' || $value[0] === '_') {
            return true;
        }

        $lastCharacter = $value[strlen($value) - 1];
        if ($lastCharacter === '.' || $lastCharacter === '_') {
            return true;
        }

        return false;
    }

Checks if the given string is valid and not numeric &

@param string            $value
@return bool


private function generateNormalizedServiceName(string $serviceName)
    {
        $normalizedServiceName = $this->camelizeServiceName($serviceName);

        $duplicateCounter = 0;
        $countedNormalizedServiceName = $normalizedServiceName;
        while(in_array($countedNormalizedServiceName, $this->normalizedServiceNames))
        {
            $duplicateCounter++;
            $countedNormalizedServiceName = $normalizedServiceName . $duplicateCounter;
        }

        $this->normalizedServiceNames[$serviceName] = $countedNormalizedServiceName;
    }

private function generateNormalizedServiceName ( string $ serviceName ) { $ normalizedServiceName = $ this -> camelizeServiceName ( $ serviceName ) ; $ duplicateCounter = 0 ; $ countedNormalizedServiceName = $ normalizedServiceName ; while ( in_array ( $ countedNormalizedServiceName , $ this -> normalizedServiceNames ) ) { $ duplicateCounter ++ ; $ countedNormalizedServiceName = $ normalizedServiceName . $ duplicateCounter ; } $ this -> normalizedServiceNames [ $ serviceName ] = $ countedNormalizedServiceName ; }

Generates the "normalizedServiceNames" array.

@param string            $serviceName
@return void

Generates the normalizedServiceNames array .


public function generate() : string
    {
        $buffer = "<?php\n\n";

        // add namespace if needed
        if (!is_null($this->containerNamespace))
        {
            $buffer .= "namespace " . $this->containerNamespace . ";\n\n";
        }

        // add use statement for the super container
        $aliasContainerName = 'ClanCatsContainer' . md5($this->containerName);
        $buffer .= "use " . Container::class . " as " . $aliasContainerName . ";\n\n";

        // generate the the class
        $buffer .= "class $this->containerClassName extends $aliasContainerName {\n\n";

        $buffer .= $this->generateParameters() . "\n";
        $buffer .= $this->generateMetaData() . "\n";
        $buffer .= $this->generateResolverTypes() . "\n";
        $buffer .= $this->generateResolverMappings() . "\n";
        $buffer .= $this->generateResolverMethods() . "\n";

        return $buffer . "\n}";
    }

Generate the container class code string

@return string


private function getResolverMethodName(string $serviceName) : string
    {
        if (!isset($this->normalizedServiceNames[$serviceName]))
        {
            throw new ContainerBuilderException("The '" . $serviceName . "' service has never been definied.");
        }

        return 'resolve' . $this->normalizedServiceNames[$serviceName];
    }

private
function
getResolverMethodName
(
string
$
serviceName
)
:
string
{
if
(
!
isset
(
$
this
->
normalizedServiceNames
[
$
serviceName
]
)
)
{
throw
new
ContainerBuilderException
(
"The '"
.
$
serviceName
.
"' service has never been definied."
)
;
}
return
'resolve'
.
$
this
->
normalizedServiceNames
[
$
serviceName
]
;
}

Generate the service resolver method name for the given service

@param string            $serviceName
@return string


private function generateArgumentsCode(ServiceArguments $arguments) : string
    {
        $buffer = [];

        foreach($arguments->getAll() as list($argumentValue, $argumentType))
        {
            if ($argumentType === ServiceArguments::DEPENDENCY)
            {
                if ($argumentValue === 'container')
                {
                    $buffer[] = "\$this";
                }
                // if the dependency is defined in the current container builder
                // we can be sure that it exists and directly call the resolver method
                elseif (isset($this->services[$argumentValue]))
                {
                    $resolverMethodCall = "\$this->" . $this->getResolverMethodName($argumentValue) . '()';

                    // if is not shared we can just forward the factory method
                    if (!in_array($argumentValue, $this->shared))
                    {
                        $buffer[] = $resolverMethodCall;
                    }
                    // otherwise we have to check if the singleton has
                    // already been resolved.
                    else
                    {
                        $buffer[] = "\$this->resolvedSharedServices['$argumentValue'] ?? \$this->resolvedSharedServices['$argumentValue'] = " . $resolverMethodCall;
                    }
                }
                // if the dependency is not defined inside the container builder
                // it might be added dynamically later. So we just access the containers `get` method.
                else
                {
                    $buffer[] = "\$this->get('$argumentValue')";
                }
            }
            elseif ($argumentType === ServiceArguments::PARAMETER)
            {
                $buffer[] = "\$this->getParameter('$argumentValue')";
            }
            elseif ($argumentType === ServiceArguments::RAW)
            {
                $buffer[] = var_export($argumentValue, true);
            }
        }

        return implode(', ', $buffer);
    }

Generate arguments code

@param ServiceArguments          $arguments
@return string


private function generateMetaData() : string
    {
        $metaData = [];
        $metaDataService = [];

        foreach($this->services as $serviceName => $serviceDefinition)
        {
            foreach($serviceDefinition->getMetaData() as $key => $serviceMetaData)
            {
                if (!isset($metaData[$key])) {
                    $metaData[$key] = [];
                }

                $metaData[$key][$serviceName] = $serviceMetaData;

                // mapping for the service centered
                if (!isset($metaDataService[$serviceName])) {
                    $metaDataService[$serviceName] = [];
                }

                if (!in_array($key, $metaDataService[$serviceName])) {
                    $metaDataService[$serviceName][] = $key;
                }
            }
        }

        return "protected \$metadata = " . var_export($metaData, true) . ";\nprotected \$metadataService = " . var_export($metaDataService, true) . ";\n";
    }

private
function
generateMetaData
(
)
:
string
{
$
metaData
=
[
]
;
$
metaDataService
=
[
]
;
foreach
(
$
this
->
services
as
$
serviceName
=>
$
serviceDefinition
)
{
foreach
(
$
serviceDefinition
->
getMetaData
(
)
as
$
key
=>
$
serviceMetaData
)
{
if
(
!
isset
(
$
metaData
[
$
key
]
)
)
{
$
metaData
[
$
key
]
=
[
]
;
}
$
metaData
[
$
key
]
[
$
serviceName
]
=
$
serviceMetaData
;
// mapping for the service centered
if
(
!
isset
(
$
metaDataService
[
$
serviceName
]
)
)
{
$
metaDataService
[
$
serviceName
]
=
[
]
;
}
if
(
!
in_array
(
$
key
,
$
metaDataService
[
$
serviceName
]
)
)
{
$
metaDataService
[
$
serviceName
]
[
]
=
$
key
;
}
}
}
return
"protected \$metadata = "
.
var_export
(
$
metaData
,
true
)
.
";\nprotected \$metadataService = "
.
var_export
(
$
metaDataService
,
true
)
.
";\n"
;
}

Generate the containers parameter property

@return string


private function generateResolverTypes() : string
    {
        $types = [];

        foreach($this->services as $serviceName => $serviceDefinition)
        {
            $types[] = var_export($serviceName, true) . ' => ' . Container::RESOLVE_METHOD;
        }

        return "protected \$serviceResolverType = [" . implode(', ', $types) . "];\n";
    }

private
function
generateResolverTypes
(
)
:
string
{
$
types
=
[
]
;
foreach
(
$
this
->
services
as
$
serviceName
=>
$
serviceDefinition
)
{
$
types
[
]
=
var_export
(
$
serviceName
,
true
)
.
' => '
.
Container
::
RESOLVE_METHOD
;
}
return
"protected \$serviceResolverType = ["
.
implode
(
', '
,
$
types
)
.
"];\n"
;
}

Generate the resolver types array

@return string


private function generateResolverMappings() : string
    {
        $mappings = [];

        foreach($this->services as $serviceName => $serviceDefinition)
        {
            $mappings[] = var_export($serviceName, true) . ' => ' . var_export($this->getResolverMethodName($serviceName), true);
        }

        return "protected \$resolverMethods = [" . implode(', ', $mappings) . "];\n";
    }

private
function
generateResolverMappings
(
)
:
string
{
$
mappings
=
[
]
;
foreach
(
$
this
->
services
as
$
serviceName
=>
$
serviceDefinition
)
{
$
mappings
[
]
=
var_export
(
$
serviceName
,
true
)
.
' => '
.
var_export
(
$
this
->
getResolverMethodName
(
$
serviceName
)
,
true
)
;
}
return
"protected \$resolverMethods = ["
.
implode
(
', '
,
$
mappings
)
.
"];\n"
;
}

Generate the resolver mappings array

@return string


private function generateResolverMethods() : string
    {
        $buffer = "";

        foreach($this->services as $serviceName => $serviceDefinition)
        {
            $buffer .= "protected function " . $this->getResolverMethodName($serviceName) . "() {\n";

            $serviceClassName = $serviceDefinition->getClassName();

            if ($serviceClassName[0] !== "\\")
            {
                $serviceClassName = "\\" . $serviceClassName;
            }

            $buffer .= "\t\$instance = new " . $serviceClassName . "(". $this->generateArgumentsCode($serviceDefinition->getArguments()) .");\n";

            foreach($serviceDefinition->getMethodCalls() as list($callName, $callArguments))
            {
                $buffer .= "\t\$instance->" . $callName . '('. $this->generateArgumentsCode($callArguments) .");\n";
            }

            if (in_array($serviceName, $this->shared))
            {
                $buffer .= "\t\$this->resolvedSharedServices[" . var_export($serviceName, true) . "] = \$instance;\n";
            }

            $buffer .= "\treturn \$instance;\n";

            $buffer .= "}\n";
        }

        return $buffer;
    }

private
function
generateResolverMethods
(
)
:
string
{
$
buffer
=
""
;
foreach
(
$
this
->
services
as
$
serviceName
=>
$
serviceDefinition
)
{
$
buffer
.=
"protected function "
.
$
this
->
getResolverMethodName
(
$
serviceName
)
.
"() {\n"
;
$
serviceClassName
=
$
serviceDefinition
->
getClassName
(
)
;
if
(
$
serviceClassName
[
0
]
!==
"\\"
)
{
$
serviceClassName
=
"\\"
.
$
serviceClassName
;
}
$
buffer
.=
"\t\$instance = new "
.
$
serviceClassName
.
"("
.
$
this
->
generateArgumentsCode
(
$
serviceDefinition
->
getArguments
(
)
)
.
");\n"
;
foreach
(
$
serviceDefinition
->
getMethodCalls
(
)
as
list
(
$
callName
,
$
callArguments
)
)
{
$
buffer
.=
"\t\$instance->"
.
$
callName
.
'('
.
$
this
->
generateArgumentsCode
(
$
callArguments
)
.
");\n"
;
}
if
(
in_array
(
$
serviceName
,
$
this
->
shared
)
)
{
$
buffer
.=
"\t\$this->resolvedSharedServices["
.
var_export
(
$
serviceName
,
true
)
.
"] = \$instance;\n"
;
}
$
buffer
.=
"\treturn \$instance;\n"
;
$
buffer
.=
"}\n"
;
}
return
$
buffer
;
}

Generate the resolver methods

@return string


public static function fromToken(Token $token) : ValueNode
    {
        if (!$token->isValue())
        {
            throw new LogicalNodeException('Can only create ValueNode from a value type Token.');
        }

        return new ValueNode($token->getValue(), $token->getType());
    }

Create value node from the given token

@param Token         $token
@return ValueNode


public function setType(int $type)
    {
    	if (!in_array($type, [
            self::TYPE_STRING,
            self::TYPE_NUMBER,
            self::TYPE_BOOL_TRUE,
            self::TYPE_BOOL_FALSE,
            self::TYPE_NULL,
        ]))
        {
            throw new LogicalNodeException('Invalid value type assigned.');
        }

    	$this->type = $type;
    }

public
function
setType
(
int
$
type
)
{
if
(
!
in_array
(
$
type
,
[
self
::
TYPE_STRING
,
self
::
TYPE_NUMBER
,
self
::
TYPE_BOOL_TRUE
,
self
::
TYPE_BOOL_FALSE
,
self
::
TYPE_NULL
,
]
)
)
{
throw
new
LogicalNodeException
(
'Invalid value type assigned.'
)
;
}
$
this
->
type
=
$
type
;
}

Validate if the given type and assing it

@param int 				$type
@return void


public static function generateMap(Event $event)
    {
        // prepare the container file mapping array
        $mapping = [];

        // get all available packages
        $packages = $event->getComposer()->getRepositoryManager()->getLocalRepository()->getCanonicalPackages();

        foreach ($packages as $package)
        {
            if ($package instanceof CompletePackage)
            {
                $extra = $package->getExtra();

                if (isset($extra['container']) && !empty($extra['container']))
                {
                    foreach($extra['container'] as $containerImportName => $containerFileName)
                    {
                        // special case for the main file
                        if ($containerImportName === '@main') {
                            $containerImportName = $package->getName();
                        } else {
                            $containerImportName = $package->getName() . '/' . $containerImportName;
                        }

                        $event->getIO()->write('found <fg=blue>'. $containerImportName .'</>', true, ConsoleIO::VERBOSE);

                        // also prefix the container file with package name
                        $containerFileName = $package->getName() . '/' . $containerFileName;

                        // assign the mapping
                        $mapping[$containerImportName] = '__DIR__' . $containerFileName;
                    }
                }
            }
        }

        $mappingFilePath = $event->getComposer()->getConfig()->get('vendor-dir') . '/container_map.php';

        // define the mapping file
        $mappingFileHeader = "<?php\n\$vendorDir = __DIR__ . '/';\n\nreturn ";
        $mappingFileContent = str_replace('\'__DIR__', '$vendorDir . \'', var_export($mapping, true));

        // store it
        file_put_contents($mappingFilePath, $mappingFileHeader . $mappingFileContent . ';');

        $event->getIO()->write("<fg=green>Generated container map file</>");
    }

This method will generate a mapping file
of container files found in required composer packages.
This mapping file can be imported into a container namespace.

@param Event             $event

This method will generate a mapping file of container files found in required composer packages . This mapping file can be imported into a container namespace .