HEX
Server: Microsoft-IIS/8.5
System: Windows NT YDAWBH120 6.3 build 9600 (Windows Server 2012 R2 Standard Edition) AMD64
User: tentjecom_web (0)
PHP: 7.4.14
Disabled: NONE
Upload Files
File: D:/HostingSpaces/SBogers85/equichecker.com/app/KommaApp/Kms/Core/Sections/KmsSection.php
<?php
/**
 *
 *
 * @author      Komma <info@komma.pro>
 * @copyright   (c) 2012-2016, Komma Mediadesign
 */

namespace KommaApp\Kms\Core\Sections;

use Illuminate\Events\Dispatcher;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\ViewErrorBag;
use KommaApp\Kms\Core\Kms;
use KommaApp\Kms\Core\KmsRepository;
use KommaApp\Languages\Models\Language;
use KommaApp\Products\Models\Product;
use KommaApp\Products\Models\ProductVariant;
use KommaApp\Sites\Models\Site;
use MyProject\Proxies\__CG__\stdClass;
use KommaApp\Core\Services\EavService;

abstract class KmsSection
{
    protected $kms;
    protected $repository;

    protected $eventListeners = [];
    protected $modelAttributesData = [];

    protected $tabs;
    protected $attributes = []; // [ attributes... ]
    protected $proccessedAttributes = [];
    protected $model = null;
    protected $models = [];

    //True if the models uses an eav
    protected $eav = false;

    protected $errors = [];

    protected $title = "";
    protected $subTitle = "";
    protected $slug = "";

    public $submitButtonLabel = "save";
    public $submitRoute = null;

    public $type = 'model';

    public $keyAsArray = false;
    public $keyArrayKey = '';

    /*
     * Protected actions
     * options:
     * all - can be accessed by everybody
     * admin - can be accessed only by super admins
     * none - can be accessed by nobody
     */
    public $showSave = 'all';
    public $showDelete = 'all';
    public $showCreate = 'all';

    //When this var is true, the right pane will be generated
    public $showEntity = true;

    function __construct(
        Kms $kms,
        KmsRepository $repository,
        KmsSectionTabs $tabs)
    {
        $this->kms = $kms;
        $this->repository = $repository;
        $this->tabs = $tabs;

        $this->initializeEventListeners();
        $this->loadModels();
    }

    protected function initializeEventListeners()
    {
        foreach ($this->eventListeners as $listenerKey => $listenerValue) {
            \Event::listen($listenerKey, $listenerValue);
        }
    }

    public function getRepository()
    {
        return $this->repository;
    }

    public function getTitle()
    {
        return $this->title;
    }

    public function getSubTitle()
    {
        return $this->subTitle;
    }

    public function getSlug()
    {
        return $this->slug;
    }

    public function getEntities()
    {
        return $this->models;
    }

    public function setKeyAsArray($keyAsArray)
    {
        $this->keyAsArray = $keyAsArray;
    }

    public function setKeyArrayKey($keyArrayKey)
    {
        $this->keyArrayKey = $keyArrayKey;

    }


    /**
     * This method will generate the list of models.
     * These are used in the sidebar.
     *
     * @return mixed
     */
    public function loadModels()
    {
        //If getSortable() returns true, dont load the models, they are loaded via Ajax
        if ($this->getSortable()) return null;
        return $this->models = $this->repository->getModels();
    }

    /**
     * This method returns the thumbnail for the top bar
     * s     *
     * @return string
     */
    public function getThumbnail()
    {
        //Check if a thumbnail is set
        if (isset($this->model->thumbnail)) {
            //If there is an image_url set, return with image tags
            if (isset($this->model->thumbnail['image_url'])) return '<img src="' . $this->model->thumbnail['image_url'] . '""/>';

            //If there is a string set, return only the string
            if (isset($this->model->thumbnail['string'])) return $this->model->thumbnail['string'];
        }
        //Return empty string
        return '';

    }


    /**
     * This method is called when an model is called
     * eg. for the edit form
     *
     * @param null $id
     * @return null
     */
    public function loadModel($id = null)
    {
        $this->model = $this->repository->getModel($id);


        //set the data in the attributes
        $this->parseModelAttributesData($id);

        return $this->model;
    }

    public function setModel($model)
    {
        if ($model == null) {
            $this->model = $this->repository->newModel();
        } else {
            $this->model = $model;
        }
        $this->parseModelAttributesData(true);

        return $this->model;
    }

    /**
     * This method returns the model id.
     * When there is no model it returns false.
     *
     * @return mixed False, model id
     */
    public function getModelId()
    {
        //Check if there is an model, return false
        if (!$this->model) return false;
        //Return the model id
        return $this->model->id;
    }

    public function getModel()
    {
        return $this->model;
    }


    /**
     * This method returns the title of the model
     * It will check if there is an model title
     * or returns new {type}
     *
     * @return string
     */
    public function getModelTitle()
    {
        //If there is an title set use this
        if (isset($this->model->title)) return $this->model->title;

        //No model title return new {type}
        return \Lang::get('kms/global.new') . ' ' . \Lang::get('kms/' . $this->slug . '.type');

    }

    /**
     * This method returns the tab array
     *
     * @return array
     */
    public function getTabs()
    {
        return $this->tabs->getTabs();
    }

    /**
     * This method returns the attrinutes array
     *
     * @return array
     */
    public function getAttributes()
    {
        return $this->attributes;
    }

    /**
     * This method renders the view for the pages
     *
     * @return mixed
     */
    public function render()
    {
        //Load the models for the sidebar
        $this->getEntities();
        return \View::make('kms/section.index', [
            'kms' => $this->kms,
            'section' => $this
        ]);
    }

    /**
     * This method will trigger the save method
     *
     * @param $id
     */
    public function update($id)
    {
        $this->save($id);
    }

    /**
     * This method creates or updates a model.
     * Based on the input data of the form.
     *
     * @param null $id
     * @return $id
     */
    public function save($id = null)
    {
        //Render the form input eg. hash de password
        $input = $this->renderInput();
        //This will trigger the repository saveModel method
        $id = $this->repository->saveModel($input, $id);

        //Fire the event saved method
        \Event::fire('kms.entity.saved.' . $this->slug, $this->model);

        //Return the id
        return $id;
    }

    /**
     * This method calls the destroyModel method
     * from the give repository class.
     *
     * @param $id
     * @return mixed
     */
    public function destroy($id)
    {
        return $this->repository->destroyModel($id);
    }

    /**
     * Thhis method creates a error list / attribute
     *
     * @param ViewErrorBag|null $errors
     */
    public function setErrors(ViewErrorBag $errors = null)
    {
        //If errors are empty; return
        if (!$errors) return;
        //Get the errors from the error
        $this->errors = $errors->getMessages();
        foreach ($this->attributes as $attribute) {
            if (isset($this->errors[$attribute->key])) {
                $attribute->setErrors($this->errors[$attribute->key]);
            }
        }

    }

    /**
     * Vallidate the data based on the given;
     * rules, messages and values.
     *
     * @param null $validation
     * @return bool
     */
    public function validateAttributes($validation = null)
    {
        $this->extendValidator();

        if (!$validation) return false;
        $values = $rules = $messages = [];
        $values = \Input::all();
        $rules = $validation['rules'];

        $messages = $validation['messages'];
        $validator = \Validator::make($values, $rules, $messages);

        return $validator;
    }


    /**
     * This method is used to show/hide the create button
     * Based on the user and the settings it will return true or false
     *
     * @return bool
     */
    public function showCreate()
    {

        return $this->showCreate == 'all' || ($this->showCreate == 'admin' && \Auth::user()->get()->is_admin == 1);
    }

    /**
     * This method is used to show/hide the delete button (delete possible)
     * Based on the user and the settings it will return true or false
     *
     * @return bool
     */
    public function showDelete()
    {
        return $this->showDelete == 'all' || ($this->showDelete == 'admin' && \Auth::user()->get()->is_admin == 1);
    }

    /**
     * This method is used to show/hide the save button (update possible)
     * Based on the user and the settings it will return true or false
     *
     * @return bool
     */
    public function showSave()
    {
        return $this->showSave == 'all' || ($this->showSave == 'admin' && \Auth::user()->get()->is_admin == 1);
    }

    /**
     * Create a list with KmsAttribute Objects, based on $this->modelAttributes
     * The data is from the modelSection file
     *
     * @return array
     */
    protected function parseModelAttributesData($test = false)
    {
        //Create  empty attributes
        $this->attributes = [];

        //Reset the tabs
        $this->tabs->clearTabs();
        //Loop trough the modelAttributesData (from the model Section)

        foreach ($this->modelAttributesData as $attributeKey => $attribute) {
            //Check the model state

            if (isset($attribute['modelState'])) {
                //if the modelState is create and there is a model_id, skip
                if ($attribute['modelState'] == 'create' && ($this->getModelId())) continue;
                //If the modelstate is update and there is no model_id, skip
                if ($attribute['modelState'] == 'update' && (!$this->getModelId())) continue;
            }
            //Set the specific type of foreach
            $forEach = isset($attribute['forEach']) ? $attribute['forEach'] : null;

            // create attributes
            switch ($forEach) {
                case "CurrentSiteLanguages":
                    $this->createAttributeForCurrentSiteLanguages($attributeKey, $attribute);
                    break;
                case "AllLanguages":
                    $this->createAttributeForAllLanguages($attributeKey, $attribute);
                    break;
                case "AllSites":
                    $this->createAttributeForAllSites($attributeKey, $attribute);
                    break;
                case "AllSitesAsSub":
                    $this->createAttributeForAllSites($attributeKey, $attribute, true);
                    break;
                case "AllSitesAndLanguages":
                    $this->createAttributeForAllSitesAndLanguages($attributeKey, $attribute);
                    break;
                case'AllForeachModels':
                    $this->createAttributeForAllForeachModel($attributeKey, $attribute);
                    break;
                case'AllForeachModelsForAllSites':
                    $this->createAttributeForAllForeachModel($attributeKey, $attribute, 'AllSites');
                    break;
                case 'AllForeachModelsForAllSitesAndLanguages':
                    $this->createAttributeForAllForeachModel($attributeKey, $attribute, 'AllSitesAndLanguages');
                    break;
                default:
                    $this->createAttribute($attributeKey, $attribute);
                    break;
            }
        }
        return $this->attributes;
    }

    /**
     * This method will create the field for the normal attributes
     *
     * @param $key
     * @param $attributeData
     */
    protected function createAttribute($key, $attributeData)
    {


        //Set the value, check if the model is set and has an $key parameter, set this or set null
        $value = isset($this->model) && isset($this->model->$key) ? $this->model->$key : null;

        //Check if there is an releated attribute
        if ($relatedAttribute = $this->getRelatedAttribute($key, $attributeData)) $value = $relatedAttribute;

        //Set the options check if there is an attributeDatap['options'], parse this, or set an empty array
        $options = isset($attributeData['options']) ? $this->parseOptions($attributeData['options']) : [];
        //Check if an specific tab is set, if not set to the default tab
        $tab = isset($attributeData['tab']) ? $attributeData['tab'] : \Config::get('kms.main.defaultTabName');


        $key = $this->generateKey($key);

        //create a new AttributeDAta based on the given values and set these in item and add this to the attributes array
        $item = $this->attributes[] = new $attributeData['type']($key, $value, $options, [], null, null, $this);
        //Set the item to the tab
        $this->tabs->addItem($item, $tab);
    }

    /**
     * This method will create the fields for the given languages
     *
     * @param $key
     * @param $attributeData
     * @param $languages
     * @return null
     */
    protected function createAttributeForLanguages($key, $attributeData, $languages)
    {

        //Check if the key populate exist and its value is false; this is an field that is just info, return NULL
        if (isset($attributeData['populate']) && $attributeData['populate'] === false) return NULL;

        //Loop trough each language of the current site
        foreach ($languages as $language) {

            //Set the default value to an empty string (new model, or modeltranslation)
            $value = '';

            //Set translation to null
            $translation = null;

            //Check if there is an translation with the current language_id coupled to the model
            if ($this->model != null && method_exists($this->model, 'translations') && $translation = $this->model->translations()->where('language_id', '=', $language->id)->first()) ;
            elseif ($this->model != null && $this->model->translations != null && $translation = $this->model->translations->where('locale', $language->iso_2)->first()) ;
            elseif ($this->model != null && $this->model->translations != null && $translation = $this->model->translations->where('language_id', $language->id)->first()) ;

            if ($translation) {
                //Switch the function with the attribute key
                $value = isset($translation->$key) ? $translation->$key : null;

                if ($relatedAttribute = $this->getRelatedAttribute($key, $attributeData, $this->kms->getCurrentSiteId(), $language->id)) $value = $relatedAttribute;

                if (isset($attributeData['model']) && $value = $this->getSubModelValue($key, $attributeData, $this->kms->getCurrentSiteId(), $language->id)) ;
            }
            //If the options are set, parse these options with the language_id, if not options is an empty array()
            $options = isset($attributeData['options']) ? $this->parseOptions($attributeData['options'], $language->id) : [];


            $tab = isset($attributeData['tab']) ? $attributeData['tab'] : $language->iso_2;

            $currentKey = $this->generateKey([$key, $language->id]);

            $sectionItem = new $attributeData['type']($currentKey, $value, $options, [], null, $language->id, $this);
            // Todo: search why this is needed
            $this->attributes[] = $sectionItem;

            $this->tabs->addItem($sectionItem, $tab);
        }
    }

    /**
     * This method will create the fields for the currentSiteLanguages
     *
     * @param $key
     * @param $attributeData
     * @return null
     */
    protected function createAttributeForCurrentSiteLanguages($key, $attributeData)
    {
        //Get the languages
        $languages = $this->kms->getCurrentSiteLanguages();

        $this->createAttributeForLanguages($key, $attributeData, $languages);
    }

    /**
     * This method will create the fields for all the Languages
     *
     * @param $key
     * @param $attributeData
     * @return null
     */
    protected function createAttributeForAllLanguages($key, $attributeData)
    {
        //Get the languages
        $languages = $this->kms->getAvailableLanguages();
        $this->createAttributeForLanguages($key, $attributeData, $languages);
    }

    /**
     * This method creates the fields for all the languages in all the sites
     *
     * @param $key
     * @param $attributeData
     */
    protected function createAttributeForAllSitesAndLanguages($key, $attributeData)
    {
        //Loop trough the sites
        foreach ($this->kms->getSites() as $site) {


            //Check if There is an sub models set, and load this.
            if (!isset($attributeData['model']) || !$subModel = $this->getSubModel($this->model, $attributeData['model'], $attributeData, 'site_id', $site->id)) {
                //Set the default model to submodel
                $subModel = $this->model;
            }

            //Loop trough the site languages
            foreach ($site->languages as $language) {

                //Load the ModelTranslation
                if (!$modelTranslation = $this->getModelTranslation($subModel, $language->id)) {
                    //set the submodel to the ModelTranslation
                    $modelTranslation = $subModel;
                }

                //Set the value
                $value = isset($modelTranslation->$key) ? $modelTranslation->$key : null;

                if ($relatedAttribute = $this->getRelatedAttribute($key, $attributeData, $site->id, $language->id)) $value = $relatedAttribute;

                //Parse the options
                $options = isset($attributeData['options']) ? $this->parseOptions($attributeData['options'], $language->id, $site->id) : [];
                //Create the site tab
                $tab = $site->short_name;
                //Create the sub tab based on the language
                $subTab = $language->iso_2;
                //Set the key to $key_language_id_site_id
                $currentKey = $key . '_' . $language->id . '_' . $site->id;
                //Create a new attributes
                $item = $this->attributes[] = new $attributeData['type']($currentKey, $value, $options, [], $site->id, $language->id, $this);
                //Add the item to the tab
                $this->tabs->addItem($item, $tab, $subTab);
            }
        }
    }

    /**
     * This method creates the fields for all the sites
     *
     * @param $key
     * @param $attributeData
     */
    protected function createAttributeForAllSites($key, $attributeData, $subTab = false)
    {

        if ($key == 'site_label') return;


        //Loop trough the site
        foreach ($this->kms->getSites() as $site) {

            $value = isset($this->model) && isset($this->model->$key) ? $this->model->$key : null;

            //GEt the value by the related attribute
            if ($relatedAttribute = $this->getRelatedAttribute($key, $attributeData, $site->id)) $value = $relatedAttribute;
            //Check if there is an model set, load the model sorted by the site_id
            elseif (isset($attributeData['model']) && $subModel = $this->getSubModel($this->model, $attributeData['model'], $attributeData, 'site_id', $site->id)) {
                $value = (isset($subModel->$key) ? $subModel->$key : $value);
            }


            //parse the options
            $tab = $site->short_name;
            $options = isset($attributeData['options']) ? $this->parseOptions($attributeData['options'], null, $site->id) : [];
            //Create the site tab
            //Create the ket from $key and site id
            $currentKey = $key . '_' . $site->id;

            //Check if there is an attribute foreach, set this to $foreach
            if (isset($attributeData['forEach'])) $foreach = $attributeData['forEach'];
            //Create a new attributes
            $item = $this->attributes[] =
                new $attributeData['type']($currentKey, $value, $options, [], $site->id, null, $this, $foreach);
            //Add the item to the tab

            if ($subTab) {
                $this->tabs->addItem($item, null, $tab);
            } else {
                $this->tabs->addItem($item, $tab);

            }
        }
    }

    /**
     * This method creates the fields for all the instances of the given model.
     *
     * @param $key
     * @param $attributeData
     */
    public function createAttributeForAllForeachModel($key, $attributeData, $repeat = null)
    {
        //Check if the foreachmodel is set, if not abort 500, with the corresponding error.
        if (!isset($attributeData['forEachModel']))
            return \App::abort(500, 'ForeachModel for ' . $key . ' not set!');

        //Set the foreach model to an array
        $foreachModel = $attributeData['forEachModel'];

        //Check if the model has the releatedForeachModel, if not abort 500, with the corresponding error.
        if (!$foreachModels = $this->model->$foreachModel)
            return \App::abort(500, $foreachModel . ' not found on ' . get_class($this->model) . '!');

        //Check if the relatedModel count is 0
        if ($foreachModels->count() == 0) {
            //Get the foreachModel als relation
            $modelRelation = $this->model->$foreachModel();
            //Set the empty related model (the foreachModel) to the foreachModels
            $foreachModels[] = $modelRelation->getRelated();
        }


        //We got foreachModels, let start to work
        foreach ($foreachModels as $loopKey => $model) {

            //Count  = $loopkey +1
            $count = $loopKey++;

            //Set the current key with Key and the Count
            $currentKey = $key . '_' . $count;

            $foreach = null;


            $tabName = isset($attributeData['tab']) ? $attributeData['tab'] : \lang::get('kms/global.foreach_name.' . $foreachModel);

            if (isset($attributeData['forEachTab']) && $attributeData['forEachTab'] === false) {
                $tabName = $tabName;
            } elseif (isset($attributeData['forEachTabKey']) && $model->$attributeData['forEachTabKey'] != null) {
                $tabName .= ' ' . $model->$attributeData['forEachTabKey'];
            } else {
                $tabName .= ' ' . $count;
            }


            switch ($repeat) {
                case 'AllSites':
                    $this->forEachModelAllSites($key, $attributeData, $model, $count, $tabName);
                    break;
                case 'AllSitesAndLanguages':
                    $this->forEachModelAllSitesAndLanguages($key, $attributeData, $model, $count, $tabName);
                    break;
                default:
                    $options = isset($attributeData['options']) ? $this->parseOptions($attributeData['options'], null, null, $loopKey, $model->id) : [];

                    //Get the value for the given key
                    $value = $this->getItemValue($key, $attributeData, null, null, $model);
                    $item = $this->attributes[] =
                        new $attributeData['type']($currentKey, $model, $options, [], $model->id, null, $this, $loopKey);
                    $this->tabs->addItem($item, $tabName);
            }

        }
    }

    public function forEachModelAllSites($key, $attributeData, $model, $count, $tabName)
    {

        foreach ($this->kms->getSites() as $site) {
            $currentKey = $key . '_' . $count . '_' . $site->id;
            $value = $this->getRelatedAttribute($key, $attributeData, $site->id, null, $model);
            $options = isset($attributeData['options']) ? $this->parseOptions($attributeData['options'], null, $site->id, $count, $model->id) : [];


            $item = $this->attributes[] =
                new $attributeData['type']($currentKey, $value, $options, [], $site->id, null, $this, null);
            $this->tabs->addItem($item, $tabName, $site->short_name);
        }
    }

    public function forEachModelAllSitesAndLanguages($key, $attributeData, $model, $count, $tabName)
    {

        foreach ($this->kms->getSites() as $site) {
            foreach ($this->kms->getSiteLanguages($site->id) as $language) {
                $currentKey = $key . '_' . $count . '_' . $site->id . '_' . $language->id;
                $value = $this->getRelatedAttribute($key, $attributeData, $site->id, $language->id, $model);
                $options = isset($attributeData['options']) ? $this->parseOptions($attributeData['options'], $language->id, $site->id, $count, $model->id) : [];


                $item = $this->attributes[] =
                    new $attributeData['type']($currentKey, $value, $options, [], $site->id, $language->id, $this, null);
                $this->tabs->addItem($item, $tabName, $site->short_name, $language->iso_2);
            }
        }
    }


    public function getItemValue($key, $attributeData, $siteId = null, $languageId = null, $model = null)
    {

        //Set the value in the most basic way
        if (isset($model->$key)) return $model->$key;
        //Check if there is an relatedAttribute
        if ($value = $this->getRelatedAttribute($key, $attributeData, $siteId, $languageId, $model)) return $value;

        //Return the model when nothing is found
        return $model;
    }


    public function getRelatedAttribute($key, $attributeData, $siteId = null, $languageId = null, $model = null)
    {


        //Check if it has the parameter relatedAttribute and is true
        if (!isset($attributeData['relatedAttribute']) || !$attributeData['relatedAttribute']) return null;

        //Set the $this->model to the model
        if ($model == null) $model = $this->model;

        //Check if there is an submodel and it exist
        if (isset($attributeData['model'])) {
            $models = explode('->', $attributeData['model']);
            foreach ($models as $countKey => $deeperLevel) {

                $keyId = (isset($attributeData['relatedAttributeOptions'][$countKey]['keyId']) ? $this->replaceModelStrings($attributeData['relatedAttributeOptions'][$countKey]['keyId'], $siteId, $languageId, $model) : null);
                $keyBy = (isset($attributeData['relatedAttributeOptions'][$countKey]['keyBy']) ? $attributeData['relatedAttributeOptions'][$countKey]['keyBy'] : null);
                //Check if it is an method
                if (preg_match('/([a-z0-9_]+)\((.*)\)/i', $deeperLevel, $matches)) {
                    //If the method doesn't exist exit to a 500 page
                    if (!method_exists($model, $matches[1])) return \App::abort(500, 'Method ' . $matches[1] . ' doesn\'t exist on section-key: ' . $key);

                    $parameters = (!empty($matches[2]) ? explode(',', $matches[2]) : []);

                    $model = call_user_func_array([$model, $matches[1]], $parameters);

                } else {
                    $model = $this->getSubModel($model, $deeperLevel, $attributeData, $keyBy, $keyId);
                }

            }
            if (!$model) return false;

            //if KeyBy is is not set, return the current model (or collection)
            if (!isset($keyBy)) return $model;
        }

        //Check if the model exists, if not return false
        if (!$model) return false;

        //Get the value of the model
        return $model->getValue($key, $siteId, $languageId);

    }

    public function getSubModelValue($key, $attributeData, $siteId = null, $languageId = null, $model = null)
    {

        $model = $this->getSubModelExtended($key, $attributeData, $siteId, $languageId, $model);

        if (is_string($model)) return $model;

        if ($model->$key) return $model->$key;

        return $model;
    }

    public function getSubModelExtended($key, $attributeData, $siteId = null, $languageId = null, $model = null)
    {
        //Set the $this->model to the model
        if ($model == null) $model = $this->model;

        //Check if there is an submodel and it exist
        if (!isset($attributeData['model'])) return false;

        //Split the model by ->
        $models = explode('->', $attributeData['model']);
        //loop trough the models and keep the dept of the level ($countKey)
        foreach ($models as $countKey => $deeperLevel) {

            //Set the KeyId if exist
            $keyId = (isset($attributeData['relatedAttributeOptions'][$countKey]['keyId']) ? $this->replaceModelStrings($attributeData['relatedAttributeOptions'][$countKey]['keyId'], $siteId, $languageId, $model) : null);
            //Set the KeyBy if exist
            $keyBy = (isset($attributeData['relatedAttributeOptions'][$countKey]['keyBy']) ? $attributeData['relatedAttributeOptions'][$countKey]['keyBy'] : null);

            //Check if the "model" is an method
            if (preg_match('/([a-z0-9_]+)\((.*)\)/i', $deeperLevel, $matches)) {

                //If the method doesn't exist exit to a 500 page
                if (!method_exists($model, $matches[1])) return \App::abort(500, 'Method ' . $matches[1] . ' doesn\'t exist on section-key: ' . $key);

                //  Explode the found $parameters, if they exist. or an empty []
                $parameters = (!empty($matches[2]) ? explode(',', $matches[2]) : []);
                //Call the method with call_user_func_array, so we can add the parameters as an array

                $model = call_user_func_array([$model, $matches[1]], $parameters);
            } else {
                //No method, check if it is an subModel (or value)
                $model = $this->getSubModel($model, $deeperLevel, $attributeData, $keyBy, $keyId);
            }

        }

        return $model;
    }


    /**
     * This method loads the subModel from the $this->model colleciton.
     * It uses the modelName and an sort field and the specific key.
     *
     * @param $attributeData
     * @param $keyBy | Db field that is used to map the array
     * @param $keyId | the id of the key we want
     * @return mixed
     */
    public function getSubModel($model, $subModelName, $attributeData, $keyBy = 'id', $keyId = null)
    {
        //Todo: let this run over getSubModelExtended

        if (!$keyId) $keyId = $this->model->id;


        if (isset($attributeData['relatedAttributeOptions'])) {
            $keyBy = (isset($attributeData['relatedAttributeOptions']['keyBy']) ? $attributeData['relatedAttributeOptions']['keyBy'] : $keyBy);
            $keyId = (isset($attributeData['relatedAttributeOptions']['keyId']) ? $this->replaceModelStrings($attributeData['relatedAttributeOptions']['keyId']) : $keyId);
        }

        //Check if the model exists, if not return false
        if (!$model) return false;
        //Check if the model has the given model, if not return false

        if (!$subModelCollection = $model->$subModelName) return false;


        //If $keyBy is not set. return the entire collection
        if (!isset($keyBy)) return $model->$subModelName;

        //Sort the collection by the given keyBy parameter
        $subModelCollection = $model->$subModelName->keyBy($keyBy);
        //Return the wanted collection model based on the keyId, or false
        return $subModelCollection->get($keyId);
    }

    /**
     * This method loads the translation from a given model colletion
     *
     * @param        $model | The model were we want to get the translation from
     * @param        $language_id | the language id of the translation we want
     * @param string $translationModel | the translation model default {translations}
     * @param string $keyBy | Db field that is used to map the array defaukt {language_id}
     * @return bool
     */
    public function getModelTranslation($model, $language_id, $translationModel = 'translations', $keyBy = 'language_id')
    {
        //Check if the model has the translationModel, if not return false
        if (!$modelTranslations = $model->$translationModel) return false;
        //Key the modelTranslations by the given key_by parameter
        $modelTranslations = $modelTranslations->keyBy($keyBy);
        //Get the wanted language model, or false
        return $modelTranslations->get($language_id);
    }


    /**
     * Set the section attributes by $this->currentEntities
     * @param array /object $data
     */
    protected function populateAttributes()
    {

        mooi('dit is niet gebruikt denk ik');
//        foreach ($this->attributes as $attribute) {
//            if ($attribute->getOption('populate') === false) continue;
//            $key = $attribute->getKey();
//            $value = $attribute->getValue();
//            $attribute->setValue($value);
//        }
//        $this->processAttributes();
    }

    /**
     * Fills the model with the processed values form the attributes array.
     * Processing happens in each attributes by $attribute->getValue()
     * Eg. Hash::make in the Password attribute
     */
    protected function processAttributes()
    {
        foreach ($this->attributes as $key => $attribute) {
            $attribute->process();
            $this->proccessedAttributes[$attribute->getKey()] = $attribute;
        }
    }


    /**
     * Parse the options
     *
     * @param      $options
     * @param null $languageId
     * @param null $siteId
     * @return mixed
     */
    private function parseOptions($options, $languageId = null, $siteId = null, $foreachCounter = null, $foreachModelId = null)
    {

        if ($siteId) $site = Site::find($siteId);
        if ($languageId) $language = Language::find($languageId);
        foreach ($options as $key => $option) {

            // Call recursively if the option is an array.
            if (is_array($option)) $options[$key] = $this->parseOptions($option, $languageId, $siteId, $foreachCounter, $foreachModelId);

            // Skip if option if isn't a string.
            if (!is_string($option)) continue;

            //Parse static strings to the value

            if (isset($this->model->id)) {

                //Replace the [[modelId]] to the model id
                $options[$key] = $option = $this->model->id ?
                    str_replace('[[modelId]]', $this->model->id, $option) : str_replace('[[modelId]]', '', $option);
            }

            if (isset($site)) {
                //Replace [[siteName]] to the site name
                $options[$key] = $option = str_replace('[[siteName]]', $site->name, $option);

                //Replace [[siteId]] to the site id
                $options[$key] = $option = str_replace('[[siteId]]', $site->id, $option);
            }
            if (isset($language)) {
                //replace the [[languageId]] to the current language id
                $options[$key] = $option = str_replace('[[languageId]]', $language->id, $option);
                //replace the [[LanguageIso2]] to the current language id
                $options[$key] = $option = str_replace('[[LanguageName]]', \Lang::get('languages.'.$language->iso_2), $option);

                //replace the [[LanguageIso2]] to the current language iso
                $options[$key] = $option =  str_replace('[[languageIso]]', $language->iso_2, $option);


            }
            if (isset($foreachModelId)) {
                //replace the [[foreachModelId]] to the current foreachModel id
                $options[$key] = $option = str_replace('[[foreachModelId]]', $foreachModelId, $option);
            }
            if (isset($foreachCounter)) {
                //replace the [[foreachModelId]] to the current foreachModel id
                $options[$key] = $option = str_replace('[[foreachCounter]]', $foreachCounter, $option);
            }


            //Replace [[status]] with the status if it exist
            if (isset($this->model->id) && $this->model->status) {
                $options[$key] = $option = str_replace('[[status]]', $this->model->status, $option);
            }

            $options[$key] = $option = str_replace('[[key]]', $key, $option);

            if (isset($this->model->id)) {

                // replace with the result of a method name in the model
                foreach (get_class_methods($this->model) as $methodName) {
                    // check if the method name is in the template to prevent automatic method calls
                    $pos = strpos($option, '[[' . $methodName . ']]');
                    if ($pos !== false) {
                        $options[$key] = $option = str_replace('[[' . $methodName . ']]', $this->model->$methodName($siteId, $languageId), $option);
                    }
                }


                // replace with a property in the model
                foreach (get_object_vars($this->model) as $property => $value) {
                    if (is_string($value)) {
                        $options[$key] = $option = str_replace('[[' . $property . ']]', $value, $option);
                    }
                }
            }

            //If the option starts with lang_get:, call the \Lang::get method with the option as parameter
            if (preg_match('/^lang_get:([a-z0-9\/._\-]+)#?(.*)/i', $option, $match)) {

                $options[$key] = $option = \Lang::get($match[1], ['value' => $match[2]]);
            }
            if (preg_match('/^config_get:([a-z0-9\/._\-]+)#?(.*)/i', $option, $match)) {

                $options[$key] = $option = \Config::get($match[1], ['value' => $match[2]]);
            }




        }

        return $options;
    }


    /**
     * This method renders the input based on the options.
     * eg. hash the password.
     *
     * @return array
     */
    public function renderInput()
    {
        //Create empty renderInput
        $renderedInput = [];
        //Loop trough the attributes
        foreach ($this->attributes as $at) {
            //Set the valuie
            $at->setValue(\Input::get($at->getKey()));
            //prices the value
            $at->process();
            //Set the value in the renderedInput

            if ($this->eav && $at->data_type != null) {
                $renderedInput[$at->getKey()]['value'] = $at->getValue(true);
                $renderedInput[$at->getKey()]['data_type'] = $at->data_type;
            } else {
                $renderedInput[$at->getKey()] = $at->getValue(true, $at->getKey());
            }
        }
        return $renderedInput;

    }


    /*
     * This method returns the validation from the loaded section
     *
     * @return array
     */
    public function getValidation($id = null, $update = false, $model = null)
    {


        //set empty validation array
        $validation = ['messages' => [], 'rules' => []];

        //Loop trough the attributes (these are modelAttributesData parsed)
        foreach ($this->attributes as $attribute) {
            //If options doest't exist, continue
            if (!isset($attribute->options)) continue;
            //If the validation doesn't exist, continue
            if (!isset($attribute->options['validation'])) continue;
            //If the rules exist add these for the current key
            if (isset($attribute->options['validation']['rules'])) $validation['rules'][$attribute->key] = $attribute->options['validation']['rules'];
            //If the messages exist add these for the current key
            if (!isset($attribute->options['validation']['messages'])) continue;

            foreach ($attribute->options['validation']['messages'] as $key => $message) {
                $validation['messages'][$attribute->key . '.' . $key] = $message;
            }

        }

        return $validation;
    }


    /**
     * This method will check if the repository is sortable
     *
     * @return bool
     */
    public function getSortable()
    {
        if (method_exists($this->repository, 'getSortable')) return $this->repository->getSortable();

        return False;
    }

    /**
     * Returns the data_type from the given key
     * When it doesn't exist returns false
     *
     * @param $key
     * @return bool
     */
    public function getDataType($key)
    {
        if (!isset($this->modelAttributesData[$key]['data_type'])) return false;
        return $this->modelAttributesData[$key]['data_type'];
    }

    public function replaceModelStrings($string, $siteId = null, $languageId = null, $model = null)
    {


        $string = preg_replace('#\[\[modelId\]\]#', $this->model->id, $string);
        if ($model) $string = preg_replace('#\[\[selfId\]\]#', $model->id, $string);

        if ($languageId) $string = preg_replace('#\[\[languageId\]\]#', $languageId, $string);

        return $string;
    }


    public function extendValidator()
    {

        //Checks if the input can be json decoded
        \Validator::extend('isJson', function ($key, $value, $options = null) {
            //If it is a, return true
            if ($prices = json_decode($value)) return true;
            return false;
        });
        //Check if the price in the json is set and greater than 0
        \Validator::extend('priceNotNull', function ($key, $value, $options = null) {
            if (!$prices = json_decode($value)) return false;

            foreach ($prices as $price) {
                //If price_inc is not set
                if (!isset($price->price_inc)) return false;
                //If price is empty
                if (empty($price->price_inc)) return false;
                //If price is 0 or smaller
                if ($price->price_inc <= 0) return false;
            }
            return true;
        });
        //Check if the minimum amount in the json is set and greater than 0
        \Validator::extend('minimumNotNull', function ($key, $value, $options = null) {
            if (!$prices = json_decode($value)) return false;

            foreach ($prices as $price) {
                //If price_inc is not set
                if (!isset($price->min_amount)) return false;
                //If price is empty
                if (empty($price->min_amount)) return false;
                //If price is 0 or smaller
                if ($price->min_amount <= 0) return false;
            }
            return true;
        });
        //Check if the price in the Json is a number
        \Validator::extend('priceAsNumber', function ($key, $value, $options = null) {
            if (!$prices = json_decode($value)) return false;
            foreach ($prices as $price) {
                if (!is_numeric($price->price_inc)) return false;
            }
            return true;
        });
        //Check if the minimum amount in the Json is a number
        \Validator::extend('minimumAsNumber', function ($key, $value, $options = null) {
            if (!$prices = json_decode($value)) return false;
            foreach ($prices as $price) {
                if (!is_numeric($price->min_amount)) return false;
            }
            return true;
        });
        //Check if the minimum amount in the Json is not repeated
        \Validator::extend('minimumRepeat', function ($key, $value, $options = null) {
            if (!$prices = json_decode($value)) return false;
            $min_amounts = [];
            foreach ($prices as $price) {
                if (in_array($price->min_amount, $min_amounts)) return false;
                $min_amounts[] = $price->min_amount;
            }
            return true;
        });
        //Check if the given field
        \Validator::extend('uniqueAttribute', function ($key, $value, $options = null) {
            $eavService = new EavService();
            //$options[0] = model_type
            //$options[1] = attribute_type
            //$options[2] = exclude_id
            //$options[2] = exclude_field
            $values = $eavService->getAllValuesForModelAndType($options[0], $options[1], $options[2], $options[3]);
            //Check if the value  exist, if so return false
            if (in_array($value, $values)) return false;

            return true;

        });


        //Check if the value is not when an other field has a certain value
        \Validator::extend('isNotIf', function ($key, $value, $options) {
            //options[0] value that the key can't be
            //options[1] the key for the if check
            //options[2] the value for the if check
            if (!\Input::has($options[1])) return true;

            if (\Input::get($options[1]) != $options[2]) return true;
            if (\Input::get($key) == $options[0]) return false;
            return true;
        });

        /**
         * Use extendImplicit when the validation also should work when the value is empty
         * Check if the model is new
         * If so, check if it is empty
         */
        \Validator::extendImplicit('required_if_new', function ($key, $value, $options) {

            //Check of the modelId is not null. If true, return true
            if ($options[0] !== null) return true;

            //New Item

            //Check if the value is not empty. return true
            if (!empty($value)) return true;

            //New model, and empty value, return false
            return false;

        });

    }

    public function generateKey($key)
    {
        if (is_array($key)) $key = implode('_', $key);

        if ($this->keyAsArray) $key = $this->keyAsArray . '_' . $key . '[' . $this->keyArrayKey . ']';

        return $key;
    }


    ///Getters
    public function getKms()
    {
        return $this->kms;
    }

    public function getTabsClass()
    {
        return $this->tabs;
    }

    public function setModelAttributesData($modelAttributesData)
    {
        $this->modelAttributesData = $modelAttributesData;

    }


}