public function parseInsertTag(ReplaceInsertTagsEvent $event)
    {
        if ($event->getTag() != 'grid') {
            return;
        }

        if (TL_MODE !== 'FE') {
            $event->setHtml(sprintf('[[%s]]', $event->getRaw()));
            return;
        }

        $walker = $this->getWalker($event);

        if (!$walker) {
            return;
        }

        if ($event->getParam(3) === 'infinite' && !in_array($event->getParam(1), array('begin', 'end'))) {
            $event->setHtml($walker->column());
        } elseif (in_array($event->getParam(1), array('begin', 'walk', 'end'))) {
            $method = $event->getParam(1);
            $event->setHtml($walker->$method());
        } else {
            $event->setHtml($walker->column());
        }
    }

public function parseInsertTag ( ReplaceInsertTagsEvent $ event ) { if ( $ event -> getTag ( ) != 'grid' ) { return ; } if ( TL_MODE !== 'FE' ) { $ event -> setHtml ( sprintf ( '[[%s]]' , $ event -> getRaw ( ) ) ) ; return ; } $ walker = $ this -> getWalker ( $ event ) ; if ( ! $ walker ) { return ; } if ( $ event -> getParam ( 3 ) === 'infinite' && ! in_array ( $ event -> getParam ( 1 ) , array ( 'begin' , 'end' ) ) ) { $ event -> setHtml ( $ walker -> column ( ) ) ; } elseif ( in_array ( $ event -> getParam ( 1 ) , array ( 'begin' , 'walk' , 'end' ) ) ) { $ method = $ event -> getParam ( 1 ) ; $ event -> setHtml ( $ walker -> $ method ( ) ) ; } else { $ event -> setHtml ( $ walker -> column ( ) ) ; } }

Parse the insert tag.

@param ReplaceInsertTagsEvent $event The subscribed event.

@return void


private function getWalker(ReplaceInsertTagsEvent $event)
    {
        $identifier = $event->getParam(0);

        if (!isset(static::$walkers[$identifier])) {
            list($columnSetId, $infinite) = $this->translateParams($event);

            try {
                static::$walkers[$identifier] = new Walker(Factory::createById($columnSetId), false, $infinite);
            } catch (\Exception $e) {
                return null;
            }
        }

        return static::$walkers[$identifier];
    }

private function getWalker ( ReplaceInsertTagsEvent $ event ) { $ identifier = $ event -> getParam ( 0 ) ; if ( ! isset ( static :: $ walkers [ $ identifier ] ) ) { list ( $ columnSetId , $ infinite ) = $ this -> translateParams ( $ event ) ; try { static :: $ walkers [ $ identifier ] = new Walker ( Factory :: createById ( $ columnSetId ) , false , $ infinite ) ; } catch ( \ Exception $ e ) { return null ; } } return static :: $ walkers [ $ identifier ] ; }

Get a walker for the subscribed event.

@param ReplaceInsertTagsEvent $event The subscribed event.

@return Walker|null


private function translateParams(ReplaceInsertTagsEvent $event)
    {
        $infinite    = false;
        $columnSetId = $event->getParam(0);

        if ($event->getParam(1) === 'begin' && $event->getParam(2)) {
            $columnSetId = $event->getParam(2);

            if ($event->getParam(3)) {
                $infinite = true;
            }
        }

        return array($columnSetId, $infinite);
    }

private function translateParams ( ReplaceInsertTagsEvent $ event ) { $ infinite = false ; $ columnSetId = $ event -> getParam ( 0 ) ; if ( $ event -> getParam ( 1 ) === 'begin' && $ event -> getParam ( 2 ) ) { $ columnSetId = $ event -> getParam ( 2 ) ; if ( $ event -> getParam ( 3 ) ) { $ infinite = true ; } } return array ( $ columnSetId , $ infinite ) ; }

Translate event params.

@param ReplaceInsertTagsEvent $event The subscribed event.

@return array


private function getEncParams()
    {
        // Parametri obbligatori
        $params = array(
            'shopLogin' => $this->getShopLogin(),
            'uicCode' => $this->getCurrency(),
            'amount' => $this->getAmount(),
            'shopTransactionId' => $this->getShopTransactionID(),
        );

        return array_merge($params, $this->getOptParams());
    }

private
function
getEncParams
(
)
{
// Parametri obbligatori
$
params
=
array
(
'shopLogin'
=>
$
this
->
getShopLogin
(
)
,
'uicCode'
=>
$
this
->
getCurrency
(
)
,
'amount'
=>
$
this
->
getAmount
(
)
,
'shopTransactionId'
=>
$
this
->
getShopTransactionID
(
)
,
)
;
return
array_merge
(
$
params
,
$
this
->
getOptParams
(
)
)
;
}

Genera l'array dei parametri per l'encrypt
@return array

Genera l array dei parametri per l encrypt


private function getDecParams()
    {
        // Parametri obbligatori
        $params = array(
            'shopLogin' => $this->getShopLogin(),
            'CryptedString' => $this->getEncryptedString(),
        );

        return array_merge($params, $this->getOptParams());
    }

private
function
getDecParams
(
)
{
// Parametri obbligatori
$
params
=
array
(
'shopLogin'
=>
$
this
->
getShopLogin
(
)
,
'CryptedString'
=>
$
this
->
getEncryptedString
(
)
,
)
;
return
array_merge
(
$
params
,
$
this
->
getOptParams
(
)
)
;
}

Genera l'array dei parametri per il decrypt
@return array

Genera l array dei parametri per il decrypt


private function saveDynamicData($entity, $data)
    {
        $fields = new DynamicFields($entity);
        $fields->init($data);
        $fields->save();
    }

private function saveDynamicData ( $ entity , $ data ) { $ fields = new DynamicFields ( $ entity ) ; $ fields -> init ( $ data ) ; $ fields -> save ( ) ; }


public function valid()
    {
        $bResult = false;
        if ($this->getOption('required') == 'true') {
            $value = $this->getValue();
            if (empty($value)) {
                $this->isValid = false;
            } else {
                $bResult = true;
            }
        } else {
            $bResult = true;
        }

        return $bResult;
    }

public function valid ( ) { $ bResult = false ; if ( $ this -> getOption ( 'required' ) == 'true' ) { $ value = $ this -> getValue ( ) ; if ( empty ( $ value ) ) { $ this -> isValid = false ; } else { $ bResult = true ; } } else { $ bResult = true ; } return $ bResult ; }

Check validator with field.

@return bool


public function save()
    {
        if (isset($this->file)) {
            $fileName = $this->entityId . '_' . $this->fieldId . '.' . $this->file->getClientOriginalExtension();
            $this->value = $fileName;
            $this->file->move(public_path() . config('asgard.dynamicfield.config.files-path'), $fileName);
        }
        parent::save();
    }

public function save ( ) { if ( isset ( $ this -> file ) ) { $ fileName = $ this -> entityId . '_' . $ this -> fieldId . '.' . $ this -> file -> getClientOriginalExtension ( ) ; $ this -> value = $ fileName ; $ this -> file -> move ( public_path ( ) . config ( 'asgard.dynamicfield.config.files-path' ) , $ fileName ) ; } parent :: save ( ) ; }


public function init($default = null)
    {
        $this->request = $default;
        $locale = $this->locale;
        $entityItem = $this->entity;
        $type = $this->type;

        if (isset($locale)) {
            $entity = new Entity($entityItem->id, $entityItem->template, $locale, $type);
            $entity->init($default);
            $this->entities[$locale] = $entity;
        } else {
            $languages = LaravelLocalization::getSupportedLocales();
            foreach ($languages as $locale => $code) {
                $entity = new Entity(@$entityItem->id, @$entityItem->template, $locale, $type);
                $entity->init($default);
                $this->entities[$locale] = $entity;
            }
        }
    }

public function init ( $ default = null ) { $ this -> request = $ default ; $ locale = $ this -> locale ; $ entityItem = $ this -> entity ; $ type = $ this -> type ; if ( isset ( $ locale ) ) { $ entity = new Entity ( $ entityItem -> id , $ entityItem -> template , $ locale , $ type ) ; $ entity -> init ( $ default ) ; $ this -> entities [ $ locale ] = $ entity ; } else { $ languages = LaravelLocalization :: getSupportedLocales ( ) ; foreach ( $ languages as $ locale => $ code ) { $ entity = new Entity ( @ $ entityItem -> id , @ $ entityItem -> template , $ locale , $ type ) ; $ entity -> init ( $ default ) ; $ this -> entities [ $ locale ] = $ entity ; } } }


public function renderFields($locale)
    {
        $entity = $this->entities[$locale];
        if (isset($this->request)) {
            $entity->valid();
        }

        $html = $entity->render();

        return $html;
    }

public function renderFields ( $ locale ) { $ entity = $ this -> entities [ $ locale ] ; if ( isset ( $ this -> request ) ) { $ entity -> valid ( ) ; } $ html = $ entity -> render ( ) ; return $ html ; }

Render by locale.

@param $locale

@return mixed


public function getFieldValue($fieldName, $locale = 'en')
    {
        $strValue = '';
        $entity = $this->entities[$locale];
        $values = $entity->values();
        if (count($values)) {
            $keys = array_keys($values);
            if (in_array($fieldName, $keys)) {
                $strValue = $values[$fieldName];
            }
        }

        return $strValue;
    }

public function getFieldValue ( $ fieldName , $ locale = 'en' ) { $ strValue = '' ; $ entity = $ this -> entities [ $ locale ] ; $ values = $ entity -> values ( ) ; if ( count ( $ values ) ) { $ keys = array_keys ( $ values ) ; if ( in_array ( $ fieldName , $ keys ) ) { $ strValue = $ values [ $ fieldName ] ; } } return $ strValue ; }

Get field data.

@param $fieldName
@param string $locale

@return string


public function getFieldValues($locale = 'en')
    {
        $entity = $this->entities[$locale];
        $values = $entity->values();

        return $values;
    }

public function getFieldValues ( $ locale = 'en' ) { $ entity = $ this -> entities [ $ locale ] ; $ values = $ entity -> values ( ) ; return $ values ; }

Get list fields data.

@param string $locale

@return mixed


public function valid()
    {
        $isValid = true;

        foreach ($this->entities as $entity) {
            $isValid = $entity->valid();
            if (!$isValid) {
                break;
            }
        }

        return $isValid;
    }

public function valid ( ) { $ isValid = true ; foreach ( $ this -> entities as $ entity ) { $ isValid = $ entity -> valid ( ) ; if ( ! $ isValid ) { break ; } } return $ isValid ; }


public function save()
    {
        $isSave = true;
        foreach ($this->entities as $entity) {
            $isSave = $entity->save();
            if (!$isSave) {
                break;
            }
        }

        return $isSave;
    }

public function save ( ) { $ isSave = true ; foreach ( $ this -> entities as $ entity ) { $ isSave = $ entity -> save ( ) ; if ( ! $ isSave ) { break ; } } return $ isSave ; }


private function assignDynamicFieldsToPageObject($view)
    {
        $entityDynamic  = null;
        $data    = $view->getData();
        //TODO Fix with event
        if (count($data)) {
            $arrType = config('asgard.dynamicfield.config.entity-type');
            $arrType =  array_keys($arrType);
            // edit entity
            foreach ($data as $item) {
                if (is_object($item)) {
                    $className = get_class($item);
                    if (in_array($className, $arrType)) {
                        $entityDynamic = $item;
                        break;
                    }
                }
            }
        }
        // initial model data for create new;
        if (is_null($entityDynamic)) {
            $router    = \Request::route()->getName();
            $arrCreateRouter    = config('asgard.dynamicfield.config.router');
            if (array_key_exists($router, $arrCreateRouter)) {
                $entityDynamic = new $arrCreateRouter[$router];
            }
        }
        $view->with('entityDynamic', $entityDynamic);

        return $view;
    }

Pass dynamicFields to view

@param $view
@return mixed


public function getFieldByLocale($locale = 'en')
    {
        $fields = $this->fields()->where('locale', $locale)->get();
        if ($fields->count()) {
            $object = $fields[0];
        } else {
            $object = new FieldTranslation();
        }

        return $object;
    }

public function getFieldByLocale ( $ locale = 'en' ) { $ fields = $ this -> fields ( ) -> where ( 'locale' , $ locale ) -> get ( ) ; if ( $ fields -> count ( ) ) { $ object = $ fields [ 0 ] ; } else { $ object = new FieldTranslation ( ) ; } return $ object ; }

Get list fields by locale.

@param string $locale

@return FieldTranslation


public function getRepeatersByLocale($locale)
    {
        $repeaters = $this->repeaters()
                            ->where('locale', $locale)
                            ->orderBy('order')
                            ->get();

        return $repeaters;
    }

public function getRepeatersByLocale ( $ locale ) { $ repeaters = $ this -> repeaters ( ) -> where ( 'locale' , $ locale ) -> orderBy ( 'order' ) -> get ( ) ; return $ repeaters ; }

Get list repeater field by locale.

@param $locale

@return mixed


public function getEntitiesByFieldId($fieldId)
    {
        $values = $this->where('field_id', $fieldId)->get();
        if ($values->count()) {
            $object = $values[0];
        } else {
            $object = new self();
        }

        return $object;
    }

public function getEntitiesByFieldId ( $ fieldId ) { $ values = $ this -> where ( 'field_id' , $ fieldId ) -> get ( ) ; if ( $ values -> count ( ) ) { $ object = $ values [ 0 ] ; } else { $ object = new self ( ) ; } return $ object ; }

Get entities by fieldID.

@param $fieldId

@return Entity


public function scopeGetEntity($query, $entityId, $entityType, $fieldId)
    {
        $entities = $query->where('entity_id', $entityId)
                        ->where('entity_type', $entityType)
                        ->where('field_id', $fieldId)->get();
        if ($entities->count()) {
            $object = $entities[0];
        } else {
            $object = new self();
        }

        return $object;
    }

public function scopeGetEntity ( $ query , $ entityId , $ entityType , $ fieldId ) { $ entities = $ query -> where ( 'entity_id' , $ entityId ) -> where ( 'entity_type' , $ entityType ) -> where ( 'field_id' , $ fieldId ) -> get ( ) ; if ( $ entities -> count ( ) ) { $ object = $ entities [ 0 ] ; } else { $ object = new self ( ) ; } return $ object ; }

Find entities by entityID,type and fieldId.

@param $query
@param $entityId
@param $entityType
@param $fieldId

@return Entity

Find entities by entityID type and fieldId .


public function duplicate($pageId = 0)
    {
        $entity = $this->replicate();
        $entity->entity_id = $pageId;
        $entity->save();
        $type = $this->getFieldType();
        if ($type != 'repeater') {
            $fields = $this->Fields;

            foreach ($fields as $translation) {
                $tranReplicate = $translation->replicate();
                $tranReplicate->entity_field_id = $entity->id;
                $tranReplicate->save();
            }
        } else {
            $repeaters = $this->Repeaters;

            foreach ($repeaters as $repeater) {
                $fields = $repeater->FieldValues;

                $repeaterReplicate = $repeater->replicate();
                $repeaterReplicate->entity_repeater_id = $entity->id;
                $repeaterReplicate->save();
                foreach ($fields as $translation) {
                    $tranReplicate = $translation->replicate();
                    $tranReplicate->translation_id = $repeaterReplicate->id;
                    $tranReplicate->save();
                }
            }
        }

        return $entity;
    }

public function duplicate ( $ pageId = 0 ) { $ entity = $ this -> replicate ( ) ; $ entity -> entity_id = $ pageId ; $ entity -> save ( ) ; $ type = $ this -> getFieldType ( ) ; if ( $ type != 'repeater' ) { $ fields = $ this -> Fields ; foreach ( $ fields as $ translation ) { $ tranReplicate = $ translation -> replicate ( ) ; $ tranReplicate -> entity_field_id = $ entity -> id ; $ tranReplicate -> save ( ) ; } } else { $ repeaters = $ this -> Repeaters ; foreach ( $ repeaters as $ repeater ) { $ fields = $ repeater -> FieldValues ; $ repeaterReplicate = $ repeater -> replicate ( ) ; $ repeaterReplicate -> entity_repeater_id = $ entity -> id ; $ repeaterReplicate -> save ( ) ; foreach ( $ fields as $ translation ) { $ tranReplicate = $ translation -> replicate ( ) ; $ tranReplicate -> translation_id = $ repeaterReplicate -> id ; $ tranReplicate -> save ( ) ; } } } return $ entity ; }

Duplicate field of page.

@param int $pageId

@return Model


public function init($default = null)
    {
        //getGroupByRule
        $options['type'] = $this->type;
        $options['template'] = $this->template;
        $groups = $this->getGroupByRule($options);

        if (count($groups)) {
            foreach ($groups as $groupId) {
                $group = Group::find($groupId);
                $this->initGroup($group, $default);
            }
        }
    }

public function init ( $ default = null ) { //getGroupByRule $ options [ 'type' ] = $ this -> type ; $ options [ 'template' ] = $ this -> template ; $ groups = $ this -> getGroupByRule ( $ options ) ; if ( count ( $ groups ) ) { foreach ( $ groups as $ groupId ) { $ group = Group :: find ( $ groupId ) ; $ this -> initGroup ( $ group , $ default ) ; } } }

Get and inital group data that match with rule.

@param null $default

Get and inital group data that match with rule .


public function valid()
    {
        $isValid = true;

        if (count($this->groupFields)) {
            foreach ($this->groupFields as $group) {
                $fields = $group['fields'];
                foreach ($fields as $field) {
                    $isValid = $field->valid();
                    if (!$isValid) {
                        break;
                    }
                }
            }
        }

        return $isValid;
    }

public function valid ( ) { $ isValid = true ; if ( count ( $ this -> groupFields ) ) { foreach ( $ this -> groupFields as $ group ) { $ fields = $ group [ 'fields' ] ; foreach ( $ fields as $ field ) { $ isValid = $ field -> valid ( ) ; if ( ! $ isValid ) { break ; } } } } return $ isValid ; }

Check validation of field.

@return bool


public function render()
    {
        $html = '';

        if (count($this->groupFields)) {
            foreach ($this->groupFields as $group) {
                $htmlControl = '';
                $fields = $group['fields'];

                foreach ($fields as $field) {
                    $htmlControl .= $field->render();
                }
                $label = $group['name'];
                $html .= sprintf($this->htmlItemTemplate, $label, $htmlControl);
            }
        }

        return $html;
    }

public function render ( ) { $ html = '' ; if ( count ( $ this -> groupFields ) ) { foreach ( $ this -> groupFields as $ group ) { $ htmlControl = '' ; $ fields = $ group [ 'fields' ] ; foreach ( $ fields as $ field ) { $ htmlControl .= $ field -> render ( ) ; } $ label = $ group [ 'name' ] ; $ html .= sprintf ( $ this -> htmlItemTemplate , $ label , $ htmlControl ) ; } } return $ html ; }


public function save()
    {
        $bResult = false;
        try {
            if (count($this->groupFields)) {
                foreach ($this->groupFields as $group) {
                    $fields = $group['fields'];
                    foreach ($fields as $field) {
                        $field->save();
                    }
                }
            }
            $bResult = true;
        } catch (\Exception $e) {
            //exception handling
        }

        return $bResult;
    }

public
function
save
(
)
{
$
bResult
=
false
;
try
{
if
(
count
(
$
this
->
groupFields
)
)
{
foreach
(
$
this
->
groupFields
as
$
group
)
{
$
fields
=
$
group
[
'fields'
]
;
foreach
(
$
fields
as
$
field
)
{
$
field
->
save
(
)
;
}
}
}
$
bResult
=
true
;
}
catch
(
\
Exception
$
e
)
{
//exception handling
}
return
$
bResult
;
}


public function getGroupByRule($options)
    {
        $arrResult = array();
        $rules = Rule::all();

        foreach ($rules as $rule) {
            $params = (array) json_decode($rule->rule);
            $defaultMatch = true;
            foreach ($params as $item) {
                $match = $this->matchRule((array) $item, $options);
                $defaultMatch = $defaultMatch && $match;
            }
            if ($defaultMatch) {
                $arrResult[$rule->group_id] = $rule->group_id;
            }
        }

        return $arrResult;
    }

public function getGroupByRule ( $ options ) { $ arrResult = array ( ) ; $ rules = Rule :: all ( ) ; foreach ( $ rules as $ rule ) { $ params = ( array ) json_decode ( $ rule -> rule ) ; $ defaultMatch = true ; foreach ( $ params as $ item ) { $ match = $ this -> matchRule ( ( array ) $ item , $ options ) ; $ defaultMatch = $ defaultMatch && $ match ; } if ( $ defaultMatch ) { $ arrResult [ $ rule -> group_id ] = $ rule -> group_id ; } } return $ arrResult ; }

Get GroupFields base on rule.

@param $options

@return array


private function matchRule($rule, $options)
    {
        $match = false;
        $type = array_get($rule, 'parameter', 'type');
        $operator = array_get($rule, 'operator', 'equal');
        $value = array_get($rule, 'value', 'default');

        if ($operator == 'equal') {
            $match = ($value === $options[$type]);
        } elseif ($operator == 'notequal') {
            $match = ($value !== $options[$type]);
        }

        return $match;
    }

private function matchRule ( $ rule , $ options ) { $ match = false ; $ type = array_get ( $ rule , 'parameter' , 'type' ) ; $ operator = array_get ( $ rule , 'operator' , 'equal' ) ; $ value = array_get ( $ rule , 'value' , 'default' ) ; if ( $ operator == 'equal' ) { $ match = ( $ value === $ options [ $ type ] ) ; } elseif ( $ operator == 'notequal' ) { $ match = ( $ value !== $ options [ $ type ] ) ; } return $ match ; }

Parse and Match rule with options.

@param $rule
@param $options

@return bool


private function initGroup($group, $default = null)
    {
        $groupId = $group->id;
        $groupName = $group->name;
        $fields = $group->getListFields();

        $fieldData = $this->getFieldPostData($default);
        $controls = array();
        if ($fields->count()) {
            $this->fieldInDB = EntityModel::getAllDataFields($this->entityId, $this->type);

            $controls['name'] = $groupName;
            foreach ($fields as $field) {
                $fieldValue = @$fieldData['fields'][$field->id];
                $fieldControl = null;
                $dbData = $this->getFieldDataInDB($field->id, $this->locale);

                switch ($field->type) {
                    case 'text':
                        $fieldControl = new Text($field, $this->entityId, $this->locale, $dbData);
                        break;
                    case 'number':
                        $fieldControl = new Number($field, $this->entityId, $this->locale, $dbData);
                        break;
                    case 'textarea':
                        $fieldControl = new Textarea($field, $this->entityId, $this->locale, $dbData);
                        break;
                    case 'wysiwyg':
                        $fieldControl = new Wysiwyg($field, $this->entityId, $this->locale, $dbData);
                        break;
                    case 'file':
                        $fieldControl = new File($field, $this->entityId, $this->locale, $dbData);
                        break;
                    case 'image':
                        $fieldControl = new Image($field, $this->entityId, $this->locale, $dbData);
                        break;
                    case 'repeater':
                        $fieldControl = new Repeater($field, $this->entityId, $this->locale, $dbData);
                        break;
                }

                // assign entity type class to field to use for save data;
                $fieldControl->setEntityType($this->type);
                $fieldControl->init($fieldValue);
                $controls['fields'][$field->id] = $fieldControl;
                $this->fieldValues[$field->name] = $fieldControl->getDisplayValue();
            }
            $this->groupFields[$groupId] = $controls;
        }
    }

Initial fields of each group and assign to GroupFields array.

@param $group
@param null $default

Initial fields of each group and assign to GroupFields array .


private function getFieldPostData($data)
    {
        $arrData = array();

        if (isset($data)) {
            $arrData = @$data[$this->locale];
        }

        return $arrData;
    }

private function getFieldPostData ( $ data ) { $ arrData = array ( ) ; if ( isset ( $ data ) ) { $ arrData = @ $ data [ $ this -> locale ] ; } return $ arrData ; }

Get field of data in browser.

@param $data

@return array


public function set($x, $y) {
        list($x, $y, $px, $py) = $this->prime($x, $y);
        $this->chars[$py][$px] |= $this->getDotFromMap($x, $y);
    }

public function set ( $ x , $ y ) { list ( $ x , $ y , $ px , $ py ) = $ this -> prime ( $ x , $ y ) ; $ this -> chars [ $ py ] [ $ px ] |= $ this -> getDotFromMap ( $ x , $ y ) ; }

Sets a pixel at the given position

@param integer $x x position
@param integer $y y position


public function get($x, $y) {
        list($x, $y, , , $char) = $this->prime($x, $y);
        return (bool) ($char & $this->getDotFromMap($x, $y));
    }

public function get ( $ x , $ y ) { list ( $ x , $ y , , , $ char ) = $ this -> prime ( $ x , $ y ) ; return ( bool ) ( $ char & $ this -> getDotFromMap ( $ x , $ y ) ) ; }

Gets the pixel state at a given position

@param integer $x x position
@param integer $y y position

@return bool the pixel state


public function row($y, array $options = []) {
        $row = isset($this->chars[$y]) ? $this->chars[$y] : [];

        if (!isset($options['min_x']) || !isset($options['max_x'])) {
            if (!($keys = array_keys($row))) {
                return '';
            }
        }

        $min = isset($options['min_x']) ? $options['min_x'] : min($keys);
        $max = isset($options['max_x']) ? $options['max_x'] : max($keys);

        return array_reduce(range($min, $max), function ($carry, $item) use ($row) {
            return $carry .= $this->toBraille(isset($row[$item]) ? $row[$item] : 0);
        }, '');
    }

public function row ( $ y , array $ options = [ ] ) { $ row = isset ( $ this -> chars [ $ y ] ) ? $ this -> chars [ $ y ] : [ ] ; if ( ! isset ( $ options [ 'min_x' ] ) || ! isset ( $ options [ 'max_x' ] ) ) { if ( ! ( $ keys = array_keys ( $ row ) ) ) { return '' ; } } $ min = isset ( $ options [ 'min_x' ] ) ? $ options [ 'min_x' ] : min ( $ keys ) ; $ max = isset ( $ options [ 'max_x' ] ) ? $ options [ 'max_x' ] : max ( $ keys ) ; return array_reduce ( range ( $ min , $ max ) , function ( $ carry , $ item ) use ( $ row ) { return $ carry .= $ this -> toBraille ( isset ( $ row [ $ item ] ) ? $ row [ $ item ] : 0 ) ; } , '' ) ; }

Gets a line

@param integer $y     y position
@param array $options options

@return string line


public function rows(array $options = []) {
        if (!isset($options['min_y']) || !isset($options['max_y'])) {
            if (!($keys = array_keys($this->chars))) {
                return [];
            }
        }

        $min = isset($options['min_y']) ? $options['min_y'] : min($keys);
        $max = isset($options['max_y']) ? $options['max_y'] : max($keys);

        if (!isset($options['min_x']) || !isset($options['max_x'])) {
            $flattened = array();
            foreach ($this->chars as $key => $char) {
                $flattened = array_merge($flattened, array_keys($char));
            }
        }

        $options['min_x'] = isset($options['min_x']) ? $options['min_x'] : min($flattened);
        $options['max_x'] = isset($options['max_x']) ? $options['max_x'] : max($flattened);

        return array_map(function ($i) use ($options) {
            return $this->row($i, $options);
        }, range($min, $max));
    }

public function rows ( array $ options = [ ] ) { if ( ! isset ( $ options [ 'min_y' ] ) || ! isset ( $ options [ 'max_y' ] ) ) { if ( ! ( $ keys = array_keys ( $ this -> chars ) ) ) { return [ ] ; } } $ min = isset ( $ options [ 'min_y' ] ) ? $ options [ 'min_y' ] : min ( $ keys ) ; $ max = isset ( $ options [ 'max_y' ] ) ? $ options [ 'max_y' ] : max ( $ keys ) ; if ( ! isset ( $ options [ 'min_x' ] ) || ! isset ( $ options [ 'max_x' ] ) ) { $ flattened = array ( ) ; foreach ( $ this -> chars as $ key => $ char ) { $ flattened = array_merge ( $ flattened , array_keys ( $ char ) ) ; } } $ options [ 'min_x' ] = isset ( $ options [ 'min_x' ] ) ? $ options [ 'min_x' ] : min ( $ flattened ) ; $ options [ 'max_x' ] = isset ( $ options [ 'max_x' ] ) ? $ options [ 'max_x' ] : max ( $ flattened ) ; return array_map ( function ( $ i ) use ( $ options ) { return $ this -> row ( $ i , $ options ) ; } , range ( $ min , $ max ) ) ; }

Gets all lines

@param array $options options

@return array line


private function getDotFromMap($x, $y) {
        $y = $y % 4;
        $x = $x % 2;

        return self::$pixel_map[$y < 0 ? 4 + $y : $y][$x < 0 ? 2 + $x : $x];
    }

private function getDotFromMap ( $ x , $ y ) { $ y = $ y % 4 ; $ x = $ x % 2 ; return self :: $ pixel_map [ $ y < 0 ? 4 + $ y : $ y ] [ $ x < 0 ? 2 + $ x : $ x ] ; }

Gets a dot from the pixel map.

@param integer $x x position
@param integer $y y position

@return integer dot


private function prime($x, $y) {
        $x = round($x);
        $y = round($y);
        $px = floor($x / 2);
        $py = floor($y / 4);

        if (!isset($this->chars[$py][$px])) {
            $this->chars[$py][$px] = 0;
        }

        return [$x, $y, $px, $py, $this->chars[$py][$px]];
    }

private function prime ( $ x , $ y ) { $ x = round ( $ x ) ; $ y = round ( $ y ) ; $ px = floor ( $ x / 2 ) ; $ py = floor ( $ y / 4 ) ; if ( ! isset ( $ this -> chars [ $ py ] [ $ px ] ) ) { $ this -> chars [ $ py ] [ $ px ] = 0 ; } return [ $ x , $ y , $ px , $ py , $ this -> chars [ $ py ] [ $ px ] ] ; }

Autovivification for a canvas position.

@param integer $x x position
@param integer $y y position

@return array

Autovivification for a canvas position .


private function initRepeatFields($fieldInfo, $default = null)
    {
        $controls = array();
        $repeaterId = $fieldInfo->id;
        $entity = Entity::getEntity($this->entityId, $this->entityType, $repeaterId);
        $repeaters = Entity::getAllDataTranactionRepeater($this->entityId, $this->entityType, $repeaterId, $this->locale);
        $this->repeaterFieldData = Entity::getAllDataTranactionRepeaterFields($this->entityId, $this->entityType, $repeaterId, $this->locale);
        $post_data = @$default['value'];
        $this->defaultOrder = @$default['order'];
        $repeater_field = $this->field;
        $fieldOfRepeater = $repeater_field->getListFields();
        if (isset($post_data)) {
            unset($post_data['clone']);
            $this->deleteItems = $default['delete'];

            foreach ($post_data as $k => $control) {
                $listDefault = $post_data[$k];
                $controls[$k]['fields'] = $this->createListControlAfterPostData($k, $listDefault, $fieldOfRepeater);
                $controls[$k]['order'] = -1;
            }
        } else {
            if (count($repeaters)) {
                $i = 1;

                foreach ($repeaters as $repeater) {
                    $controls[$repeater->id]['fields'] = $this->createListControl($repeater, $fieldOfRepeater);
                    $controls[$repeater->id]['order'] = $i;
                    ++$i;
                }
            }
        }

        $this->groupFields = $controls;

        $this->repeaterHeaders = $this->createHeaderRepeater($fieldOfRepeater);
    }

private function initRepeatFields ( $ fieldInfo , $ default = null ) { $ controls = array ( ) ; $ repeaterId = $ fieldInfo -> id ; $ entity = Entity :: getEntity ( $ this -> entityId , $ this -> entityType , $ repeaterId ) ; $ repeaters = Entity :: getAllDataTranactionRepeater ( $ this -> entityId , $ this -> entityType , $ repeaterId , $ this -> locale ) ; $ this -> repeaterFieldData = Entity :: getAllDataTranactionRepeaterFields ( $ this -> entityId , $ this -> entityType , $ repeaterId , $ this -> locale ) ; $ post_data = @ $ default [ 'value' ] ; $ this -> defaultOrder = @ $ default [ 'order' ] ; $ repeater_field = $ this -> field ; $ fieldOfRepeater = $ repeater_field -> getListFields ( ) ; if ( isset ( $ post_data ) ) { unset ( $ post_data [ 'clone' ] ) ; $ this -> deleteItems = $ default [ 'delete' ] ; foreach ( $ post_data as $ k => $ control ) { $ listDefault = $ post_data [ $ k ] ; $ controls [ $ k ] [ 'fields' ] = $ this -> createListControlAfterPostData ( $ k , $ listDefault , $ fieldOfRepeater ) ; $ controls [ $ k ] [ 'order' ] = - 1 ; } } else { if ( count ( $ repeaters ) ) { $ i = 1 ; foreach ( $ repeaters as $ repeater ) { $ controls [ $ repeater -> id ] [ 'fields' ] = $ this -> createListControl ( $ repeater , $ fieldOfRepeater ) ; $ controls [ $ repeater -> id ] [ 'order' ] = $ i ; ++ $ i ; } } } $ this -> groupFields = $ controls ; $ this -> repeaterHeaders = $ this -> createHeaderRepeater ( $ fieldOfRepeater ) ; }

Set data per group.

@param $fieldInfo
@param null $default


private function createListControlAfterPostData($repeaterId, $default = null, $fieldOfRepeater)
    {
        $controls = array();
        $nameFormat = '%s[fields]' . sprintf('[%s][value][%s]', $this->getFieldId(), $repeaterId) . '[%s][value]';
        $idFormat = '%s_' . sprintf('%s_%s_', $this->getFieldId(), $repeaterId) . '_%s_value';

        if ($fieldOfRepeater->count()) {
            foreach ($fieldOfRepeater as $field) {
                $listDefault = $default[$field->id];
                $fieldControl = $this->createFieldControl($field, $repeaterId, $listDefault);
                $fieldControl->setHtmlNameFormat($nameFormat);
                $fieldControl->setHtmlIdFormat($idFormat);
                $controls[$field->id] = $fieldControl;
            }
        }

        return $controls;
    }

private function createListControlAfterPostData ( $ repeaterId , $ default = null , $ fieldOfRepeater ) { $ controls = array ( ) ; $ nameFormat = '%s[fields]' . sprintf ( '[%s][value][%s]' , $ this -> getFieldId ( ) , $ repeaterId ) . '[%s][value]' ; $ idFormat = '%s_' . sprintf ( '%s_%s_' , $ this -> getFieldId ( ) , $ repeaterId ) . '_%s_value' ; if ( $ fieldOfRepeater -> count ( ) ) { foreach ( $ fieldOfRepeater as $ field ) { $ listDefault = $ default [ $ field -> id ] ; $ fieldControl = $ this -> createFieldControl ( $ field , $ repeaterId , $ listDefault ) ; $ fieldControl -> setHtmlNameFormat ( $ nameFormat ) ; $ fieldControl -> setHtmlIdFormat ( $ idFormat ) ; $ controls [ $ field -> id ] = $ fieldControl ; } } return $ controls ; }

create list controller when user post data from browser.

@param $repeaterId
@param null $default

@return array

create list controller when user post data from browser .


private function createListControl($repeater, $fieldOfRepeater)
    {
        $nameFormat = '%s[fields]' . sprintf('[%s][value][%s]', $this->getFieldId(), $repeater->id) . '[%s][value]';
        $idFormat = '%s_' . sprintf('%s_%s_', $this->getFieldId(), $repeater->id) . '_%s_value';

        if ($fieldOfRepeater->count()) {
            foreach ($fieldOfRepeater as $field) {
                $dbData = $this->getFieldDataInDB($field->id, $repeater->id);
                $fieldControl = $this->createFieldControl($field, $repeater->id);
                $fieldControl->setHtmlItemTemplate('%s');
                $fieldControl->setHtmlNameFormat($nameFormat);
                $fieldControl->setHtmlIdFormat($idFormat);

               // $value = $repeater->getFieldValue($field->id);
                $fieldControl->setValue($dbData);

                $controls[$field->id] = $fieldControl;
            }
        }

        return $controls;
    }

Set list control of repeater.

@param $repeater

@return mixed


private function createFieldControl($field, $translateId, $default = null)
    {
        $fieldControl = null;
        $fieldValue = $default;
        switch ($field->type) {
            case 'text':
                $fieldControl = new Text($field, $this->entityId, $this->locale);
                break;
            case 'number':
                $fieldControl = new Number($field, $this->entityId, $this->locale);
                break;
            case 'textarea':
                $fieldControl = new Textarea($field, $this->entityId, $this->locale);
                break;
            case 'wysiwyg':
                $fieldControl = new Wysiwyg($field, $this->entityId, $this->locale);
                break;
            case 'file':
                $fieldControl = new File($field, $this->entityId, $this->locale);
                break;
            case 'image':
                $fieldControl = new Image($field, $this->entityId, $this->locale);
                break;
        }
        // assign entity type class to field to use for save data;
        $fieldControl->setEntityType($this->entityType);
        $fieldControl->setRepeaterId($this->fieldId);
        $fieldControl->setTranslateId($translateId);

        $fieldControl->init($fieldValue);

        return $fieldControl;
    }

Set field control data.

@param $field
@param $translateId
@param null $default

@return File|Image|Number|Text|Textarea|Wysiwyg|null


private function createHeaderRepeater($fieldOfRepeater)
    {
        $repeater = new RepeaterTranslation();
        //TODO Here was ='clone'
        $repeater->id = 'clone';
        $controls = $this->createListControl($repeater, $fieldOfRepeater);

        return $controls;
    }

private
function
createHeaderRepeater
(
$
fieldOfRepeater
)
{
$
repeater
=
new
RepeaterTranslation
(
)
;
//TODO Here was ='clone'
$
repeater
->
id
=
'clone'
;
$
controls
=
$
this
->
createListControl
(
$
repeater
,
$
fieldOfRepeater
)
;
return
$
controls
;
}


public function save()
    {
        $bResult = false;
        try {
            if (!empty($this->deleteItems)) {
                $items = explode(',', $this->deleteItems);
                RepeaterTranslation::destroy($items);
            }
            if (count($this->groupFields)) {
                foreach ($this->groupFields as $groupId => $group) {
                    $fields = $group['fields'];
                    $order = $this->defaultOrder[$groupId];

                    $translate_id = 0;
                    foreach ($fields as $field) {
                        if ($translate_id) {
                            $field->setTranslateId($translate_id);
                        }
                        $field->save();
                        $translate_id = $field->getTranslateId();
                    }
                     // update order
                     $translate = RepeaterTranslation::find($translate_id);
                    $translate->order = $order;
                    $translate->save();
                }
            }
            $bResult = true;
        } catch (\Exception $e) {
            //exception handling
        }

        return $bResult;
    }

public
function
save
(
)
{
$
bResult
=
false
;
try
{
if
(
!
empty
(
$
this
->
deleteItems
)
)
{
$
items
=
explode
(
','
,
$
this
->
deleteItems
)
;
RepeaterTranslation
::
destroy
(
$
items
)
;
}
if
(
count
(
$
this
->
groupFields
)
)
{
foreach
(
$
this
->
groupFields
as
$
groupId
=>
$
group
)
{
$
fields
=
$
group
[
'fields'
]
;
$
order
=
$
this
->
defaultOrder
[
$
groupId
]
;
$
translate_id
=
0
;
foreach
(
$
fields
as
$
field
)
{
if
(
$
translate_id
)
{
$
field
->
setTranslateId
(
$
translate_id
)
;
}
$
field
->
save
(
)
;
$
translate_id
=
$
field
->
getTranslateId
(
)
;
}
// update order
$
translate
=
RepeaterTranslation
::
find
(
$
translate_id
)
;
$
translate
->
order
=
$
order
;
$
translate
->
save
(
)
;
}
}
$
bResult
=
true
;
}
catch
(
\
Exception
$
e
)
{
//exception handling
}
return
$
bResult
;
}

Save field data to database.

@return bool


public function getDisplayValue()
    {
        $values = array();

        if (count($this->groupFields)) {
            $i = 0;
            foreach ($this->groupFields as $key => $group) {
                $fields = $group['fields'];
                $item = array();
                foreach ($fields as $field) {
                    $item[$field->getFieldName()] = $field->getDisplayValue();
                }
                $item['id'] = $key;
                $values[$i] = $item;
                ++$i;
            }
        }

        return $values;
    }

public function getDisplayValue ( ) { $ values = array ( ) ; if ( count ( $ this -> groupFields ) ) { $ i = 0 ; foreach ( $ this -> groupFields as $ key => $ group ) { $ fields = $ group [ 'fields' ] ; $ item = array ( ) ; foreach ( $ fields as $ field ) { $ item [ $ field -> getFieldName ( ) ] = $ field -> getDisplayValue ( ) ; } $ item [ 'id' ] = $ key ; $ values [ $ i ] = $ item ; ++ $ i ; } } return $ values ; }


public function getFieldValue($fieldId)
    {
        $object = new RepeaterValue();
        if (is_numeric($this->id)) {
            $repeatValues = $this->fieldValues()->where('field_id', $fieldId)->get();
            if ($repeatValues->count()) {
                $object = $repeatValues[0];
            }
        }

        return $object;
    }

public function getFieldValue ( $ fieldId ) { $ object = new RepeaterValue ( ) ; if ( is_numeric ( $ this -> id ) ) { $ repeatValues = $ this -> fieldValues ( ) -> where ( 'field_id' , $ fieldId ) -> get ( ) ; if ( $ repeatValues -> count ( ) ) { $ object = $ repeatValues [ 0 ] ; } } return $ object ; }

Get repeater data by fieldId.

@param $fieldId

@return RepeaterValue


private function getTemplateName($template)
    {
        preg_match('/{{-- Template: (.*) --}}/', $template->getContents(), $templateName);

        if (count($templateName) > 1) {
            return $templateName[1];
        }

        return $this->getDefaultTemplateName($template);
    }

private
function
getTemplateName
(
$
template
)
{
preg_match
(
'/{{-- Template: (.*) --}}/'
,
$
template
->
getContents
(
)
,
$
templateName
)
;
if
(
count
(
$
templateName
)
>
1
)
{
return
$
templateName
[
1
]
;
}
return
$
this
->
getDefaultTemplateName
(
$
template
)
;
}

Read template name defined in comments.

@param $template

@return string

Read template name defined in comments .


private function getDefaultTemplateName($template)
    {
        $relativePath = $template->getRelativePath();
        $fileName = $this->removeExtensionsFromFilename($template);

        return $this->hasSubdirectory($relativePath) ? $relativePath . '/' . $fileName : $fileName;
    }

private function getDefaultTemplateName ( $ template ) { $ relativePath = $ template -> getRelativePath ( ) ; $ fileName = $ this -> removeExtensionsFromFilename ( $ template ) ; return $ this -> hasSubdirectory ( $ relativePath ) ? $ relativePath . '/' . $ fileName : $ fileName ; }

If the template name is not defined in comments, build a default.

@param $template

@return mixed

If the template name is not defined in comments build a default .


public function init($default = null)
    {
        //$this->model = $this->getModel();
        if (!isset($default)) {
            //$this->value = $this->model->value;
            if (empty($this->dataInDB)) {
                $this->value = $this->getOption('default');
            } else {
                $this->value =  $this->dataInDB;
            }
        } else {
            $this->value = $default['value'];
        }
    }

public
function
init
(
$
default
=
)
{
//$this->model = $this->getModel();
if
(
!
isset
(
$
default
)
)
{
//$this->value = $this->model->value;
if
(
empty
(
$
this
->
dataInDB
)
)
{
$
this
->
value
=
$
this
->
getOption
(
'default'
)
;
}
else
{
$
this
->
value
=
$
this
->
dataInDB
;
}
}
else
{
$
this
->
value
=
$
default
[
'value'
]
;
}
}

Set model and value.

@param null $default


public function getModel()
    {
        if (is_a($this->field, 'Modules\Dynamicfield\Entities\Field')) {
            $entity = Entity::getEntity($this->entityId, $this->entityType, $this->fieldId);
            $model = $entity->getFieldByLocale($this->locale);
        } else {
            $model = new RepeaterValue();
            if (is_numeric($this->translationId)) {
                $repeaterTranslate = RepeaterTranslation::firstOrNew(array('id' => $this->translationId));
                $model = $repeaterTranslate->getFieldValue($this->fieldId);
            }
        }

        return $model;
    }

public function getModel ( ) { if ( is_a ( $ this -> field , 'Modules\Dynamicfield\Entities\Field' ) ) { $ entity = Entity :: getEntity ( $ this -> entityId , $ this -> entityType , $ this -> fieldId ) ; $ model = $ entity -> getFieldByLocale ( $ this -> locale ) ; } else { $ model = new RepeaterValue ( ) ; if ( is_numeric ( $ this -> translationId ) ) { $ repeaterTranslate = RepeaterTranslation :: firstOrNew ( array ( 'id' => $ this -> translationId ) ) ; $ model = $ repeaterTranslate -> getFieldValue ( $ this -> fieldId ) ; } } return $ model ; }

Get Entity or RepeaterTranslation model by locale.

@return RepeaterValue

Get Entity or RepeaterTranslation model by locale .


public function getHtmlId()
    {
        $strHtmlId = sprintf($this->htmlIdFormat, $this->locale, $this->fieldId);

        return $strHtmlId;
    }

public function getHtmlId ( ) { $ strHtmlId = sprintf ( $ this -> htmlIdFormat , $ this -> locale , $ this -> fieldId ) ; return $ strHtmlId ; }


public function getHtmlName()
    {
        $strHtmlName = sprintf($this->htmlNameFormat, $this->locale, $this->fieldId);

        return $strHtmlName;
    }

public function getHtmlName ( ) { $ strHtmlName = sprintf ( $ this -> htmlNameFormat , $ this -> locale , $ this -> fieldId ) ; return $ strHtmlName ; }


public function save()
    {
        $this->model = $this->getModel();
        if (is_a($this->model, 'Modules\Dynamicfield\Entities\FieldTranslation')) {
            $this->saveField();
        } else {
            // save sub control of repeater
            $this->saveRepeaterField();
        }
    }


public function saveField()
    {
        $entity = Entity::getEntity($this->entityId, $this->entityType, $this->fieldId);
        if (!$entity->id) {
            $entity->entity_id = $this->entityId;
            $entity->field_id = $this->fieldId;
            $entity->entity_type = $this->entityType;
            $entity->save();
        }
        $this->model->entity_field_id = $entity->id;
        $this->model->locale = $this->locale;
        $this->model->value = $this->getValue();
        $this->model->save();
    }

public function saveField ( ) { $ entity = Entity :: getEntity ( $ this -> entityId , $ this -> entityType , $ this -> fieldId ) ; if ( ! $ entity -> id ) { $ entity -> entity_id = $ this -> entityId ; $ entity -> field_id = $ this -> fieldId ; $ entity -> entity_type = $ this -> entityType ; $ entity -> save ( ) ; } $ this -> model -> entity_field_id = $ entity -> id ; $ this -> model -> locale = $ this -> locale ; $ this -> model -> value = $ this -> getValue ( ) ; $ this -> model -> save ( ) ; }


public function saveRepeaterField()
    {
        $repeaterId = $this->repeaterId;

        $repeaterTranslate = RepeaterTranslation::firstOrNew(array('id' => $this->translationId));

        if (!$repeaterTranslate->id) {
            $entity = Entity::getEntity($this->entityId, $this->entityType, $repeaterId);
            if (!$entity->id) {
                $entity->entity_id = $this->entityId;
                $entity->entity_type = $this->entityType;
                $entity->field_id = $repeaterId;
                $entity->save();
            }
            $repeaterTranslate->entity_repeater_id = $entity->id;
            $repeaterTranslate->locale = $this->locale;
            $repeaterTranslate->save();
        }
        $this->model->translation_id = $repeaterTranslate->id;
        $this->model->field_id = $this->fieldId;

        $this->model->value = $this->getValue();
        $this->model->save();
        // assign translate_id to same group;
        $this->translationId = $this->model->translation_id;
    }

public
function
saveRepeaterField
(
)
{
$
repeaterId
=
$
this
->
repeaterId
;
$
repeaterTranslate
=
RepeaterTranslation
::
firstOrNew
(
array
(
'id'
=>
$
this
->
translationId
)
)
;
if
(
!
$
repeaterTranslate
->
id
)
{
$
entity
=
Entity
::
getEntity
(
$
this
->
entityId
,
$
this
->
entityType
,
$
repeaterId
)
;
if
(
!
$
entity
->
id
)
{
$
entity
->
entity_id
=
$
this
->
entityId
;
$
entity
->
entity_type
=
$
this
->
entityType
;
$
entity
->
field_id
=
$
repeaterId
;
$
entity
->
save
(
)
;
}
$
repeaterTranslate
->
entity_repeater_id
=
$
entity
->
id
;
$
repeaterTranslate
->
locale
=
$
this
->
locale
;
$
repeaterTranslate
->
save
(
)
;
}
$
this
->
model
->
translation_id
=
$
repeaterTranslate
->
id
;
$
this
->
model
->
field_id
=
$
this
->
fieldId
;
$
this
->
model
->
value
=
$
this
->
getValue
(
)
;
$
this
->
model
->
save
(
)
;
// assign translate_id to same group;
$
this
->
translationId
=
$
this
->
model
->
translation_id
;
}

Save repeat data for field of repeater .


public function getOption($key)
    {
        $value = '';
        try {
            $value = $this->options[$key];
        } catch (\Exception $e) {
        }

        return $value;
    }

public function getOption ( $ key ) { $ value = '' ; try { $ value = $ this -> options [ $ key ] ; } catch ( \ Exception $ e ) { } return $ value ; }

get value of option.

@param $key

@return string


public function forward($length) {
        $theta = $this->rotation / 180.0 * M_PI;
        $x     = $this->x + $length * cos($theta);
        $y     = $this->y + $length * sin($theta);

        $this->move($x, $y);
    }

public function forward ( $ length ) { $ theta = $ this -> rotation / 180.0 * M_PI ; $ x = $ this -> x + $ length * cos ( $ theta ) ; $ y = $ this -> y + $ length * sin ( $ theta ) ; $ this -> move ( $ x , $ y ) ; }

Move the pen forward

@param integer $length distance to move forward


Move the pen, drawing if the pen is down.

@param int $y new x position
@param int $y new y position

Move the pen drawing if the pen is down .


public function hasAncestor(TaskConfiguration $taskConfig)
    {
        foreach ($this->getPreviousTasksConfigurations() as $previousTaskConfig) {
            // Avoid errors for direct ancestors
            if ($this->getCode() === $previousTaskConfig->getCode()) {
                continue;
            }

            if ($previousTaskConfig->getCode() === $taskConfig->getCode()) {
                return true;
            }

            if ($previousTaskConfig->hasAncestor($taskConfig)) {
                return true;
            }
        }

        return false;
    }

public
function
hasAncestor
(
TaskConfiguration
$
taskConfig
)
{
foreach
(
$
this
->
getPreviousTasksConfigurations
(
)
as
$
previousTaskConfig
)
{
// Avoid errors for direct ancestors
if
(
$
this
->
getCode
(
)
===
$
previousTaskConfig
->
getCode
(
)
)
{
continue
;
}
if
(
$
previousTaskConfig
->
getCode
(
)
===
$
taskConfig
->
getCode
(
)
)
{
return
true
;
}
if
(
$
previousTaskConfig
->
hasAncestor
(
$
taskConfig
)
)
{
return
true
;
}
}
return
false
;
}

Check task ancestors to find if it have a given task as parent

@param TaskConfiguration $taskConfig

@return bool


public function hasDescendant(TaskConfiguration $taskConfig, $checkErrors = true)
    {
        foreach ($this->getNextTasksConfigurations() as $nextTaskConfig) {
            // Avoid errors for direct descendant
            if ($this->getCode() === $nextTaskConfig->getCode()) {
                continue;
            }

            if ($nextTaskConfig->getCode() === $taskConfig->getCode()) {
                return true;
            }

            if ($nextTaskConfig->hasDescendant($taskConfig, $checkErrors)) {
                return true;
            }
        }

        if ($checkErrors) {
            foreach ($this->getErrorTasksConfigurations() as $errorTasksConfig) {
                // Avoid errors for direct error descendant
                if ($this->getCode() === $errorTasksConfig->getCode()) {
                    continue;
                }

                if ($errorTasksConfig->getCode() === $taskConfig->getCode()) {
                    return true;
                }

                if ($errorTasksConfig->hasDescendant($taskConfig, $checkErrors)) {
                    return true;
                }
            }
        }

        return false;
    }

Check task ancestors to find if it have a given task as child

@param TaskConfiguration $taskConfig
@param bool              $checkErrors

@return bool


public function reset($cleanInput)
    {
        $this->setOutput(null);
        $this->setSkipped(false);
        $this->setException(null);
        $this->setErrorOutput(null);

        if($cleanInput) {
            $this->setInput(null);
            $this->setPreviousState(null);
        }
    }

public function reset ( $ cleanInput ) { $ this -> setOutput ( null ) ; $ this -> setSkipped ( false ) ; $ this -> setException ( null ) ; $ this -> setErrorOutput ( null ) ; if ( $ cleanInput ) { $ this -> setInput ( null ) ; $ this -> setPreviousState ( null ) ; } }

Reset the state object
To be used before execution

@param bool $cleanInput


protected function checkCondition($input, $conditions)
    {
        foreach ($conditions['match'] as $key => $value) {
            if (!$this->checkValue($input, $key, $value)) {
                return false;
            }
        }

        foreach ($conditions['empty'] as $key => $value) {
            if (!$this->checkEmpty($input, $key)) {
                return false;
            }
        }

        foreach ($conditions['match_regexp'] as $key => $value) {
            if (!$this->checkValue($input, $key, $value, true, true)) {
                return false;
            }
        }

        foreach ($conditions['not_match'] as $key => $value) {
            if (!$this->checkValue($input, $key, $value, false)) {
                return false;
            }
        }

        foreach ($conditions['not_empty'] as $key => $value) {
            if ($this->checkEmpty($input, $key)) {
                return false;
            }
        }

        foreach ($conditions['not_match_regexp'] as $key => $value) {
            if (!$this->checkValue($input, $key, $value, false, true)) {
                return false;
            }
        }

        return true;
    }

protected function checkCondition ( $ input , $ conditions ) { foreach ( $ conditions [ 'match' ] as $ key => $ value ) { if ( ! $ this -> checkValue ( $ input , $ key , $ value ) ) { return false ; } } foreach ( $ conditions [ 'empty' ] as $ key => $ value ) { if ( ! $ this -> checkEmpty ( $ input , $ key ) ) { return false ; } } foreach ( $ conditions [ 'match_regexp' ] as $ key => $ value ) { if ( ! $ this -> checkValue ( $ input , $ key , $ value , true , true ) ) { return false ; } } foreach ( $ conditions [ 'not_match' ] as $ key => $ value ) { if ( ! $ this -> checkValue ( $ input , $ key , $ value , false ) ) { return false ; } } foreach ( $ conditions [ 'not_empty' ] as $ key => $ value ) { if ( $ this -> checkEmpty ( $ input , $ key ) ) { return false ; } } foreach ( $ conditions [ 'not_match_regexp' ] as $ key => $ value ) { if ( ! $ this -> checkValue ( $ input , $ key , $ value , false , true ) ) { return false ; } } return true ; }

Test the input with the given set of conditions
True by default

@param mixed $input
@param array $conditions

@return bool


protected function configureWrappedConditionOptions(string $wrapperKey, OptionsResolver $resolver)
    {
        $resolver->setDefault($wrapperKey, []);
        $resolver->setAllowedTypes($wrapperKey, ['array']);
        $resolver->setNormalizer($wrapperKey, function (OptionsResolver $options, $value) {
            $conditionResolver = new OptionsResolver();
            $this->configureConditionOptions($conditionResolver);

            return $conditionResolver->resolve($value);
        });
    }

protected function configureWrappedConditionOptions ( string $ wrapperKey , OptionsResolver $ resolver ) { $ resolver -> setDefault ( $ wrapperKey , [ ] ) ; $ resolver -> setAllowedTypes ( $ wrapperKey , [ 'array' ] ) ; $ resolver -> setNormalizer ( $ wrapperKey , function ( OptionsResolver $ options , $ value ) { $ conditionResolver = new OptionsResolver ( ) ; $ this -> configureConditionOptions ( $ conditionResolver ) ; return $ conditionResolver -> resolve ( $ value ) ; } ) ; }

Configure available condition rules in a wrapper option

@param string          $wrapperKey
@param OptionsResolver $resolver


protected function configureConditionOptions(OptionsResolver $resolver)
    {
        $resolver->setDefault('not_match', []);
        $resolver->setDefault('match', []);
        $resolver->setDefault('not_empty', []);
        $resolver->setDefault('empty', []);
        $resolver->setDefault('not_match_regexp', []);
        $resolver->setDefault('match_regexp', []);
        $resolver->setAllowedTypes('not_match', 'array');
        $resolver->setAllowedTypes('match', 'array');
        $resolver->setAllowedTypes('not_match_regexp', 'array');
        $resolver->setAllowedTypes('match_regexp', 'array');
    }

protected function configureConditionOptions ( OptionsResolver $ resolver ) { $ resolver -> setDefault ( 'not_match' , [ ] ) ; $ resolver -> setDefault ( 'match' , [ ] ) ; $ resolver -> setDefault ( 'not_empty' , [ ] ) ; $ resolver -> setDefault ( 'empty' , [ ] ) ; $ resolver -> setDefault ( 'not_match_regexp' , [ ] ) ; $ resolver -> setDefault ( 'match_regexp' , [ ] ) ; $ resolver -> setAllowedTypes ( 'not_match' , 'array' ) ; $ resolver -> setAllowedTypes ( 'match' , 'array' ) ; $ resolver -> setAllowedTypes ( 'not_match_regexp' , 'array' ) ; $ resolver -> setAllowedTypes ( 'match_regexp' , 'array' ) ; }

Configure available condition rules

@param OptionsResolver $resolver


protected function checkValue($input, $key, $value, $shouldMatch = true, $regexpMode = false)
    {
        $currentValue = $this->getValue($input, $key);

        /** @noinspection TypeUnsafeComparisonInspection */
        if ($shouldMatch && !$regexpMode && $currentValue != $value) {
            return false;
        }

        /** @noinspection TypeUnsafeComparisonInspection */
        if (!$shouldMatch && !$regexpMode && $currentValue == $value) {
            return false;
        }

        if ($regexpMode) {
            $pregMatch = preg_match($value, $currentValue);

            if ($shouldMatch && (false === $pregMatch || 0 === $pregMatch)) {
                return false;
            }

            if (!$shouldMatch && (false === $pregMatch || $pregMatch > 0)) {
                return false;
            }
        }

        return true;
    }

Softly check if an input key match a value, or not

@param object|array $input
@param string       $key
@param mixed        $value
@param bool         $shouldMatch
@param bool         $regexpMode

@throws \Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException
@throws \Symfony\Component\PropertyAccess\Exception\AccessException
@throws \Symfony\Component\PropertyAccess\Exception\InvalidArgumentException

@return bool

Softly check if an input key match a value or not


protected function checkEmpty($input, $key)
    {
        $currentValue = $this->getValue($input, $key);

        return empty($currentValue);
    }

protected function checkEmpty ( $ input , $ key ) { $ currentValue = $ this -> getValue ( $ input , $ key ) ; return empty ( $ currentValue ) ; }

Check if the input property is empty or not

@param array|object $input
@param string       $key

@return bool


public function getDuration()
    {
        if ($this->getEndDate()) {
            return $this->getEndDate()->getTimestamp() - $this->getStartDate()->getTimestamp();
        }

        return null;
    }

public function getDuration ( ) { if ( $ this -> getEndDate ( ) ) { return $ this -> getEndDate ( ) -> getTimestamp ( ) - $ this -> getStartDate ( ) -> getTimestamp ( ) ; } return null ; }

Get process duration in seconds

@return int|null


public function contextualizeOptions(array $options, array $context): array
    {
        $contextualizedOptions = [];
        foreach ($options as $key => $value) {
            $contextualizedKey = $this->contextualizeOption($key, $context);
            $contextualizedValue = $this->contextualizeOption($value, $context);
            $contextualizedOptions[$contextualizedKey] = $contextualizedValue;
        }

        return $contextualizedOptions;
    }

public function contextualizeOptions ( array $ options , array $ context ) : array { $ contextualizedOptions = [ ] ; foreach ( $ options as $ key => $ value ) { $ contextualizedKey = $ this -> contextualizeOption ( $ key , $ context ) ; $ contextualizedValue = $ this -> contextualizeOption ( $ value , $ context ) ; $ contextualizedOptions [ $ contextualizedKey ] = $ contextualizedValue ; } return $ contextualizedOptions ; }

Replace all contextualized values from options

@param array $options
@param array $context

@return array


protected function findBestNextTask($branches, $taskList, ProcessConfiguration $process)
    {
        // Get resolvable tasks
        $taskCandidates = [];
        foreach ($taskList as $taskCode) {
            $task = $process->getTaskConfiguration($taskCode);
            if (empty($task->getPreviousTasksConfigurations())) {
                return $taskCode;
            }

            // Check if task has all necessary ancestors in branches
            $hasAllAncestors = array_reduce($task->getPreviousTasksConfigurations(), function ($result, TaskConfiguration $prevTask) use ($branches) {
                return $result && \in_array($prevTask->getCode(), $branches);
            }, true);

            if ($hasAllAncestors) {
                $taskCandidates[] = $taskCode;
            }
        }

        if (empty($taskCandidates)) {
            throw new \UnexpectedValueException('Cannot find a task to output');
        }

        // Try to find the task the most on the right
        $taskWeights = [];
        foreach ($taskCandidates as $taskCandidate) {
            $weight = 0;
            $task = $process->getTaskConfiguration($taskCandidate);
            foreach ($task->getPreviousTasksConfigurations() as $prevTask) {
                $key = array_search($prevTask->getCode(), $branches);

                // Should never be non-numeric...
                if (!is_numeric($key)) {
                    throw new \UnexpectedValueException('Invalid key type');
                }
                $weight += $key;
            }

            if (!empty($task->getPreviousTasksConfigurations())) {
                $weight = $weight / \count($task->getPreviousTasksConfigurations());
            }

            $taskWeights[$taskCandidate] = $weight;
        }

        arsort($taskWeights);
        $bestCandidate = key($taskWeights);
        $bestWeight = $taskWeights[$bestCandidate];

        $equalWeights = array_filter($taskWeights, function ($item) use ($bestWeight) {
            return $item == $bestWeight;
        });

        if (count($equalWeights) == 1) {
            return $bestCandidate;
        }

        // If a few tasks have the same weight, return the tasks with the lowest number of children
        $childCounts = [];
        foreach ($equalWeights as $taskCode => $weight) {
            $task = $process->getTaskConfiguration($taskCode);
            $childCounts[$taskCode] = $this->getTaskChildrenCount($task);
        }
        asort($childCounts);

        return key($childCounts);
    }

Try to find a best candidate for next display

@param                      $branches
@param                      $taskList
@param ProcessConfiguration $process

@return int|null|string


protected function getInputCode(ProcessState $state)
    {
        $previousState = $state->getPreviousState();
        $previousTaskCode = $previousState->getTaskConfiguration()->getCode();
        $inputCodes = $this->getOption($state, 'input_codes');
        if (!array_key_exists($previousTaskCode, $inputCodes)) {
            throw new \UnexpectedValueException("Task '{$previousTaskCode}' is not mapped in the input_codes option");
        }

        return $inputCodes[$previousTaskCode];
    }

Map the previous task code to an input code

@param ProcessState $state

@throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface
@throws \InvalidArgumentException
@throws \UnexpectedValueException

@return string


protected function isResolved(ProcessState $state)
    {
        $inputCodes = $this->getOption($state, 'input_codes');
        foreach ($inputCodes as $inputCode) {
            if (!array_key_exists($inputCode, $this->inputs)) {
                return false;
            }
        }

        return true;
    }

protected function isResolved ( ProcessState $ state ) { $ inputCodes = $ this -> getOption ( $ state , 'input_codes' ) ; foreach ( $ inputCodes as $ inputCode ) { if ( ! array_key_exists ( $ inputCode , $ this -> inputs ) ) { return false ; } } return true ; }

Check if the received inputs match the defined mappings

@param ProcessState $state

@throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface
@throws \InvalidArgumentException

@return bool


protected function getFilePath(array $options, string $input)
    {
        $basePath = $options['base_path'];
        if (\strlen($basePath) > 0) {
            $basePath = rtrim($options['base_path'], '/').'/';
        }

        return $basePath.$input;
    }

protected function getFilePath ( array $ options , string $ input ) { $ basePath = $ options [ 'base_path' ] ; if ( \ strlen ( $ basePath ) > 0 ) { $ basePath = rtrim ( $ options [ 'base_path' ] , '/' ) . '/' ; } return $ basePath . $ input ; }

If there is no base_path, then the given path from input should be absolute

@param array  $options
@param string $input

@return string

If there is no base_path then the given path from input should be absolute


public function processSorter(ProcessConfiguration $a, ProcessConfiguration $b)
    {
        if ($a->getCode() === $b->getCode()) {
            return 0;
        }

        return ($a->getCode() < $b->getCode()) ? -1 : 1;
    }

public function processSorter ( ProcessConfiguration $ a , ProcessConfiguration $ b ) { if ( $ a -> getCode ( ) === $ b -> getCode ( ) ) { return 0 ; } return ( $ a -> getCode ( ) < $ b -> getCode ( ) ) ? - 1 : 1 ; }

Sorter callback for process codes

@param ProcessConfiguration $a
@param ProcessConfiguration $b

@return int


protected function handleIteratorFromInput(ProcessState $state)
    {
        if ($this->iterator instanceof \Iterator) {
            if ($this->iterator->valid()) {
                // No action needed, execution is in progress
                return;
            }
            // Cleanup invalid iterator => prepare for new iteration cycle
            $this->iterator = null;
        }

        // This should never be reached
        if (null !== $this->iterator) {
            throw new \UnexpectedValueException(
                "At this point iterator should have been null, maybe it's a wrong type..."
            );
        }

        // Create iterator
        if ($state->getInput() instanceof \Iterator) {
            $this->iterator = $state->getInput();
        } elseif (\is_array($state->getInput())) {
            $this->iterator = new \ArrayIterator($state->getInput());
        }

        // Assert iterator is OK
        if (!$this->iterator instanceof \Iterator) {
            throw new \UnexpectedValueException('Cannot create iterator from input');
        }
    }

Create or recreate an iterator from input

@param ProcessState $state


public function flush(ProcessState $state): void
    {
        $modulo = $this->getOption($state, 'flush_every');
        if (0 === $this->counter % $modulo) {
            $state->setSkipped(true);
        } else {
            $state->setOutput($this->counter);
        }
    }

public function flush ( ProcessState $ state ) : void { $ modulo = $ this -> getOption ( $ state , 'flush_every' ) ; if ( 0 === $ this -> counter % $ modulo ) { $ state -> setSkipped ( true ) ; } else { $ state -> setOutput ( $ this -> counter ) ; } }

Condition is inversed during flush

@param ProcessState $state


public function getLineCount(): int
    {
        if (null === $this->lineCount) {
            $this->rewind();
            $line = 0;
            while (!$this->isEndOfFile()) {
                ++$line;
                $this->readRaw();
            }
            $this->rewind();

            $this->lineCount = $line;
        }

        return $this->lineCount;
    }

public function getLineCount ( ) : int { if ( null === $ this -> lineCount ) { $ this -> rewind ( ) ; $ line = 0 ; while ( ! $ this -> isEndOfFile ( ) ) { ++ $ line ; $ this -> readRaw ( ) ; } $ this -> rewind ( ) ; $ this -> lineCount = $ line ; } return $ this -> lineCount ; }

Warning! This method will rewind the file to the beginning before and after counting the lines!

@throws \RuntimeException

@return int


public function rewind(): void
    {
        $this->assertOpened();
        if (!rewind($this->handler)) {
            throw new \RuntimeException("Unable to rewind '{$this->getResourceName()}'");
        }
        $this->currentLine = 0;
        if (!$this->manualHeaders) {
            $this->readRaw(); // skip headers
        }
    }

This methods rewinds the file to the first line of data, skipping the headers.

@throws \RuntimeException

This methods rewinds the file to the first line of data skipping the headers .


protected function getCleanedTransfomerCode(string $transformerCode)
    {
        $match = preg_match('/([^#]+)(#[\d]+)?/', $transformerCode, $parts);

        if (1 === $match && $this->transformerRegistry->hasTransformer($parts[1])) {
            return $parts[1];
        }

        return $transformerCode;
    }

protected function getCleanedTransfomerCode ( string $ transformerCode ) { $ match = preg_match ( '/([^#]+)(#[\d]+)?/' , $ transformerCode , $ parts ) ; if ( 1 === $ match && $ this -> transformerRegistry -> hasTransformer ( $ parts [ 1 ] ) ) { return $ parts [ 1 ] ; } return $ transformerCode ; }

This allows to use transformer codes suffixes to avoid limitations to the "transformers" option using codes as
keys This way you can chain multiple times the same transformer. Without this, it would silently call only the
1st one.

@example
transformers:
callback#1:
callback: array_filter
callback#2:
callback: array_reverse

@param string $transformerCode

@throws \CleverAge\ProcessBundle\Exception\MissingTransformerException

@return string

This allows to use transformer codes suffixes to avoid limitations to the transformers option using codes as keys This way you can chain multiple times the same transformer . Without this it would silently call only the 1st one .


public function getDependencyGroups(): array
    {
        if (null === $this->dependencyGroups) {
            $this->dependencyGroups = [];
            foreach ($this->getTaskConfigurations() as $taskConfiguration) {
                $isInBranch = false;
                foreach ($this->dependencyGroups as $branch) {
                    if (\in_array($taskConfiguration->getCode(), $branch, true)) {
                        $isInBranch = true;
                        break;
                    }
                }

                if (!$isInBranch) {
                    $dependencies = $this->buildDependencies($taskConfiguration);
                    $dependencies = $this->sortDependencies($dependencies);

                    $this->dependencyGroups[] = $dependencies;
                }
            }
        }

        return $this->dependencyGroups;
    }

public function getDependencyGroups ( ) : array { if ( null === $ this -> dependencyGroups ) { $ this -> dependencyGroups = [ ] ; foreach ( $ this -> getTaskConfigurations ( ) as $ taskConfiguration ) { $ isInBranch = false ; foreach ( $ this -> dependencyGroups as $ branch ) { if ( \ in_array ( $ taskConfiguration -> getCode ( ) , $ branch , true ) ) { $ isInBranch = true ; break ; } } if ( ! $ isInBranch ) { $ dependencies = $ this -> buildDependencies ( $ taskConfiguration ) ; $ dependencies = $ this -> sortDependencies ( $ dependencies ) ; $ this -> dependencyGroups [ ] = $ dependencies ; } } } return $ this -> dependencyGroups ; }

Group all task by dependencies

If one task depend from another, it should come after

@throws \CleverAge\ProcessBundle\Exception\MissingTaskConfigurationException

@return array


public function getMainTaskGroup(): array
    {
        if (null === $this->mainTaskGroup) {
            $mainTask = $this->getMainTask();

            foreach ($this->getDependencyGroups() as $branch) {
                if (\in_array($mainTask->getCode(), $branch, true)) {
                    $this->mainTaskGroup = $branch;
                    break;
                }
            }
        }

        return $this->mainTaskGroup;
    }

public function getMainTaskGroup ( ) : array { if ( null === $ this -> mainTaskGroup ) { $ mainTask = $ this -> getMainTask ( ) ; foreach ( $ this -> getDependencyGroups ( ) as $ branch ) { if ( \ in_array ( $ mainTask -> getCode ( ) , $ branch , true ) ) { $ this -> mainTaskGroup = $ branch ; break ; } } } return $ this -> mainTaskGroup ; }

Get the main task group that will be executed
It may be defined by the entry_point, or the end_point or simply the first task

If one task depend from another, it should come after

@throws \CleverAge\ProcessBundle\Exception\MissingTaskConfigurationException

@return array

Get the main task group that will be executed It may be defined by the entry_point or the end_point or simply the first task


public function checkCircularDependencies()
    {
        $taskConfigurations = $this->getTaskConfigurations();

        foreach ($taskConfigurations as $taskConfiguration) {
            foreach ($taskConfiguration->getPreviousTasksConfigurations() as $previousTaskConfig) {
                if ($taskConfiguration->getCode() === $previousTaskConfig->getCode()) {
                    throw CircularProcessException::create($this->getCode(), $taskConfiguration->getCode());
                }
            }
            if ($taskConfiguration->hasAncestor($taskConfiguration)) {
                throw CircularProcessException::create($this->getCode(), $taskConfiguration->getCode());
            }
        }
    }

public function checkCircularDependencies ( ) { $ taskConfigurations = $ this -> getTaskConfigurations ( ) ; foreach ( $ taskConfigurations as $ taskConfiguration ) { foreach ( $ taskConfiguration -> getPreviousTasksConfigurations ( ) as $ previousTaskConfig ) { if ( $ taskConfiguration -> getCode ( ) === $ previousTaskConfig -> getCode ( ) ) { throw CircularProcessException :: create ( $ this -> getCode ( ) , $ taskConfiguration -> getCode ( ) ) ; } } if ( $ taskConfiguration -> hasAncestor ( $ taskConfiguration ) ) { throw CircularProcessException :: create ( $ this -> getCode ( ) , $ taskConfiguration -> getCode ( ) ) ; } } }

Assert the process does not contain circular dependencies

@throws CircularProcessException


protected function buildDependencies(TaskConfiguration $taskConfig, array &$dependencies = [])
    {
        $code = $taskConfig->getCode();

        // May have been added by previous task
        if (!\in_array($code, $dependencies, true)) {
            $dependencies[] = $code;

            foreach ($taskConfig->getPreviousTasksConfigurations() as $previousTasksConfig) {
                $this->buildDependencies($previousTasksConfig, $dependencies);
            }

            foreach ($taskConfig->getNextTasksConfigurations() as $nextTasksConfig) {
                $this->buildDependencies($nextTasksConfig, $dependencies);
            }

            foreach ($taskConfig->getErrorTasksConfigurations() as $errorTasksConfig) {
                $this->buildDependencies($errorTasksConfig, $dependencies);
            }
        }

        return $dependencies;
    }

protected
function
buildDependencies
(
TaskConfiguration
$
taskConfig
,
array
&
$
dependencies
=
[
]
)
{
$
code
=
$
taskConfig
->
getCode
(
)
;
// May have been added by previous task
if
(
!
\
in_array
(
$
code
,
$
dependencies
,
true
)
)
{
$
dependencies
[
]
=
$
code
;
foreach
(
$
taskConfig
->
getPreviousTasksConfigurations
(
)
as
$
previousTasksConfig
)
{
$
this
->
buildDependencies
(
$
previousTasksConfig
,
$
dependencies
)
;
}
foreach
(
$
taskConfig
->
getNextTasksConfigurations
(
)
as
$
nextTasksConfig
)
{
$
this
->
buildDependencies
(
$
nextTasksConfig
,
$
dependencies
)
;
}
foreach
(
$
taskConfig
->
getErrorTasksConfigurations
(
)
as
$
errorTasksConfig
)
{
$
this
->
buildDependencies
(
$
errorTasksConfig
,
$
dependencies
)
;
}
}
return
$
dependencies
;
}

Cross all relations of a task to find all dependencies, and append them to the given array

@param TaskConfiguration $taskConfig
@param array             $dependencies

@return array

Cross all relations of a task to find all dependencies and append them to the given array


protected function sortDependencies(array $dependencies)
    {
        if (\count($dependencies) <= 1) {
            return $dependencies;
        }

        try {
            $this->checkCircularDependencies();
        } catch (CircularProcessException $e) {
            // Skipping the sort phase, it will throw later, on runtime
            return $dependencies;
        }

        /** @var int $midOffset */
        $midOffset = \count($dependencies) / 2;
        $midTaskCode = $dependencies[$midOffset];
        $midTask = $this->getTaskConfiguration($midTaskCode);

        $previousTasks = [];
        $independentTasks = [];
        $nextTasks = [];

        foreach ($dependencies as $taskCode) {
            if ($taskCode !== $midTaskCode) {
                $task = $this->getTaskConfiguration($taskCode);

                if ($midTask->hasAncestor($task)) {
                    $previousTasks[] = $taskCode;
                } elseif ($midTask->hasDescendant($task)) {
                    $nextTasks[] = $taskCode;
                } else {
                    $independentTasks[] = $taskCode;
                }
            }
        }

        $previousTasks = $this->sortDependencies($previousTasks);
        $independentTasks = $this->sortDependencies($independentTasks);
        $nextTasks = $this->sortDependencies($nextTasks);

        return array_merge($previousTasks, [$midTaskCode], $independentTasks, $nextTasks);
    }

Sort the tasks by dependencies

@param array $dependencies

@throws \CleverAge\ProcessBundle\Exception\MissingTaskConfigurationException

@return array


protected function resolve(TaskConfiguration $taskConfiguration): bool
    {
        $state = $taskConfiguration->getState();
        if ($state->isResolved()) {
            return true;
        }

        $state->setStatus(ProcessState::STATUS_PENDING);

        // Resolve parents first
        $allParentsResolved = true;
        foreach ($taskConfiguration->getPreviousTasksConfigurations() as $previousTasksConfiguration) {
            if (!$previousTasksConfiguration->getState()->isResolved()) {
                $isResolved = $this->resolve($previousTasksConfiguration);
                $allParentsResolved = $allParentsResolved && $isResolved;
            }
        }

        if (!$allParentsResolved) {
            throw new \UnexpectedValueException('Cannot resolve all parents');
        }

        $state->setStatus(ProcessState::STATUS_PROCESSING);

        // Start processing only roots that are not in error branch
        if ($taskConfiguration->isRoot()) {
            $this->process($taskConfiguration);
        }

        // Then we can proceed with BlockingTask only if they have been processed normally and where never "proceeded"
        if ($taskConfiguration->getTask() instanceof BlockingTaskInterface
            && $this->hasProcessedBlocking($taskConfiguration)
        ) {
            $this->process($taskConfiguration, self::EXECUTE_PROCEED);
        }

        // This task is now finished, we may flush it to test if there is anything lasting
        $this->flush($taskConfiguration);

        $state->setStatus(ProcessState::STATUS_RESOLVED);

        return $state->isResolved();
    }

Resolve a task, by checking if parents are resolved and processing roots and BlockingTasks

@param TaskConfiguration $taskConfiguration

@throws \RuntimeException
@throws \UnexpectedValueException

@return bool

Resolve a task by checking if parents are resolved and processing roots and BlockingTasks


protected function initialize(TaskConfiguration $taskConfiguration): void
    {
        $this->taskConfiguration = $taskConfiguration;

        if ($taskConfiguration->getErrorStrategy() === TaskConfiguration::STRATEGY_STOP
            && \count($taskConfiguration->getErrorOutputs()) > 0) {
            $m = "Task configuration {$taskConfiguration->getCode()} has error outputs ";
            $m .= "but it's error strategy 'stop' implies they will never be reached.";
            $this->taskLogger->error($m);
        }
        // @todo Refactor this using a Registry with this feature:
        // https://symfony.com/doc/current/service_container/service_subscribers_locators.html
        $serviceReference = $taskConfiguration->getServiceReference();
        if (0 === strpos($serviceReference, '@')) {
            $task = $this->container->get(ltrim($serviceReference, '@'));
        } elseif ($this->container->has($serviceReference)) {
            $task = $this->container->get($serviceReference);
        } else {
            throw new \UnexpectedValueException(
                "Unable to resolve service reference for Task '{$taskConfiguration->getCode()}'"
            );
        }
        if (!$task instanceof TaskInterface) {
            throw new \UnexpectedValueException(
                "Service defined in Task '{$taskConfiguration->getCode()}' is not a TaskInterface"
            );
        }
        $taskConfiguration->setTask($task);

        if ($task instanceof InitializableTaskInterface) {
            $state = $taskConfiguration->getState();
            try {
                $task->initialize($state);
            } catch (\Throwable $e) {
                $logContext = ['exception' => $e];
                $this->taskLogger->critical($e->getMessage(), $logContext);
                $state->stop($e);
            }
        }
        $this->handleState($taskConfiguration->getState());

        $this->taskConfiguration = null;
    }

Fetch task service and run additional setup for InitializableTasks

@param TaskConfiguration $taskConfiguration

@throws \Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException
@throws \Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException
@throws \UnexpectedValueException
@throws \RuntimeException


protected function flush(TaskConfiguration $taskConfiguration): void
    {
        $task = $taskConfiguration->getTask();
        if ($task instanceof BlockingTaskInterface) {
            return;
        }
        if ($task instanceof FlushableTaskInterface) {
            $this->process($taskConfiguration, self::EXECUTE_FLUSH);
            if ($taskConfiguration->getState()->isStopped()) {
                return;
            }
        }
        // Check outputs
        foreach ($taskConfiguration->getNextTasksConfigurations() as $nextTaskConfiguration) {
            $this->flush($nextTaskConfiguration);
        }
        // Check errors
        foreach ($taskConfiguration->getErrorTasksConfigurations() as $errorTasksConfiguration) {
            $this->flush($errorTasksConfiguration);
        }
    }

protected
function
flush
(
TaskConfiguration
$
taskConfiguration
)
:
void
{
$
task
=
$
taskConfiguration
->
getTask
(
)
;
if
(
$
task
instanceof
BlockingTaskInterface
)
{
return
;
}
if
(
$
task
instanceof
FlushableTaskInterface
)
{
$
this
->
process
(
$
taskConfiguration
,
self
::
EXECUTE_FLUSH
)
;
if
(
$
taskConfiguration
->
getState
(
)
->
isStopped
(
)
)
{
return
;
}
}
// Check outputs
foreach
(
$
taskConfiguration
->
getNextTasksConfigurations
(
)
as
$
nextTaskConfiguration
)
{
$
this
->
flush
(
$
nextTaskConfiguration
)
;
}
// Check errors
foreach
(
$
taskConfiguration
->
getErrorTasksConfigurations
(
)
as
$
errorTasksConfiguration
)
{
$
this
->
flush
(
$
errorTasksConfiguration
)
;
}
}

Browse all children for FlushableTask until a BlockingTask is found

@param TaskConfiguration $taskConfiguration

@throws \RuntimeException


protected function handleState(ProcessState $state): void
    {
        $processHistory = $state->getProcessHistory();
        if ($state->getException() && $state->isStopped()) {
            $processHistory->setFailed();

            throw new \RuntimeException(
                "Process {$state->getProcessConfiguration()->getCode()} has failed",
                -1,
                $state->getException()
            );
        }
    }

Save the state of the import process

@param ProcessState $state

@throws \RuntimeException


protected function checkProcess(ProcessConfiguration $processConfiguration): void
    {
        $processConfiguration->checkCircularDependencies();

        $taskConfigurations = $processConfiguration->getTaskConfigurations();
        $mainTaskList = $processConfiguration->getMainTaskGroup();
        $entryPoint = $processConfiguration->getEntryPoint();
        $endPoint = $processConfiguration->getEndPoint();

        // Check multi-branch processes
        foreach ($taskConfigurations as $taskConfiguration) {
            if (!\in_array($taskConfiguration->getCode(), $mainTaskList, true)) {
                // We won't throw an error to ease development... but there must be some kind of warning
                $state = $taskConfiguration->getState();
                $logContext = ['main_task_list' => $mainTaskList];
                $this->processLogger->warning("Task '{$taskConfiguration->getCode()}' is unreachable", $logContext);
                $this->handleState($state);
            }
        }

        // Check coherence for entry/end points
        $processConfiguration->getEndPoint();
        if ($entryPoint && !\in_array($entryPoint->getCode(), $mainTaskList, true)) {
            throw InvalidProcessConfigurationException::createNotInMain($entryPoint, $mainTaskList);
        }
        if ($endPoint && !\in_array($endPoint->getCode(), $mainTaskList, true)) {
            throw InvalidProcessConfigurationException::createNotInMain($endPoint, $mainTaskList);
        }
    }

Validate a process

@param ProcessConfiguration $processConfiguration

@throws \RuntimeException
@throws \CleverAge\ProcessBundle\Exception\InvalidProcessConfigurationException
@throws \CleverAge\ProcessBundle\Exception\CircularProcessException
@throws \CleverAge\ProcessBundle\Exception\MissingTaskConfigurationException


protected static function _validateModel()
    {
        // check if model is already validate
        if (!isset(self::$_validationStatus[static::$_databaseName . static::$_tableName])) {

            // grab actual class name from late state binding
            $subClassName = get_class(new static());

            // check model OOP static structure is OK
            if (static::$_tableName === null) {
                throw new Exception($subClassName . '::$_tableName must be implemented');
            }
            if (static::$_primaryKey === null) {
                throw new Exception($subClassName . '::$_primaryKey must be implemented');
            }
            if (static::$_tableFields === null) {
                throw new Exception($subClassName . '::$_tableFields must be implemented');
            }
            if(in_array(static::$_primaryKey,static::$_tableFields)) {
                throw new Exception($subClassName . '::$_tableFields must not contain $_primaryKey');
            }
            // if user has implemented $_relations for this model, call the defineRelations() method
            if (static::$_relations !== null) {
                static::defineRelations();
            }

            // store model validation status
            self::$_validationStatus[static::$_databaseName . static::$_tableName] = true;
        }
    }

Validate if this model is correctly implemented

@return void
@throws Exception


public function toArray($includePrimary = true)
    {
        if ($includePrimary) {
            $array = array(static::$_primaryKey => $this->{static::$_primaryKey});
        } else {
            $array = array();
        }

        foreach (static::$_tableFields as $unChamp) {
            $array[$unChamp] = $this->{$unChamp};
        }

        return $array;
    }

public function toArray ( $ includePrimary = true ) { if ( $ includePrimary ) { $ array = array ( static :: $ _primaryKey => $ this -> { static :: $ _primaryKey } ) ; } else { $ array = array ( ) ; } foreach ( static :: $ _tableFields as $ unChamp ) { $ array [ $ unChamp ] = $ this -> { $ unChamp } ; } return $ array ; }

Return model data in an array

@param bool $includePrimary - Include or not primary key in returned array

@return array


public static function getModelFields($includePrimary = true)
    {
        $fields = array();

        if ($includePrimary) {
            $fields[] = static::$_primaryKey;
        }
        foreach (static::$_tableFields as $unChamp) {
            $fields[] = $unChamp;
        }

        return $fields;
    }

public static function getModelFields ( $ includePrimary = true ) { $ fields = array ( ) ; if ( $ includePrimary ) { $ fields [ ] = static :: $ _primaryKey ; } foreach ( static :: $ _tableFields as $ unChamp ) { $ fields [ ] = $ unChamp ; } return $ fields ; }

Return table field from Model

@param bool $includePrimary - Include or not primary key in returned array

@return array


private function _unsetRelation(array $configRelation, $callArgs)
    {
        $isDeleted = false;
        switch ($configRelation['typeRelation']) {
            case self::MANY_TO_MANY:
                // assure that we provide an array of relation to unset
                if (!is_array($callArgs[0])) {
                    $callArgs[0] = array($callArgs[0]);
                }
                foreach ($callArgs[0] as $oneRelationModel) {
                    // build delete query for this relationship
                    $query = new InternalQueryHelper();
                    $query->delete($configRelation['relationTable'])
                          ->where($configRelation['sourceField'], '=', '?')
                          ->where($configRelation['targetField'], '=', '?');

                    $query = static::$_dataSource->prepare($query->buildQuery());

                    $query->execute(
                          array(
                              $this->{$configRelation['sourceField']},
                              $oneRelationModel->{$configRelation['targetField']}
                          )
                    );
                }
                $isDeleted = true;
                break;
        }

        return $isDeleted;
    }

Unset a relation value from magic setter

@param array $configRelation - Relation configuration
@param array $callArgs       - Models instance

@todo unset other relations type
@return bool


protected static function formatClassnameToRelationName($fullClassName)
    {
        // test if namespace present and remove them
        if (strpos($fullClassName, '\\') !== false) {
            $fullClassName = explode('\\', $fullClassName);
            $fullClassName = array_pop($fullClassName);
        }

        return strtolower($fullClassName);
    }

Format class name without namespace to store a relation name

@param string $fullClassName - Class name to normalize (with namespace)

@return string


protected static function addRelationOneToOne(
        $sourceField,
        $classRelation,
        $targetField,
        $autoGetFields = array(),
        $aliasRelation = ''
    )
    {
        if (!is_string($sourceField)) {
            throw new Exception('$sourceField have to be a string');
        }
        if (!is_string($classRelation)) {
            throw new Exception('$classRelation have to be a string');
        }
        if (!is_string($targetField)) {
            throw new Exception('$targetField have to be a string');
        }

        // test is related class is a PicORM model
        if (!class_exists($classRelation) || !new $classRelation() instanceof Model) {
            throw new Exception("Class " . $classRelation . " doesn't exists or is not subclass of \PicORM\Model");
        }

        // test if its needed to autoget all fields
        if ($autoGetFields === true) {
            $autoGetFields = $classRelation::getModelFields();
        }

        // store autogetfields as an array
        if (!is_array($autoGetFields)) {
            $autoGetFields = array($autoGetFields);
        }

        // create relation id with normalized classRelation name
        $idRelation = self :: formatClassnameToRelationName($classRelation);

        // override the relation's id if an alias is present
        if (!empty($aliasRelation)) {
            $idRelation = strtolower($aliasRelation);
        }

        // store new relation in model
        static::$_relations[$idRelation] = array(
            'typeRelation'  => self::ONE_TO_ONE,
            'classRelation' => $classRelation,
            'sourceField'   => $sourceField,
            'targetField'   => $targetField,
            'autoGetFields' => $autoGetFields
        );
    }

Add a OneToOne relation

@param string $sourceField   - model source field
@param string $classRelation - relation model classname
@param string $targetField   - related model target field
@param array  $autoGetFields - field to auto get from relation when loading model
@param string $aliasRelation - override relation auto naming with an alias (ex : for reflexive relation)

@throws Exception

@return void


protected static function addRelationOneToMany($sourceField, $classRelation, $targetField, $aliasRelation = '')
    {
        // test is related class is a PicORM model
        if (!class_exists($classRelation) || !new $classRelation() instanceof Model) {
            throw new Exception("Class " . $classRelation . " doesn't exists or is not subclass of PicORM\Model");
        }

        // create relation id with normalized classRelation name
        $idRelation = self :: formatClassnameToRelationName($classRelation);

        // override the relation's id if an alias is present
        if (!empty($aliasRelation)) {
            $idRelation = strtolower($aliasRelation);
        }

        // store new relation in model
        static::$_relations[$idRelation] = array(
            'typeRelation'  => self::ONE_TO_MANY,
            'classRelation' => $classRelation,
            'sourceField'   => $sourceField,
            'targetField'   => $targetField,
        );
    }

Add a OneToMany relation

@param        $sourceField   - model source field
@param        $classRelation - relation model classname
@param        $targetField   - related model target field
@param string $aliasRelation - override relation auto naming className with an alias

@throws Exception


protected static function addRelationManyToMany(
        $sourceField,
        $classRelation,
        $targetField,
        $relationTable,
        $aliasRelation = ''
    )
    {
        // test is related class is a PicORM model
        if (!class_exists($classRelation) || !new $classRelation() instanceof Model) {
            throw new Exception("Class " . $classRelation . " doesn't exists or is not subclass of PicORM\Model");
        }

        // create relation id with normalized classRelation name
        $idRelation = self :: formatClassnameToRelationName($classRelation);

        // override the relation's id if an alias is present
        if (!empty($aliasRelation)) {
            $idRelation = strtolower($aliasRelation);
        }

        // store new relation in model
        static::$_relations[$idRelation] = array(
            'typeRelation'  => self::MANY_TO_MANY,
            'classRelation' => $classRelation,
            'sourceField'   => $sourceField,
            'targetField'   => $targetField,
            'relationTable' => $relationTable,
        );
    }

Add a ManyToMany relation

@param        $sourceField   - model source field
@param        $classRelation - relation model name
@param        $targetField   - related model field
@param        $relationTable - mysql table containing the two models ID
@param string $aliasRelation - override relation auto naming className

@throws Exception


public static function findQuery($query, $params)
    {
        $query = static::$_dataSource->prepare($query);
        $query->execute($params);
        $fetch = $query->fetchAll(\PDO::FETCH_ASSOC);

        $collection = array();
        foreach ($fetch as $unRes) {
            $object = new static();
            $object->hydrate($unRes);
            $collection[] = $object;
        }

        return $collection;
    }

public static function findQuery ( $ query , $ params ) { $ query = static :: $ _dataSource -> prepare ( $ query ) ; $ query -> execute ( $ params ) ; $ fetch = $ query -> fetchAll ( \ PDO :: FETCH_ASSOC ) ; $ collection = array ( ) ; foreach ( $ fetch as $ unRes ) { $ object = new static ( ) ; $ object -> hydrate ( $ unRes ) ; $ collection [ ] = $ object ; } return $ collection ; }

Return model array fetched from database with custom mysql query

@param $query
@param $params

@return static[]
@todo must return Collection


public static function find($where = array(), $order = array(), $limitStart = null, $limitEnd = null)
    {
        // validate model PHP structure if necessary
        self :: _validateModel();

        // build a query helper with parameters
        $queryHelper = static::buildSelectQuery(array("*"), $where, $order, $limitStart, $limitEnd);

        // create a collection instance for called model with model datasource and custom created queryhelper
        return new Collection(static::$_dataSource, $queryHelper, get_called_class());
    }

Return model collection fetched from database with criteria

@param array $where      - associative array ex:
simple criteria        array('idMarque' => 1)
custom operator        array('idMarque' => array('operator' => '<=','value' => ''))
raw SQL                array('idMarque' => array('IN (5,6,4)'))
@param array $order      - associative array ex:array('libMarque'=>'ASC')
@param int   $limitStart - int
@param int   $limitEnd   - int

@return Collection