<?php

/**
 * @package    contao-bootstrap
 * @author     David Molineus <david.molineus@netzmacht.de>
 * @copyright  2015 netzmacht creative David Molineus
 * @license    LGPL 3.0
 * @filesource
 *
 */
namespace Netzmacht\Bootstrap\Grid;

use Netzmacht\Bootstrap\Grid\Builder\GridBuilder;

/**
 * Grid factory.
 *
 * @package Netzmacht\Bootstrap\Grid
 */
class Factory
{
    /**
     * Database created grids.
     *
     * @var array
     */
    private static $cache = array();

    /**
     * Build columns.
     *
     * @param GridBuilder      $builder The grid builder.
     * @param \Database\Result $result  The database result.
     * @param array            $classes Custom css classes.
     *
     * @return Grid
     */
    private static function buildGridColumns($builder, $result, $classes)
    {
        $columns = $result->columns;
        $sizes   = deserialize($result->sizes, true);

        for ($i = 0; $i < $columns; $i++) {
            $column = $builder->addColumn();

            foreach ($sizes as $size) {
                $key    = 'columnset_' . $size;
                $values = deserialize($result->$key, true);

                $column->forDevice(
                    $size,
                    $values[$i]['width'],
                    ($values[$i]['offset']) ? ($values[$i]['offset'] == 'null' ? 0 : $values[$i]['offset']): null,
                    $values[$i]['order'] ?: null
                );

                $index = ($i + 1);

                if (!empty($classes[$index])) {
                    $column->setClass($classes[$index]);
                }
            }
        }

        return $builder->build();
    }

    /**
     * Fetch the database result.
     *
     * @param int  $gridId      The grid id.
     * @param bool $ignoreError If true no exception is thrown. An empty grid is used instead.
     *
     * @return \Database\Result
     * @throws \InvalidArgumentException If grid is not found.
     */
    private static function fetchResult($gridId, $ignoreError = false)
    {
        $result = \Database::getInstance()
            ->prepare('SELECT * FROM tl_columnset WHERE id=? AND published=1')
            ->limit(1)
            ->execute($gridId);

        if (!$ignoreError && $result->numRows < 1) {
            throw new \InvalidArgumentException(sprintf('Could not find columnset with ID "%s"', $gridId));
        }

        return $result;
    }

    /**
     * Prepare the css classes.
     *
     * @param \Database\Result $result The database result.
     *
     * @return array
     */
    private static function prepareClasses($result)
    {
        $classes = array();

        foreach (deserialize($result->customClasses, true) as $class) {
            $classes[$class['column']] = $class['class'];
        }

        return $classes;
    }

    /**
     * Build the column resets.
     *
     * @param \Database\Result $result The database result.
     * @param Grid             $grid   The grid being built.
     *
     * @return void
     */
    private static function buildColumnResets($result, $grid)
    {
        foreach (deserialize($result->resets, true) as $row) {
            foreach (array('xs', 'sm', 'md', 'lg') as $size) {
                if (isset($row[$size]) && $row[$size]) {
                    $grid->addColumnReset(($row['column'] - 1), $size);
                }
            }
        }
    }

    /**
     * Create the grid by id.
     *
     * @param int  $gridId      The grid id.
     * @param bool $ignoreError If true no exception is thrown. An empty grid is used instead.
     *
     * @return Grid
     * @throws \InvalidArgumentException If grid is not found.
     */
    public static function createById($gridId, $ignoreError = false)
    {
        if (isset(static::$cache[$gridId])) {
            return static::$cache[$gridId];
        }

        $result = self::fetchResult($gridId, $ignoreError);

        if ($result) {
            $builder = GridBuilder::create();
            $classes = self::prepareClasses($result);
            $grid    = self::buildGridColumns($builder, $result, $classes);
            $grid->setRowClass($result->rowClass);

            self::buildColumnResets($result, $grid);
        } else {
            $grid = new Grid();
        }

        static::$cache[$gridId] = $grid;

        return static::$cache[$gridId];
    }
}


<?php

/**
 * @package   contao-bootstrap
 * @author    David Molineus <david.molineus@netzmacht.de>
 * @license   LGPL 3+
 * @copyright 2013-2015 netzmacht creative David Molineus
 */

namespace Netzmacht\Bootstrap\Grid\Integration;

use Netzmacht\Bootstrap\Core\Bootstrap;
use Netzmacht\Bootstrap\Grid\Event\GetGridsEvent;
use Netzmacht\Bootstrap\Grid\Factory;
use Netzmacht\Bootstrap\Grid\Grid;

/**
 * Subcolumns integration.
 *
 * @package Netzmacht\Bootstrap\Grid\Integration
 */
class Subcolumns
{
    /**
     * The subcolumns config name.
     *
     * @var string
     */
    protected static $name = 'bootstrap_customizable';

    /**
     * Setup the subcolumns integration.
     *
     * @return void
     *
     * @SuppressWarnings(PHPMD.Superglobals)
     */
    public static function setUp()
    {
        if (static::isActive()) {
            $GLOBALS['TL_HOOKS']['isVisibleElement'][] = array(
                'Netzmacht\Bootstrap\Grid\Integration\Subcolumns',
                'hookIsVisibleElement'
            );

            $GLOBALS['TL_EVENTS'][GetGridsEvent::NAME][] = 'Netzmacht\Bootstrap\Grid\Integration\Subcolumns::getGrids';

            $GLOBALS['TL_HOOKS']['parseTemplate'][] = array(
                'Netzmacht\Bootstrap\Grid\Integration\Subcolumns',
                'hookParseTemplate'
            );

            $GLOBALS['TL_HOOKS']['loadFormField'][] = array(
                'Netzmacht\Bootstrap\Grid\Integration\Subcolumns',
                'hookLoadFormField'
            );
        }
    }

    /**
     * Check if subcolumns integration is activated.
     *
     * @return bool
     */
    public static function isActive()
    {
        return in_array('Subcolumns', \Config::getInstance()->getActiveModules())
            && \Config::get('subcolumns') === static::$name;
    }

    /**
     * ParseTemplate hook being used to beatify the backend view.
     *
     * @param \Template $template The template.
     *
     * @return void
     */
    public function hookParseTemplate(\Template $template)
    {
        if (TL_MODE == 'BE'
            && $template->getName() == 'be_subcolumns'
            && Bootstrap::getConfigVar('grid-editor.backend.replace-subcolumns-template')
        ) {
            $template->setName('be_subcolumns_bootstrap');
        }
    }

    /**
     * The isVisibleElement hook is used to dynamically load the grid definitions from the database.
     *
     * Known limitation: If being logged in in the backend and frontend preview is used with show all elements
     * it does not work!
     *
     * @param \Model $model     The row model.
     * @param bool   $isVisible The current visible state.
     *
     * @return bool
     *
     * @SuppressWarnings(PHPMD.Superglobals)
     */
    public function hookIsVisibleElement(\Model $model, $isVisible)
    {
        if (static::isActive() && (
            ($model->getTable() == 'tl_module' && $model->type == 'subcolumns') ||
            $model->getTable() == 'tl_content' && ($model->type == 'colsetStart' ||
            $model->type == 'colsetPart'
        ))) {
            if ($model->type == 'colsetPart') {
                $modelClass = get_class($model);
                $parent     = $modelClass::findByPk($model->sc_parent);
                $type       = $parent->sc_type;
                $gridId     = $parent->bootstrap_grid;
            } else {
                $type   = $model->sc_type;
                $gridId = $model->bootstrap_grid;
            }

            try {
                $this->updateSubcolumnsDefinition($gridId, $type);
            } catch (\Exception $e) {
                // Do not throw the exception in the frontend. If nothing could fetched the fallback is used.
            }
        }

        return $isVisible;
    }

    /**
     * Load columnset definition for the form field.
     *
     * @param \Widget $widget The form widget.
     *
     * @return \Widget
     *
     * @SuppressWarnings(PHPMD.Superglobals)
     */
    public function hookLoadFormField($widget)
    {
        if ($widget->type === 'formcolstart') {
            $type   = $widget->fsc_type;
            $gridId = $widget->bootstrap_grid;
            $grid   = Factory::createById($gridId);

            $GLOBALS['TL_SUBCL'][static::$name]['sets'][$type] = $this->prepareContainer($grid);

        } elseif ($widget->type === 'formcolpart' || $widget->type === 'formcolend') {
            $parent = \FormFieldModel::findByPk($widget->fsc_parent);

            $this->updateSubcolumnsDefinition($parent->bootstrap_grid, $parent->fsc_type);
        }

        return $widget;
    }

    /**
     * Add column set field to the colsetStart content element.
     *
     * We need to do it dynamically because subcolumns creates its palette dynamically.
     *
     * @param \DataContainer $dataContainer The data container driver.
     *
     * @return void
     *
     * @SuppressWarnings(PHPMD.Superglobals)
     */
    public function appendColumnsetIdToPalette($dataContainer)
    {
        if ($dataContainer->table == 'tl_content') {
            $model = \ContentModel::findByPK($dataContainer->id);

            if ($model->sc_type > 0) {
                \MetaPalettes::appendFields($dataContainer->table, 'colsetStart', 'colset', array('bootstrap_grid'));
            }
        } elseif ($dataContainer->table == 'tl_form_field') {
            $model = \FormFieldModel::findByPk($dataContainer->id);

            if ($model->fsc_type > 0) {
                $GLOBALS['TL_DCA']['tl_form_field']['palettes']['formcolstart'] = str_replace(
                    'fsc_color,',
                    'fsc_color,bootstrap_grid,',
                    $GLOBALS['TL_DCA']['tl_form_field']['palettes']['formcolstart']
                );
            }
        } else {
            $model = \ModuleModel::findByPk($dataContainer->id);

            if ($model->sc_type > 0) {
                $GLOBALS['TL_DCA']['tl_module']['palettes']['subcolumns'] = str_replace(
                    'sc_type,',
                    'sc_type,columnset_id,',
                    $GLOBALS['TL_DCA']['tl_module']['palettes']['subcolumns']
                );
            }
        }
    }

    /**
     * Load all grids from the database.
     *
     * @param GetGridsEvent $event The subscribed event.
     *
     * @return void
     */
    public static function getGrids(GetGridsEvent $event)
    {
        $model = $event->getModel();
        $grids = $event->getGrids();

        if ($model->type == 'colsetStart' || $model->type == 'subcolumns') {
            $query   = 'SELECT * FROM tl_columnset WHERE published=1 AND columns=? ORDER BY title';
            $columns = $model->sc_type;
            $result  = \Database::getInstance()
                ->prepare($query)
                ->execute($columns);

            while ($result->next()) {
                $grids[$result->id] = $result->title;
            }
        } elseif ($model->type == 'formcolstart') {
            $query   = 'SELECT * FROM tl_columnset WHERE published=1 AND columns=? ORDER BY title';
            $columns = $model->fsc_type;
            $result  = \Database::getInstance()
                ->prepare($query)
                ->execute($columns);

            while ($result->next()) {
                $grids[$result->id] = $result->title;
            }
        }
    }

    /**
     * Prepare the container by loading the grid and parse it as subcolumns definition.
     *
     * @param Grid $grid The grid object.
     *
     * @return array
     */
    protected function prepareContainer(Grid $grid)
    {
        $container = array();

        foreach ($grid->getColumns() as $column) {
            $container[] = array(implode(' ', $column));
        }

        return $container;
    }

    /**
     * Update the subcolumns definition.
     *
     * @param int    $gridId The grid id.
     * @param string $type   The subcolumns type.
     *
     * @return void
     * @SuppressWarnings(PHPMD.Superglobals)
     */
    private function updateSubcolumnsDefinition($gridId, $type)
    {
        $grid = Factory::createById($gridId);

        $GLOBALS['TL_SUBCL'][static::$name]['sets'][$type] = $this->prepareContainer($grid);

        if ($grid->getRowClass()) {
            $GLOBALS['TL_SUBCL'][static::$name]['scclass'] = 'row ' . $grid->getRowClass();
        } else {
            $GLOBALS['TL_SUBCL'][static::$name]['scclass'] = 'row';
        }
    }
}


<?php

/**
 * @package   contao-bootstrap
 * @author    David Molineus <david.molineus@netzmacht.de>
 * @license   LGPL 3+
 * @copyright 2013-2015 netzmacht creative David Molineus
 */

namespace Netzmacht\Bootstrap\Grid\DataContainer;

use Netzmacht\Bootstrap\Core\Bootstrap;
use Netzmacht\Bootstrap\Grid\Event\GetGridsEvent;

/**
 * Class ColumnSet provides helper methods for handling the data container and generating the dynamic column set.
 *
 * @package Netzmacht\ColumnSet
 */
class ColumnSet extends \Backend
{
    /**
     * Add column set field to the colsetStart content element.
     *
     * We need to do it dynamically because subcolumns creates its palette dynamically.
     *
     * @param \DataContainer $dataContainer The data container driver.
     *
     * @return void
     *
     * @SuppressWarnings(PHPMD.Superglobals)
     */
    public function appendColumnsetIdToPalette($dataContainer)
    {
        if ($GLOBALS['TL_CONFIG']['subcolumns'] != 'bootstrap_customizable') {
            return;
        }

        if ($dataContainer->table == 'tl_content') {
            $model = \ContentModel::findByPK($dataContainer->id);

            if ($model->sc_type > 0) {
                \MetaPalettes::appendFields($dataContainer->table, 'colsetStart', 'colset', array('columnset_id'));
            }
        } else {
            $model = \ModuleModel::findByPk($dataContainer->id);

            if ($model->sc_type > 0) {
                if ($model->sc_type > 0) {
                    $GLOBALS['TL_DCA']['tl_module']['palettes']['subcolumns'] = str_replace(
                        'sc_type,',
                        'sc_type,columnset_id,',
                        $GLOBALS['TL_DCA']['tl_module']['palettes']['subcolumns']
                    );
                }
            }
        }
    }

    /**
     * Append column sizes fields dynamically to the palettes.
     *
     * @param \DataContainer $dataContainer The data container driver.
     *
     * @return void
     */
    public function appendColumnSizesToPalette($dataContainer)
    {
        $model = \Database::getInstance()
            ->prepare('SELECT * FROM tl_columnset WHERE id=?')
            ->limit(1)
            ->execute($dataContainer->id);

        $sizes = array_merge(deserialize($model->sizes, true));

        foreach ($sizes as $size) {
            $field = 'columnset_' . $size;

            \MetaPalettes::appendFields('tl_columnset', 'columnset', array($field));
        }
    }

    /**
     * Create a MCW row for each column.
     *
     * @param string  $value Deseriazable value, for getting an array.
     * @param \Widget $mcw   The multi column wizard or DC_Table.
     *
     * @return mixed
     */
    public function createColumns($value, $mcw)
    {
        $columns = (int) $mcw->activeRecord->columns;
        $value   = deserialize($value, true);
        $count   = count($value);
        $total   = Bootstrap::getConfigVar('grid-editor.columns');

        if ($count == 0) {
            // initialize columns

            for ($i = 0; $i < $columns; $i++) {
                $value[$i]['width'] = floor($total / $columns);
            }
        } elseif ($count > $columns) {
            // reduce columns if necessary

            $count = (count($value) - $columns);

            for ($i = 0; $i < $count; $i++) {
                array_pop($value);
            }
        } else {
            // make sure that column numbers has not changed

            for ($i = 0; $i < ($columns - $count); $i++) {
                $value[($i + $count)]['width'] = floor($total / $columns);
            }
        }

        return $value;
    }

    /**
     * Replace subcolumns getAllTypes method to load all created columnsets.
     *
     * There is a fallback provided if not bootstrap_customizable is used.
     *
     * @return array
     *
     * @SuppressWarnings(PHPMD.Superglobals)
     */
    public function getAllTypes()
    {
        if ($GLOBALS['TL_CONFIG']['subcolumns'] != 'bootstrap_customizable') {
            return array_keys($GLOBALS['TL_SUBCL'][$GLOBALS['TL_CONFIG']['subcolumns']]['sets']);
        }

        $this->import('Database');
        $collection = $this->Database->execute('SELECT columns FROM tl_columnset GROUP BY columns ORDER BY columns');

        $types = array();

        while ($collection->next()) {
            $types[] = $collection->columns;
        }

        return $types;
    }

    /**
     * Get grids.
     *
     * @param \DataContainer $dataContainer The data container driver.
     *
     * @return array
     *
     * @SuppressWarnings(PHPMD.Superglobals)
     */
    public function getGrids($dataContainer)
    {
        if ($dataContainer->activeRecord) {
            $dispatcher = $GLOBALS['container']['event-dispatcher'];
            $event      = new GetGridsEvent($dataContainer->activeRecord);
            $dispatcher->dispatch(GetGridsEvent::NAME, $event);

            return $event->getGrids()->getArrayCopy();
        }

        return array();
    }

    /**
     * Get columns for a a specific module.
     *
     * @param \DataContainer $dataContainer The data container driver.
     *
     * @return array
     *
     * @SuppressWarnings(PHPMD.Superglobals)
     */
    public function getColumnsForModule($dataContainer)
    {
        if ($GLOBALS['TL_CONFIG']['subcolumns'] != 'bootstrap_customizable') {
            $subcolumns = new \tl_module_sc();

            return $subcolumns->getColumns($dataContainer);
        }

        $model = \ModuleModel::findByPK($dataContainer->currentRecord);
        $cols  = array();

        $translate = array('first', 'second', 'third', 'fourth', 'fith');

        for ($i = 0; $i < $model->sc_type; $i++) {
            if (!array_key_exists($i, $translate)) {
                break;
            }

            $key        = $translate[$i];
            $cols[$key] = $GLOBALS['TL_LANG']['MSC']['sc_' . $key];
        }

        return $cols;
    }

    /**
     * Create the order values.
     *
     * @return array
     */
    public function getColumnOrders()
    {
        $columns = Bootstrap::getConfigVar('grid-editor.columns');
        $values  = array();

        for ($i = 0; $i <= $columns; $i++) {
            $values['push'][] = 'push-' . $i;
            $values['pull'][] = 'pull-' . $i;
        }

        return $values;
    }

    /**
     * Get column widths.
     *
     * @return array
     */
    public function getWidths()
    {
        $columns = Bootstrap::getConfigVar('grid-editor.columns');
        $values  = range(0, $columns);

        return $values;
    }

    /**
     * Get column numbers.
     *
     * @return array
     */
    public function getColumns()
    {
        $columns = Bootstrap::getConfigVar('grid-editor.columns');
        $values  = range(1, $columns);

        return $values;
    }

    /**
     * Get column offsets.
     *
     * @return array
     */
    public function getOffsets()
    {
        $columns = Bootstrap::getConfigVar('grid-editor.columns');
        $values  = array_merge(
            ['null'],
            range(1, $columns)
        );

        return $values;
    }

    /**
     * Get column numbers.
     *
     * @param \DataContainer $dataContainer Data container driver.
     *
     * @return array
     */
    public function getColumnNumbers($dataContainer)
    {
        if ($dataContainer->activeRecord) {
            $columns = $dataContainer->activeRecord->columns;
        } else {
            $columns = Bootstrap::getConfigVar('grid-editor.columns');
        }

        $values = range(1, $columns);

        return $values;
    }
}


<?php
/* ===========================================================================
 * Copyright 2018 Zindex Software
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * ============================================================================ */

namespace Opis\Session;

class Flash
{
    /** @var array */
    protected $data = [];

    /** @var array */
    protected $session;

    /**
     * @param array $session
     */
    public function __construct(array $session = [])
    {
        $this->session = $session;
    }

    /**
     * Stores a value
     *
     * @param string $key
     * @param mixed $value
     * @return Flash
     */
    public function set(string $key, $value): self
    {
        $this->data[$key] = $value;
        return $this;
    }

    /**
     * Read a value
     *
     * @param string $key Key
     * @param mixed|null $default Default value
     *
     * @return  mixed
     */
    public function get(string $key, $default = null)
    {
        if (array_key_exists($key, $this->data)) {
            return $this->data[$key];
        }

        return array_key_exists($key, $this->session) ? $this->session[$key] : $default;
    }

    /**
     * Check if a key exists
     *
     * @param string $key Key
     * @return boolean
     */
    public function has(string $key): bool
    {
        return array_key_exists($key, $this->data) || array_key_exists($key, $this->session);
    }

    /**
     * Remove specified key
     *
     * @param string $key Key
     * @return  Flash
     */
    public function delete(string $key): self
    {
        unset($this->data[$key]);
        unset($this->session[$key]);
        return $this;
    }

    /**
     * Read the value associated with the specified key or associate
     * the specified key with the value returned by invoking the callback.
     *
     * @param string $key Key
     * @param callable $callback Callback
     *
     * @return mixed
     */
    public function load(string $key, callable $callback)
    {
        if (!$this->has($key)) {
            $this->set($key, $callback($key));
        }

        return $this->get($key);
    }

    /**
     * Clear or replace data
     *
     * @param array $data Data
     *
     * @return Flash
     */
    public function clear(array $data = []): self
    {
        $this->data = $data;
        $this->session = [];
        return $this;
    }

    /**
     * Re-flash data
     *
     * @param array|null $keys Data
     *
     * @return Flash
     */
    public function reflash(array $keys = null): self
    {
        if ($keys === null) {
            return $this->clear($this->data + $this->session);
        }

        $session = array_intersect_key($this->session, array_flip($keys));
        return $this->clear($this->data + $session);
    }

    /**
     * Return saved data
     *
     * @return array
     */
    public function toArray(): array
    {
        return $this->data;
    }
}


<?php

/**
 * @package   contao-bootstrap
 * @author    David Molineus <david.molineus@netzmacht.de>
 * @license   LGPL 3+
 * @copyright 2013-2015 netzmacht creative David Molineus
 */

namespace Netzmacht\Bootstrap\Grid\Integration;

use Netzmacht\Bootstrap\Core\Event\ReplaceInsertTagsEvent;
use Netzmacht\Bootstrap\Grid\Factory;
use Netzmacht\Bootstrap\Grid\Walker;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

/**
 * Class InsertTag provides an insert tag integration for the grids.
 *
 * Begin a grid by defining an identifier and the to using column set id.
 * {{grid::IDENTIFIER::begin::COLUMNSET_ID}}
 *
 * You can also pass the infinite flag. When enabling it you can build endless columns.
 * {{grid::IDENTIFIER::begin::COLUMNSET_ID::infinite}}
 *
 * Create a new column without the columnset id.
 * {{grid::IDENTIFIER}}
 *
 * Close the grid.
 * {{grid::IDENTIFIER::end}}
 *
 * @package Netzmacht\Bootstrap\Grid\Integration
 */
class InsertTag implements EventSubscriberInterface
{
    /**
     * The insert tag walkers.
     *
     * @var Walker[]
     */
    private static $walkers = array();

    /**
     * {@inheritdoc}
     */
    public static function getSubscribedEvents()
    {
        return array(
            ReplaceInsertTagsEvent::NAME => 'parseInsertTag'
        );
    }

    /**
     * Rewrite grid insert tags so that the refresh flag is added.
     *
     * @param string $buffer The template buffer.
     *
     * @return string
     */
    public function hookOutputFrontendTemplate($buffer)
    {
        return preg_replace(
            '/(\{\{grid::.*)\}\}/Ui',
            '$1|refresh}}',
            $buffer
        );
    }

    /**
     * Parse the insert tag.
     *
     * @param ReplaceInsertTagsEvent $event The subscribed event.
     *
     * @return void
     */
    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());
        }
    }

    /**
     * Get a walker for the subscribed event.
     *
     * @param ReplaceInsertTagsEvent $event The subscribed event.
     *
     * @return Walker|null
     */
    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];
    }

    /**
     * Translate event params.
     *
     * @param ReplaceInsertTagsEvent $event The subscribed event.
     *
     * @return array
     */
    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);
    }
}


<?php

/*
 * GestPayCryptWS
 * Copyright (C) 2015 Gabriele Brosulo <gabriele@brosulo.net>
 *                    Alessandro Astarita <aleast@capri.it>
 *
 * http://github.com/asterixcapri/gestpaycrypt-php
 *
 * GestPayCryptWS is the new implementation of GestPayCrypt using SOAP WebServices
 * It allows to connect to online credit card payment GestPay.
 *
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details at
 * http://www.gnu.org/copyleft/lgpl.html
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 */

class GestPayCryptWS
{
    private $context;
    private $shopLogin;
    private $currency;
    private $amount;
    private $shopTransactionId;
    private $cardNumber;
    private $expMonth;
    private $expYear;
    private $buyerName;
    private $buyerEmail;
    private $language;
    private $customInfo;
    private $authorizationCode;
    private $errorCode;
    private $errorDescription;
    private $bankTransactionId;
    private $alertCode;
    private $alertDescription;
    private $encryptedString;
    private $decrypted;
    private $transactionResult;
    private $transport;
    private $domainName;
    private $domainNameS2S;
    private $testDomainName;
    private $paymentUrl;
    private $separator;
    private $min;
    private $cvv;
    private $country;
    private $vbv;
    private $vbvRisp;
    private $threeDLevel;
    private $testEnv;

    public function __construct()
    {
        $this->shopLogin = "";
        $this->currency = "";
        $this->amount = "";
        $this->shopTransactionId = "";

        $this->testEnv = false;
        $this->domainName = "ecomm.sella.it";
        $this->domainNameS2S = "ecommS2S.sella.it";
        $this->testDomainName = "testecomm.sella.it";
        $this->paymentUrl = "/pagam/pagam.aspx";
        $this->separator = "*P1*";

        $this->setContext();
    }

    public function setTestEnv($enable)
    {
        $this->testEnv = $enable;
        return $this;
    }

    public function getTestEnv()
    {
        return $this->testEnv;
    }

    public function setShopLogin($val)
    {
        $this->shopLogin = $val;
        return $this;
    }

    public function getShopLogin()
    {
        return $this->shopLogin;
    }

    public function setCurrency($val)
    {
        $this->currency = $val;
        return $this;
    }

    public function getCurrency()
    {
        return $this->currency;
    }

    public function setAmount($val)
    {
        $this->amount = $val;
        return $this;
    }

    public function getAmount()
    {
        return $this->amount;
    }

    public function setShopTransactionID($val)
    {
        $this->shopTransactionId = urlencode(trim($val));
        return $this;
    }

    public function getShopTransactionID()
    {
        return urldecode($this->shopTransactionId);
    }

    public function setCardNumber($val)
    {
        $this->cardNumber = $val;
        return $this;
    }

    public function getCardNumber()
    {
        return $this->cardNumber;
    }

    public function setExpMonth($val)
    {
        $this->expMonth = $val;
        return $this;
    }

    public function getExpMonth()
    {
        return $this->expMonth;
    }

    public function setExpYear($val)
    {
        $this->expYear = $val;
        return $this;
    }

    public function getExpYear()
    {
        return $this->expYear;
    }

    public function setMin($val)
    {
        $this->min = $val;
        return $this;
    }

    public function getMin()
    {
        return $this->min;
    }

    public function setCvv($val)
    {
        $this->cvv = $val;
        return $this;
    }

    public function getCvv()
    {
        return $this->cvv;
    }

    public function setBuyerName($val)
    {
        $this->buyerName = urlencode(trim($val));
        return $this;
    }

    public function getBuyerName()
    {
        return urldecode($this->buyerName);
    }

    public function setBuyerEmail($val)
    {
        $this->buyerEmail = trim($val);
        return $this;
    }

    public function getBuyerEmail()
    {
        return $this->buyerEmail;
    }

    public function setLanguage($val)
    {
        $this->language = trim($val);
        return $this;
    }

    public function getLanguage()
    {
        return $this->language;
    }

    public function setCustomInfo($val)
    {
        $this->customInfo = urlencode(trim($val));
        return $this;
    }

    public function getCustomInfo()
    {
        return urldecode($this->customInfo);
    }

    /**
     * @param array $arrval
     * @return GestPayCryptWS|bool
     */
    public function setCustomInfoFromArray(array $arrval)
    {
        if (!is_array($arrval)) {
            return false;
        }

        //check string validity
        foreach ($arrval as $key => $val) {
            if (strlen($val) > 300) {
                $val = substr($val, 0, 300);
            }

            $arrval[$key] = urlencode($val);
        }

        $this->customInfo = http_build_query($arrval, '', $this->separator);

        return $this;
    }

    public function getCustomInfoToArray()
    {
        $allinfo = explode($this->separator, $this->customInfo);
        $customInfoArray = array();

        foreach ($allinfo as $singleInfo) {
            $tagval = explode("=", $singleInfo);
            $customInfoArray[$tagval[0]] = urldecode($tagval[1]);
        }

        return $customInfoArray;
    }

    public function setEncryptedString($val)
    {
        $this->encryptedString = $val;
        return $this;
    }

    public function getEncryptedString()
    {
        return $this->encryptedString;
    }

    public function setCountry($country)
    {
        $this->country = $country;
        return $this;
    }

    public function getCountry()
    {
        return $this->country;
    }

    public function setVbv($vbv)
    {
        $this->vbv = $vbv;
        return $this;
    }

    public function getVbv()
    {
        return $this->vbv;
    }

    public function setVbvRisp($vbvRisp)
    {
        $this->vbvRisp = $vbvRisp;
        return $this;
    }

    public function getVbvRisp()
    {
        return $this->vbvRisp;
    }

    public function set3dLevel($val)
    {
        $this->threeDLevel = $val;
        return $this;
    }

    public function get3dLevel()
    {
        return $this->threeDLevel;
    }

    public function setAuthorizationCode($val)
    {
        $this->authorizationCode = $val;
        return $this;
    }

    public function getAuthorizationCode()
    {
        return $this->authorizationCode;
    }

    /**
     * @param string $errorCode
     * @param string $errorDescription
     * @return GestPayCryptWS
     */
    protected function setError($errorCode, $errorDescription)
    {
        $this->errorCode = $errorCode;
        $this->errorDescription = $errorDescription;
        return $this;
    }

    public function getErrorCode()
    {
        return $this->errorCode;
    }

    public function getErrorDescription()
    {
        return $this->errorDescription;
    }

    public function setBankTransactionID($val)
    {
        $this->bankTransactionId = urlencode(trim($val));
        return $this;
    }

    public function getBankTransactionID()
    {
        return $this->bankTransactionId;
    }

    public function setTransactionResult($val)
    {
        $this->transactionResult = $val;
        return $this;
    }

    public function getTransactionResult()
    {
        return $this->transactionResult;
    }

    public function setAlertCode($alertCode)
    {
        $this->alertCode = $alertCode;
        return $this;
    }

    public function getAlertCode()
    {
        return $this->alertCode;
    }

    public function setAlertDescription($alertDescription)
    {
        $this->alertDescription = $alertDescription;
        return true;
    }

    public function getAlertDescription()
    {
        return $this->alertDescription;
    }

    public function setTransport($type)
    {
        $this->transport = $type;
        return $this;
    }

    public function getTransport()
    {
        return $this->transport;
    }

    public function getDomainName()
    {
        if ($this->testEnv === true) {
            return $this->testDomainName;
        }

        return $this->domainName;
    }

	public function getDomainNameS2S()
    {
        if ($this->testEnv === true) {
            return $this->testDomainName;
        }
        return $this->domainNameS2S;
    }

    public function getPaymentUrl()
    {
        return $this->paymentUrl;
    }

    public function setPaymentUrl($url)
    {
        $this->paymentUrl = $url;
        return $this;
    }

    public function setSeparator($separator)
    {
        $this->separator = $separator;
        return $this;
    }

    public function getSeparator()
    {
        return $this->separator;
    }

    public function setDecrypted($decrypted)
    {
        $this->decrypted = $decrypted;
        return $this;
    }

    public function getDecrypted()
    {
        return $this->decrypted;
    }

    /**
     * @param string $ciphers allowed chipers
     * @return GestPayCryptWS
     */
    public function setContext($ciphers = 'DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA:AES256-SHA:KRB5-DES-CBC3-MD5:KRB5-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:EDH-DSS-DES-CBC3-SHA:DES-CBC3-SHA:DES-CBC3-MD5:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA:AES128-SHA:RC2-CBC-MD5:KRB5-RC4-MD5:KRB5-RC4-SHA:RC4-SHA:RC4-MD5:RC4-MD5:KRB5-DES-CBC-MD5:KRB5-DES-CBC-SHA:EDH-RSA-DES-CBC-SHA:EDH-DSS-DES-CBC-SHA:DES-CBC-SHA:DES-CBC-MD5:EXP-KRB5-RC2-CBC-MD5:EXP-KRB5-DES-CBC-MD5:EXP-KRB5-RC2-CBC-SHA:EXP-KRB5-DES-CBC-SHA:EXP-EDH-RSA-DES-CBC-SHA:EXP-EDH-DSS-DES-CBC-SHA:EXP-DES-CBC-SHA:EXP-RC2-CBC-MD5:EXP-RC2-CBC-MD5:EXP-KRB5-RC4-MD5:EXP-KRB5-RC4-SHA:EXP-RC4-MD5:EXP-RC4-MD5')
    {
        $this->context = stream_context_create(array(
            'ssl' => array(
                'ciphers' => $ciphers
            )
        ));

        return $this;
    }

    /**
     * @return A stream context resource.
     */
    public function getContext()
    {
        return $this->context;
    }

    /**
     *
     * @return string
     */
    public function getRedirectUrl()
    {
        return 'https://' . $this->getDomainName() . $this->getPaymentUrl() .
            '?a=' . $this->getShopLogin() .
            '&b=' . $this->getEncryptedString();
    }

    /**
     * Genera la URL del WSDL
     * @return string
     */
    private function getWsdl()
    {
        return 'https://' . $this->getDomainNameS2S() .
            '/gestpay/gestpayws/WSCryptDecrypt.asmx?WSDL';
    }

    /**
     * Genera l'array dei parametri per l'encrypt
     * @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());
    }

    /**
     * Genera l'array dei parametri per il decrypt
     * @return array
     */
    private function getDecParams()
    {
        // Parametri obbligatori
        $params = array(
            'shopLogin' => $this->getShopLogin(),
            'CryptedString' => $this->getEncryptedString(),
        );

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

    /**
     * Parametri opzionali
     * @todo Gestire parametri opzionali
     * @return array
     */
    private function getOptParams()
    {
        $params = array();

        // Parametri opzionali
        if (isset($this->buyerName)) {
            $params['buyerName'] = $this->getBuyerName();
        }
        if (isset($this->buyerEmail)) {
            $params['buyerEmail'] = $this->getBuyerEmail();
        }
		if (isset($this->language)) {
            $params['languageId'] = $this->getLanguage();
        }
        if (isset($this->customInfo)) {
            $params['customInfo'] = $this->getCustomInfo();
        }
        return $params;
    }

    /**
     * @return bool
     */
    public function encrypt()
    {
        $retVal = false;
        $this->setError('0', '');

        if (empty($this->shopLogin)) {
            $this->setError('546', 'IDshop not valid');
            return false;
        }

        if (empty($this->currency)) {
            $this->setError('552', 'Currency not valid');
            return false;
        }

        if (empty($this->amount)) {
            $this->setError('553', 'Amount not valid');
            return false;
        }

        if (empty($this->shopTransactionId)) {
            $this->setError('551', 'Shop Transaction ID not valid');
            return false;
        }

        // Creo il SoapClient
        $client = new SoapClient($this->getWsdl(), array('stream_context' => $this->context));
        // Chiamo la funzione
        $objectresult = $client->__soapCall("Encrypt", array($this->getEncParams()));

        // Leggo l'output
        $res = new SimpleXMLElement($objectresult->EncryptResult->any);

        if ($res !== false) {
            // Parso i contenuti della risposta
            $TransactionType = (string) $res->TransactionType;
            $TransactionResult = (string) $res->TransactionResult;
            $EncryptedString = (string) $res->CryptDecryptString;
            $ErrorCode = (string) $res->ErrorCode;
            $ErrorDescription = (string) $res->ErrorDescription;

            // Gestione degli errori
            $this->setError($ErrorCode, $ErrorDescription);
            $this->setTransactionResult($TransactionResult);

            if ($ErrorCode == 0) {
                // Imposto la stringa criptata
                $this->setEncryptedString($EncryptedString);
                $retVal = true;
            }
        }

        return $retVal;
    }

    /**
     * @return bool
     */
    public function decrypt()
    {
        $retVal = false;
        $this->setError('0', '');

        if (empty($this->shopLogin)) {
            $this->setError('546', 'IDshop not valid');
            return false;
        }

        if (empty($this->encryptedString)) {
            $this->setError('1009', 'String to Decrypt not valid');
            return false;
        }

        // Creo il SoapClient
        $client = new SoapClient($this->getWsdl(), array('stream_context' => $this->context));
        // Chiamo la funzione
        $objectresult = $client->__soapCall("Decrypt", array($this->getDecParams()));

        // Leggo l'output
        $res = new SimpleXMLElement($objectresult->DecryptResult->any);
        if ($res !== false) {
            // Parso i contenuti della risposta
            $TransactionType = (string) $res->TransactionType;
            $TransactionResult = (string) $res->TransactionResult;
            $ErrorCode = (string) $res->ErrorCode;
            $ErrorDescription = (string) $res->ErrorDescription;

            // Gestione degli errori
            $this->setError($ErrorCode, $ErrorDescription);
            $this->setTransactionResult($TransactionResult);

            $this->setShopTransactionID((string) $res->ShopTransactionID);
            $this->setBankTransactionID((string) $res->BankTransactionID);
            $this->setAuthorizationCode((string) $res->AuthorizationCode);
            $this->setCurrency((int) $res->Currency);
            $this->setAmount((float) $res->Amount);
            $this->setCustomInfo((string) $res->CustomInfo);
            $this->setDecrypted((string) $res->asXML());

            if ($ErrorCode == 0) {
                // Decrypted
                $retVal = true;
            }
        }

        return $retVal;
    }
}


<?php

namespace Modules\Dynamicfield\Listener;

use Modules\Blog\Entities\Post;
use Modules\Dynamicfield\Utility\DynamicFields;
use Modules\Page\Entities\Page;

class UpdateProcess
{
    /**
     * Create the event listener.
     */
    public function __construct()
    {
        //
    }

    /**
     * Handle the event.
     *
     * @param PageWasUpdated $event
     */
    public function pageHandle($event)
    {
        $page = Page::find($event->pageId);
        $this->saveDynamicData($page, $event->data);
    }
    /**
     * Handle the event.
     *
     * @param BlogWasUpdated $event
     */
    public function blogHandle($event)
    {
        $post = Post::find($event->blogId);
        $this->saveDynamicData($post, $event->data);
    }
    public function handle($event)
    {
    }
    public function subscribe($events)
    {
        $events->listen(
            'Modules\Blog\Events\BlogWasUpdated',
            'Modules\Dynamicfield\Listener\UpdateProcess@blogHandle'
        );

        $events->listen(
            'Modules\Page\Events\PageWasUpdated',
            'Modules\Dynamicfield\Listener\UpdateProcess@pageHandle'
        );
    }
    // save data to dynamic database ;
    private function saveDynamicData($entity, $data)
    {
        $fields = new DynamicFields($entity);
        $fields->init($data);
        $fields->save();
    }
}


<?php

namespace Modules\Dynamicfield\Listener;

use Modules\Dynamicfield\Entities\Entity;
use Modules\Page\Events\PageWasReplicated;

class ReplicateProcess
{
    /**
     * Create the event listener.
     */
    public function __construct()
    {
        //
    }

    /**
     * Handle the event.
     *
     * @param PodcastWasPurchased $event
     */
    public function handle(PageWasReplicated $event)
    {
        $entity = new Entity();
        $entities = $entity->getFieldsByEntity($event->pageId);
        foreach ($entities as $item) {
            $item->duplicate($event->replicateId);
        }
    }
}


<?php

namespace Modules\Dynamicfield\Listener;

use Modules\Blog\Entities\Post;
use Modules\Blog\Events\BlogWasCreated;
use Modules\Dynamicfield\Utility\DynamicFields;
use Modules\Page\Entities\Page;
use Modules\Page\Events\PageWasCreated;

class AddNewProcess
{
    /**
     * Create the event listener.
     */
    public function __construct()
    {
        //
    }
    public function handle($event)
    {
    }
    /**
     * Handle the event.
     *
     * @param PageWasCreated $event
     */
    public function pageHandle($event)
    {
        $page = Page::firstOrNew(['id' => $event->pageId]);
        $this->saveDynamicData($page, $event->data);
    }
    /**
     * Handle the event.
     *
     * @param BlogWasCreated $event
     */
    public function blogHandle($event)
    {
        $post    = Post::firstOrNew(['id' => $event->blogId]);
        $this->saveDynamicData($post, $event->data);
    }
    public function subscribe($events)
    {
        $events->listen(
            'Modules\Blog\Events\BlogWasCreated',
            'Modules\Dynamicfield\Listener\AddNewProcess@blogHandle'
        );

        $events->listen(
            'Modules\Page\Events\PageWasCreated',
            'Modules\Dynamicfield\Listener\AddNewProcess@pageHandle'
        );
    }
    // save data to dynamic database ;
    private function saveDynamicData($entity, $data)
    {
        $fields = new DynamicFields($entity);
        $fields->init($data);
        $fields->save();
    }
}


<?php

namespace Modules\Dynamicfield\Http\Controllers\Admin;

use Collective\Html\FormFacade;
use Illuminate\Http\Request;
use Mcamara\LaravelLocalization\Facades\LaravelLocalization;
use Modules\Core\Http\Controllers\Admin\AdminBaseController;
use Modules\Dynamicfield\Entities\Group;
use Modules\Dynamicfield\Entities\Rule;
use Modules\Dynamicfield\Http\Requests\GroupFieldRequest;
use Modules\Dynamicfield\Repositories\GroupRepository;
use Modules\Dynamicfield\Utility\DynamicFields;
use Modules\Dynamicfield\Utility\Template;
use Modules\Page\Entities\Page;
use Modules\Page\Repositories\PageRepository;
use Request as BaseRequest;

class GroupFieldsController extends AdminBaseController
{
    /**
     * @var GroupRepository
     * @var PageRepository
     * @var RoleRepository
     */
    private $group;
    private $page;
    private $template;

    public function __construct(GroupRepository $group, PageRepository $page, Template $template)
    {
        parent::__construct();
        $this->group = $group;
        $this->page = $page;
        $this->template = $template;
    }

    /**
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
     */
    public function index()
    {
        $group = $this->group->all();

        return view('dynamicfield::admin.group.index', compact('group'));
    }

    /**
     * @param Group $group
     *
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
     */
    public function create(Group $group)
    {
        $fields = $group->getListFields();

        return view('dynamicfield::admin.group.edit', compact('group', 'fields'));
    }

    /**
     * @param GroupFieldRequest $request
     *
     * @return \Illuminate\Http\RedirectResponse
     */
    public function store(GroupFieldRequest $request)
    {
        $data = $request->all();
        $dataGroup = $data['group'];
        $dataFields = $data['field'];
        // reset key of array location
        $dataLocations     = array_values($data["location"]);
        $newDataLocations = array_map('array_values', $dataLocations);

        $bResult = $this->group->saveData($dataGroup, $dataFields, $newDataLocations);
        $groupId = @$data["group"]["id"];
        $tran_core = 'core::core.messages.resource created';
        if ($groupId > 0) {
            $tran_core = 'core::core.messages.resource updated';
        }
        if ($bResult) {
            flash()->success(trans($tran_core, ['name' => trans('dynamicfield::dynamicfield.title.field_group')]));
        }

        return redirect()->route('admin.dynamicfield.group.index');
    }

    /**
     * @param Group $group
     *
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
     */
    public function edit(Group $group)
    {
        $fields     = $group->getListFields();
        $locations  = Rule::where('group_id', '=', $group->id)->get();

        return view('dynamicfield::admin.group.edit', compact('group', 'fields', 'locations'));
    }

    /**
     * @param Group   $group
     * @param Request $request
     *
     * @return \Illuminate\Http\RedirectResponse
     */
    public function update(Group $group, Request $request)
    {
        $this->group->update($group, $request->all());
        flash()->success(trans('core::core.messages.resource updated', ['name' => trans('dynamicfield::dynamicfield.title.field_group')]));

        return redirect()->route('admin.dynamicfield.group.index');
    }

    /**
     * @param Group $group
     *
     * @return \Illuminate\Http\RedirectResponse
     */
    public function destroy(Group $group)
    {
        $this->group->destroy($group);
        flash()->success(trans('core::core.messages.resource deleted', ['name' => trans('dynamicfield::dynamicfield.title.field_group')]));

        return redirect()->route('admin.dynamicfield.group.index');
    }

    /**
     * @return \Illuminate\Http\JsonResponse
     */
    public function renderOption()
    {
        $type = $_REQUEST['field_type'];
        $index = $_REQUEST['field_index'];
        $repeaterIndex = $index;

        $optionClass = "Modules\Dynamicfield\Utility\Enum\Options\\" . ucfirst($type);
        $options = $optionClass::getList();
        $prefixName = 'field[%s]';
        $viewPath = 'dynamicfield::admin.group.partials.fields.' . $type;
        $fields = array();
        $html = view($viewPath, compact('index', 'options', 'fields', 'prefixName', 'repeaterIndex'));

        return response()->json(['html' => $html->render()]);
    }

    /**
     * @return \Illuminate\Http\JsonResponse
     */
    public function renderRepeaterOption()
    {
        $type = $_REQUEST['field_type'];
        $index = $_REQUEST['field_index'];
        $repeaterIndex = $_REQUEST['repeater_index'];

        $prefixName = sprintf('field[%s][repeater][%s]', $repeaterIndex, $index);
        $optionClass = "Modules\Dynamicfield\Utility\Enum\Options\\" . ucfirst($type);
        $options = $optionClass::getList();
        $viewPath = 'dynamicfield::admin.group.partials.fields.' . $type;
        $html = view($viewPath, compact('index', 'options', 'repeaterIndex', 'prefixName'));

        return response()->json(['html' => $html->render()]);
    }

    /**
     * @return \Illuminate\Http\JsonResponse
     */
    public function ajaxRender()
    {
        $this->assetPipeline->requireJs('ckeditor.js');
        $request = BaseRequest::all();
        $template = $request['template'];
        $entityType = $request['entity_type'];
        $id = $request['id'];
        $entity = new $entityType();
        if (get_class($entity) == "stdClass") {
            $entity->id = null;
        } else {
            $entity = $entity->firstOrNew(['id' => $id]);
        }
        $entity->template = $template;
        $advanceFields = new DynamicFields($entity);
        $advanceFields->init();
        $locale = array_keys(LaravelLocalization::getSupportedLocales());
        $jsonData = array();
        foreach ($locale as $v) {
            $jsonData['html'][$v] = $advanceFields->renderFields($v);
        }
        $jsonData['locale'] = $locale;

        return response()->json($jsonData);
    }

    public function duplicate(Page $page)
    {
        $this->page->replicate($page);

        flash(trans('dynamicfield::messages.page.duplicate successful'));

        return redirect()->route('admin.page.page.index');
    }

    /**
     * @return \Illuminate\Http\JsonResponse
     */
    public function renderLocationDrop()
    {
        $selected   = $_REQUEST['selected'];
        $dropName    = $_REQUEST['dropName'];
        $value      = null;
        if ($_REQUEST['value'] != "undefined") {
            $value    = $_REQUEST['value'];
        }
        $name       = str_replace("parameter", "value", $dropName);
        $arrData   = array();
        switch ($selected) {
            case "type":
                $arrData = config('asgard.dynamicfield.config.entity-type');
                break;
            case "template":
                $arrData    = $this->template->getTemplates();
                break;
        }
        $html = FormFacade::select($name, $arrData, $value, ['class' => "form-control"]);

        return response()->json(['html' => $html]);
    }
}


<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;

class CreateDynamicfieldTable extends Migration
{
    /**
     * Run the migrations.
     */
    public function up()
    {
        Schema::create('dynamicfield__groups', function (Blueprint $table) {
            $table->engine = 'InnoDB';
            $table->increments('id');
            $table->string('name');
            $table->string('template');
            $table->timestamps();
        });
        Schema::create('dynamicfield__fields', function (Blueprint $table) {
            $table->engine = 'InnoDB';
            $table->increments('id');
            $table->integer('group_id')->unsigned();
            $table->string('data', 500);
            $table->string('type');
            $table->string('name');
            $table->string('order')->default(0);
            $table->foreign('group_id')->references('id')->on('dynamicfield__groups')->onDelete('cascade');
            $table->timestamps();
        });

        Schema::create('dynamicfield__entities', function (Blueprint $table) {
            $table->engine = 'InnoDB';
            $table->increments('id');
            $table->integer('entity_id')->unsigned();
            $table->integer('field_id')->unsigned();
            $table->string('entity_type', 200);
            $table->foreign('field_id')->references('id')->on('dynamicfield__fields')->onDelete('cascade');
            $table->timestamps();
        });

        Schema::create('dynamicfield__field_translations', function (Blueprint $table) {
            $table->engine = 'InnoDB';
            $table->increments('id');
            $table->integer('entity_field_id')->unsigned();
            $table->string('locale', 5);
            $table->text('value');
            $table->foreign('entity_field_id')->references('id')->on('dynamicfield__entities')->onDelete('cascade');
            $table->timestamps();
        });

        Schema::create('dynamicfield__repeater_fields', function (Blueprint $table) {
            $table->engine = 'InnoDB';
            $table->increments('id');
            $table->integer('field_id')->unsigned();
            $table->string('data', 500);
            $table->string('type');
            $table->string('name');
            $table->string('order')->default(0);
            $table->foreign('field_id')->references('id')->on('dynamicfield__fields')->onDelete('cascade');
            $table->timestamps();
        });

        Schema::create('dynamicfield__repeater_translations', function (Blueprint $table) {
            $table->engine = 'InnoDB';
            $table->increments('id');
            $table->integer('entity_repeater_id')->unsigned();
            $table->string('locale', 5);
            $table->string('order')->default(0);
            $table->foreign('entity_repeater_id')->references('id')->on('dynamicfield__entities')->onDelete('cascade');
            $table->timestamps();
        });

        Schema::create('dynamicfield__repeater_values', function (Blueprint $table) {
            $table->engine = 'InnoDB';
            $table->increments('id');
            $table->integer('translation_id')->unsigned();
            $table->integer('field_id')->unsigned();
            $table->text('value');
            $table->foreign('translation_id')->references('id')->on('dynamicfield__repeater_translations')->onDelete('cascade');
            $table->foreign('field_id')->references('id')->on('dynamicfield__repeater_fields')->onDelete('cascade');
            $table->timestamps();
        });

        Schema::create('dynamicfield__rules', function (Blueprint $table) {
            $table->engine = 'InnoDB';
            $table->increments('id');
            $table->string('rule', 500);
            $table->integer('group_id')->unsigned();
            $table->foreign('group_id')->references('id')->on('dynamicfield__groups')->onDelete('cascade');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down()
    {
        Schema::drop('dynamicfield__repeater_values');
        Schema::drop('dynamicfield__repeater_translations');
        Schema::drop('dynamicfield__repeater_fields');
        Schema::drop('dynamicfield__field_translations');
        Schema::drop('dynamicfield__entities');
        Schema::drop('dynamicfield__fields');
        Schema::drop('dynamicfield__groups');
        Schema::drop('dynamicfield__rules');
    }
}


<?php

namespace Modules\Dynamicfield\Utility\Fields;

use Collective\Html\FormFacade;
use Modules\Dynamicfield\Entities\Entity;
use Request;

class File extends FieldBase
{
    /**
     * @var file
     */
    private $file;

    public function __construct($fieldInfo, $entityId, $locale, $dbData = null)
    {
        parent:: __construct($fieldInfo, $entityId, $locale, $dbData);
    }
    public function init($_default = null)
    {
        // get data from db;
        $entity = Entity::getEntity($this->entityId, $this->entityType, $this->fieldId);
        $this->model = $entity->getFieldByLocale($this->locale);
        $files = Request::file();
        $this->file = @$files[$this->locale]['fields'][$this->fieldId]['value'];

        if (!isset($this->file)) {
            $this->value = $this->model->value;
            if (!$this->model->id) {
                $this->value = $this->getOption('default');
            }
        } else {
            $fileName = $this->entityId . '_' . $this->fieldId . '.' . $this->file->getClientOriginalExtension();
            $this->value = $fileName;
        }
    }

    /**
     * Check validator with field.
     *
     * @return bool
     */
    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;
    }

    /**
     * Render html of field.
     *
     * @return string
     */
    public function render()
    {
        $attrs = array();
        $id = $this->getHtmlId();
        $name = $this->getHtmlName();
        $label = $this->getLabel();
        $img = '';
        $cssClass = 'file';
        $errorMessage = '';
        $attrs['id'] = $id;
        if (!$this->isValid) {
            $errorMessage = sprintf("%s", $this->getErrorMessage());
            $cssClass .= ' error';
        }

        if ($this->getOption('required') == 'true') {
            $cssClass .= ' required';
        }
        if ($this->value) {
            $imgPath = $this->getDisplayValue();
            $img = sprintf("", $imgPath);
        }
        $attrs['class'] = $cssClass;

        $html = '';
        if (!empty($label)) {
            $html .= FormFacade::label($label);
        }
        $html                .= FormFacade::file($name, $attrs) . $errorMessage;
        $html                .= $img;

        $html = sprintf($this->htmlItemTemplate, $html);

        return $html;
    }

    /**
     * Get error message.
     *
     * @return string
     */
    public function getErrorMessage()
    {
        $error = $this->getOption('error_message');

        return $error;
    }

    /**
     * Show data file when isset.
     *
     * @return string
     */
    public function getDisplayValue()
    {
        $value = $this->value;
        if ($value) {
            $value = config('asgard.dynamicfield.config.files-path') . $value;
        }

        return $value;
    }

    /**
     * Override base method.
     */
    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 loadFieldData()
    {
    }
}


<?php

namespace Modules\Dynamicfield\Utility;

use Mcamara\LaravelLocalization\Facades\LaravelLocalization;

class DynamicFields
{
    protected $entities;
    private $request = null;
    private $locale;
    private $entity;
    private $type;

    public function __construct($entity, $locale = null)
    {
        $this->locale = $locale;
        $this->entity = $entity;
        $this->type = get_class($entity);
    }

    /**
     * Set entity data.
     *
     * @param null $default
     */
    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;
            }
        }
    }

    /**
     * Render by locale.
     *
     * @param $locale
     *
     * @return mixed
     */
    public function renderFields($locale)
    {
        $entity = $this->entities[$locale];
        if (isset($this->request)) {
            $entity->valid();
        }

        $html = $entity->render();

        return $html;
    }

    /**
     * Get field data.
     *
     * @param $fieldName
     * @param string $locale
     *
     * @return string
     */
    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 list fields data.
     *
     * @param string $locale
     *
     * @return mixed
     */
    public function getFieldValues($locale = 'en')
    {
        $entity = $this->entities[$locale];
        $values = $entity->values();

        return $values;
    }

    /**
     * Check valid entity.
     *
     * @return bool
     */
    public function valid()
    {
        $isValid = true;

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

        return $isValid;
    }

    /**
     * Save field data.
     *
     * @return bool
     */
    public function save()
    {
        $isSave = true;
        foreach ($this->entities as $entity) {
            $isSave = $entity->save();
            if (!$isSave) {
                break;
            }
        }

        return $isSave;
    }
}


<?php

namespace Modules\Dynamicfield\Composers;

use Illuminate\Contracts\View\View;
use Modules\Dynamicfield\Utility\DynamicFields;

class DynamicfieldViewComposer
{
    /**
     * Assign dynamicField to view
     *
     * @param View $view
     */
    public function compose(View $view)
    {
        $this->assignDynamicFieldsToPageObject($view);
    }

    /**
     * Pass dynamicFields to view
     *
     * @param $view
     * @return mixed
     */
    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;
    }
}


<?php

namespace Modules\Dynamicfield\Entities;

use Illuminate\Database\Eloquent\Model;

;

class Entity extends Model
{
    protected $table = 'dynamicfield__entities';
    protected $fillable = ['entity_id', 'field_id', 'entity_type'];
    /**
     * Create Relationship with FieldTranslation.
     *
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function fields()
    {
        return $this->hasMany('Modules\Dynamicfield\Entities\FieldTranslation', 'entity_field_id', 'id');
    }

    /**
     * Create Relationship with RepeaterTranslation.
     *
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function repeaters()
    {
        return $this->hasMany('Modules\Dynamicfield\Entities\RepeaterTranslation', 'entity_repeater_id', 'id');
    }

    /**
     * Create Relationship with Field.
     *
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function defindFields()
    {
        return $this->belongsTo('Modules\Dynamicfield\Entities\Field', 'field_id', 'id');
    }

    /**
     * Get list fields by locale.
     *
     * @param string $locale
     *
     * @return FieldTranslation
     */
    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 static function getAllDataFields($entityId, $entityType)
    {
        $fields = \DB::table('dynamicfield__entities')
            ->join('dynamicfield__field_translations', 'dynamicfield__entities.id', '=', 'dynamicfield__field_translations.entity_field_id')
            ->select('dynamicfield__entities.field_id', 'dynamicfield__field_translations.locale', 'dynamicfield__field_translations.value')
            ->where('dynamicfield__entities.entity_id', '=', $entityId)
            ->where('dynamicfield__entities.entity_type', '=', $entityType)
            ->get();

        return $fields;
    }

    public static function getAllDataTranactionRepeater($entityId, $entityType, $fieldId, $locale)
    {
        $fields = \DB::table('dynamicfield__entities')
            ->join('dynamicfield__repeater_translations', function ($join) use ($locale) {
                $join->on('dynamicfield__entities.id', '=', 'dynamicfield__repeater_translations.entity_repeater_id')->where('dynamicfield__repeater_translations.locale', '=', $locale);
            })
            ->select('dynamicfield__repeater_translations.id', 'dynamicfield__repeater_translations.locale')
            ->OrderBy('dynamicfield__repeater_translations.order')
            ->where('dynamicfield__entities.entity_id', '=', $entityId)
            ->where('dynamicfield__entities.field_id', '=', $fieldId)
            ->where('dynamicfield__entities.entity_type', '=', $entityType)
            ->get();

        return $fields;
    }

    public static function getAllDataTranactionRepeaterFields($entityId, $entityType, $fieldId, $locale)
    {
        $fields = \DB::table('dynamicfield__entities')
            ->join('dynamicfield__repeater_translations', function ($join) use ($locale) {
                $join->on('dynamicfield__entities.id', '=', 'dynamicfield__repeater_translations.entity_repeater_id')->where('dynamicfield__repeater_translations.locale', '=', $locale);
            })
            ->join('dynamicfield__repeater_values', 'dynamicfield__repeater_translations.id', '=', 'dynamicfield__repeater_values.translation_id')
            ->select('dynamicfield__repeater_values.*')
            ->where('dynamicfield__entities.entity_id', '=', $entityId)
            ->where('dynamicfield__entities.field_id', '=', $fieldId)
            ->where('dynamicfield__entities.entity_type', '=', $entityType)
            ->get();

        return $fields;
    }

    /**
     * Get list repeater field by locale.
     *
     * @param $locale
     *
     * @return mixed
     */
    public function getRepeatersByLocale($locale)
    {
        $repeaters = $this->repeaters()
                            ->where('locale', $locale)
                            ->orderBy('order')
                            ->get();

        return $repeaters;
    }

    /**
     * Get entities by fieldID.
     *
     * @param $fieldId
     *
     * @return Entity
     */
    public function getEntitiesByFieldId($fieldId)
    {
        $values = $this->where('field_id', $fieldId)->get();
        if ($values->count()) {
            $object = $values[0];
        } else {
            $object = new self();
        }

        return $object;
    }

    /**
     * Find entities by entityID,type and fieldId.
     *
     * @param $query
     * @param $entityId
     * @param $entityType
     * @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;
    }

    /**
     * Find list fields by EntityId.
     *
     * @param $query
     * @param $entityId
     *
     * @return mixed
     */
    public function scopeGetFieldsByEntity($query, $entityId)
    {
        $entities = $query->where('entity_id', $entityId)->get();

        return $entities;
    }

    /**
     * Duplicate field of page.
     *
     * @param int $pageId
     *
     * @return Model
     */
    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;
    }

    /**
     * Get first value in Field model.
     *
     * @return mixed
     */
    public function getFieldType()
    {
        $field = $this->defindFields()->first();

        return $field->type;
    }
}


<?php

namespace Modules\Dynamicfield\Composers;

use Illuminate\Contracts\View\View;
use Mcamara\LaravelLocalization\Facades\LaravelLocalization;
use Modules\Dynamicfield\Utility\DynamicFields;
use Request;
use Route;

class FrontendViewComposer
{
    /**
     * @param View $view
     */
    public function compose(View $view)
    {
        $this->assignDynamicFieldsToPageObject($view);
    }

    /**
     * @param $view
     *
     * @return mixed
     */
    private function assignDynamicFieldsToPageObject($view)
    {
        $arrAllow = ['page', 'homepage',"en.blog.slug"];
        $data = $view->getData();
        $routName = Route::currentRouteName();

        if (in_array($routName, $arrAllow)) {
            $arrType = config('asgard.dynamicfield.config.entity-type');
            $arrType =  array_keys($arrType);
            if (count($data)) {
                foreach ($data as $item) {
                    if (is_object($item)) {
                        $className = get_class($item);
                        if (in_array($className, $arrType)) {
                            $locale = LaravelLocalization::getCurrentLocale();
                            $request = Request::all();
                            $dynamicFields = new DynamicFields($item, $locale);
                            $dynamicFields->init($request);
                            $fieldValues = $dynamicFields->getFieldValues($locale);
                            $view->with('dynamicfields', $fieldValues);
                        }
                    }
                }
            }
        }

        return $view;
    }
}


<?php

namespace Modules\Dynamicfield\Utility\Fields;

use Collective\Html\FormFacade;

class Image extends FieldBase
{
    public function __construct($fieldInfo, $entityId, $locale, $dbData = null)
    {
        parent:: __construct($fieldInfo, $entityId, $locale, $dbData);
    }
    /**
     * Check validator with field.
     *
     * @return bool
     */
    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;
    }

    /**
     * Render html of field.
     *
     * @return string
     */
    public function render()
    {
        $attrs = array();
        $id = $this->getHtmlId();
        $name = $this->getHtmlName();
        $label = $this->getLabel();
        $cssClass = 'file';
        $attrs['id'] = $id;

        if ($this->getOption('required') == 'true') {
            $cssClass .= ' required';
        }
        $value = $this->value;
        $attrs['class'] = $cssClass;
        $html = '';
        if (!empty($label)) {
            $html .= FormFacade::label($label);
        }
        $html            .= view('dynamicfield::admin.dynamicfield.media-link', compact('name', 'id', 'value'))->render();

        $html = sprintf($this->htmlItemTemplate, $html);

        return $html;
    }

    /**
     * Get error message.
     *
     * @return string
     */
    public function getErrorMessage()
    {
        $error = $this->getOption('error_message');

        return $error;
    }

    /**
     * Show data file when isset.
     *
     * @return string
     */
    public function getDisplayValue()
    {
        $value = $this->value;

        return $value;
    }

    public function loadFieldData()
    {
    }
}


<?php

namespace Modules\Dynamicfield\Utility;

use Modules\Dynamicfield\Entities\Entity as EntityModel;
use Modules\Dynamicfield\Entities\Group;
use Modules\Dynamicfield\Entities\Rule;
use Modules\Dynamicfield\Utility\Fields\File;
use Modules\Dynamicfield\Utility\Fields\Image;
use Modules\Dynamicfield\Utility\Fields\Number;
use Modules\Dynamicfield\Utility\Fields\Repeater;
use Modules\Dynamicfield\Utility\Fields\Text;
use Modules\Dynamicfield\Utility\Fields\Textarea;
use Modules\Dynamicfield\Utility\Fields\Wysiwyg;

class Entity
{
    private $template;
    private $entityId;
    private $locale;
    private $type;
    private $groupFields;
    private $fieldValues;
    private $fieldInDB ;
    private $htmlItemTemplate = "

%s

%s

";

    /**
     * Constructor.
     *
     * @param $entityId
     * @param $template
     * @param $locale
     * @param $type
     */
    public function __construct($entityId, $template, $locale, $type)
    {
        $this->template = $template;
        $this->entityId = $entityId;
        $this->locale = $locale;
        $this->type = $type;
    }

    /**
     * Get and inital group data that match with rule.
     *
     * @param null $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);
            }
        }
    }

    /**
     * Check validation of field.
     *
     * @return bool
     */
    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;
    }

    /**
     * Render hmtl of group.
     *
     * @return string
     */
    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;
    }

    /**
     * Save group field data.
     *
     * @return bool
     */
    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;
    }

    /**
     * Get field value.
     *
     * @return mixed
     */
    public function values()
    {
        return $this->fieldValues;
    }

    /**
     * Get GroupFields base on rule.
     *
     * @param $options
     *
     * @return array
     */
    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;
    }

    /**
     * Parse and Match rule with options.
     *
     * @param $rule
     * @param $options
     *
     * @return bool
     */
    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;
    }

    /**
     * Initial fields of each group and assign to GroupFields array.
     *
     * @param $group
     * @param null $default
     */
    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;
        }
    }

    /**
     * Get field of data in browser.
     *
     * @param $data
     *
     * @return array
     */
    private function getFieldPostData($data)
    {
        $arrData = array();

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

        return $arrData;
    }

    public function getFieldDataInDB($fieldId, $locale)
    {
        $fieldValue = "";
        $index = -1;
        foreach ($this->fieldInDB as $k=>$v) {
            if ($v->locale == $locale && $v->field_id == $fieldId) {
                $fieldValue = $v->value;
                $index = $k ;
                break;
            }
        }
        // remove item to improve performance
        if ($index) {
            unset($this->fieldInDB[$index]);
        }

        return $fieldValue;
    }
}


<?php

/*
 * This file is part of php-drawille
 *
 * (c) Jeff Welch <whatthejeff@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Drawille;

/**
 * Pixel surface
 *
 * @author Jeff Welch <whatthejeff@gmail.com>
 */
class Canvas
{
    /**
     * Dots:
     *
     *   ,___,
     *   |1 4|
     *   |2 5|
     *   |3 6|
     *   |7 8|
     *   `````
     *
     * @var array
     * @see http://www.alanwood.net/unicode/braille_patterns.html
     */
    private static $pixel_map = [
        [0x01, 0x08],
        [0x02, 0x10],
        [0x04, 0x20],
        [0x40, 0x80]
    ];

    /**
     * Braille characters starts at 0x2800
     *
     * @var integer
     */
    private static $braille_char_offset = 0x2800;

    /**
     * Canvas representation
     *
     * @var array
     */
    private $chars = [];

    /**
     * Clears the canvas
     */
    public function clear() {
        $this->chars = [];
    }

    /**
     * Sets a pixel at the given position
     *
     * @param integer $x x position
     * @param integer $y y position
     */
    public function set($x, $y) {
        list($x, $y, $px, $py) = $this->prime($x, $y);
        $this->chars[$py][$px] |= $this->getDotFromMap($x, $y);
    }

    /**
     * Unsets a pixel at the given position
     *
     * @param integer $x x position
     * @param integer $y y position
     */
    public function reset($x, $y) {
        list($x, $y, $px, $py) = $this->prime($x, $y);
        $this->chars[$py][$px] &= ~$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 get($x, $y) {
        list($x, $y, , , $char) = $this->prime($x, $y);
        return (bool) ($char & $this->getDotFromMap($x, $y));
    }

    /**
     * Toggles the pixel state on/off at a given position
     *
     * @param integer $x x position
     * @param integer $y y position
     */
    public function toggle($x, $y) {
        $this->get($x, $y) ? $this->reset($x, $y) : $this->set($x, $y);
    }

    /**
     * Gets a line
     *
     * @param integer $y     y position
     * @param array $options options
     *
     * @return string line
     */
    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 all lines
     *
     * @param array $options options
     *
     * @return array 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));
    }

    /**
     * Gets a string representation of the canvas
     *
     * @param array $options options
     *
     * @return string representation
     */
    public function frame(array $options = []) {
        return join("\n", $this->rows($options));
    }

    /**
     * Gets the canvas representation.
     *
     * @return array characters
     */
    public function getChars() {
      return $this->chars;
    }

    /**
     * Gets a braille unicode character
     *
     * @param integer $code character code
     *
     * @return string braille
     */
    private function toBraille($code) {
        return html_entity_decode('&#' . (self::$braille_char_offset + $code) . ';', ENT_NOQUOTES, 'UTF-8');
    }

    /**
     * Gets a dot from the pixel map.
     *
     * @param integer $x x position
     * @param integer $y y position
     *
     * @return integer dot
     */
    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];
    }

    /**
     * Autovivification for a canvas position.
     *
     * @param integer $x x position
     * @param integer $y y position
     *
     * @return array
     */
    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]];
    }
}