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/brameda/brameda.nl/app/Komma/Kms/Core/Sections/Section.php
<?php

namespace App\Komma\Kms\Core\Sections;

use App\Helpers\KommaHelpers;
use App\Komma\Kms\Core\Attributes\Models\Traits\HasThumbnailInterface;
use App\Komma\Kms\Core\Attributes\Attribute;
use App\Komma\Kms\Core\Attributes\Traits\LabelTrait;
use App\Komma\Kms\Core\Entities\DisplayNameTrait;
use App\Komma\Globalization\Languages\Models\Language;
use App\Komma\Pages\Models\Page;
use App\Komma\Routes\RouteService;
use App\Komma\Sites\Models\Site;
use App\Komma\Sites\SiteServiceInterface;
use Illuminate\Contracts\View\View;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\MessageBag;

/**
 * Class Section. Will replace KmsSection
 * @package App\Komma\Kms\Core\Sections
 */
abstract class Section
{
    /** @var SiteServiceInterface $siteService */
    protected $siteService;

    /**
     * @var SectionServiceInterface $sectionService
     */
    protected $sectionService;

    /** @var RouteService $routeService */
    protected $routeService;

    protected $eventListeners = [];

    /**
     * @var SectionTabsCollectionInterface
     */
    protected $sectionTabDirector;

    /** @var Collection The AbstractSectionTabItem instances that belong to a sectionTab. Todo: this should be the sectionTab instead. If we edit this like i described then we must modify related code too */
    protected $sectionTabItems;

    /** @var Model|HasThumbnailInterface $model */
    private $model = null;
    protected $models = [];

    protected $errors = [];

    protected $successes = [];

    protected $sectionNewModel = "";
    protected $sectionTitle = "";
    protected $sectionsubtitle = "";
    protected $submitButtonLabel = "";

    protected $slug = "";

//    public $submitRoute = null;

    public $type = 'model';

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

    /** @var bool whether or not the RouteService should manage routes for this section using the models translationmodels name attribute */
    protected $hasRoutes = false;

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

    /** @var Model $forModelName */
    private $forModelName;

    function __construct(
        SectionServiceInterface $sectionService,
        RouteService $routeService,
        SiteServiceInterface $siteService,
        AbstractSectionTabsDirector $sectionTabDirector
    ) {
        $this->siteService = $siteService;
        $this->sectionService = $sectionService;
        $this->routeService = $routeService;
        $this->sectionTabDirector = $sectionTabDirector;

        $this->setSectionText();
    }

    public function getSectionService()
    {
        return $this->sectionService;
    }

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

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

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

    /**
     * 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->sectionService->getModelsForSideBar();
    }

    /**
     * This method is called when an model is called
     * eg. for the edit form via the controller
     *
     * @param null $idOrModel
     * @return null
     */
    public function loadModel($idOrModel = null)
    {
//        \Log::debug("KmsSection:191 loadModel");

        if (is_numeric($idOrModel) || is_null($idOrModel)) {
            $this->model = $this->sectionService->getModel($idOrModel);
        }elseif (gettype($idOrModel) == "object" && is_a($idOrModel, HasThumbnailInterface::class)) {
            /** @var HasThumbnailInterface $idOrModel */
            $this->setOrCreateModel($idOrModel);
            $this->model->generateThumbnail();
        }else {
            throw new \InvalidArgumentException("KmsSection loadModel expected a variable of type int or numeric string or eloquent model that implements the HasThumbnailInterface but got a variable of type: " . gettype($idOrModel));
        }

        return $this->model;
    }

    public function setOrCreateModel($model)
    {
        if ($model == null) {
            $this->model = $this->sectionService->newModel();
        }else {
            $this->model = $this->sectionService->makeAndInjectEmptyTranslationsIntoTranslatableIfNeeded($model);;
        }

        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;
    }

    /**
     * @return Model
     */
    public function getForModelName(): string
    {
        return $this->forModelName;
    }

//    /**
//     * Gets the model name
//     */
//    public function getModelName($stripModelSuffix = true)
//    {
//        if ( ! $this->model) {
//            return '';
//        }
//
//        $reflect = new \ReflectionClass($this->model);
//
//        $className = $reflect->getShortName();
//
//        if ($stripModelSuffix) {
//            $className = str_ireplace('model', '', $className);
//        }
//
//        return $className;
//    }

    /**
     * @return Model
     */
    public function getModel()
    {
//        if($this->model) \Log::debug("KmsSection:250 getModel (exists)"); else \Log::debug("KmsSection:250 (does not exist)");
        return $this->model;
    }


    /**
     * This method returns the display name of the model
     * It will check if there is an model name
     * or returns new {type}
     *
     * @return string
     */
    public function getModelDisplayName()
    {
        if ( ! method_exists($this->model, 'getDisplayName')) {
            throw new \RuntimeException('Please add the ' . DisplayNameTrait::class . ' trait to ' . $this->forModelName);
        }

        return ($this->model) ? $this->model->getDisplayName() : null;
    }

    /**
     * Generates the attributes for this section. They all must extend the App\Komma\Kms\Core\Attributes\Attribute class
     *
     * @return Collection A collection of SectionTabItems
     */
    abstract protected function generateAttributes(): Collection;


    /**
     * Generates the attributes for the section using the sections generatesAttributes method
     * and adds them to the appropriate tabs
     *
     * @return void
     */
    public function generateAttributesAndAddThemToTabs()
    {
        $this->sectionTabItems = $this->generateAttributes();
        $this->addAttributesToTabs();
    }

    /**K
     * Returns a rendered view
     *
     * @return View
     */
    public function render()
    {
        if ($this->showEntity) {
            $this->generateAttributesAndAddThemToTabs();
        }

        if ( ! $this->getModel()) {
            return $this->makeView();
        } //Return a view since we can't fill it with data because the model is not set.

        $this->getSectionService()->fillAttributesWithData($this->sectionTabItems, $this->getModel());

        return $this->makeView();
    }

    /**
     * Makes the view and returns it
     *
     * @return View
     */
    protected function makeView(): View
    {
        $tabslug = null !== \Input::get('tabslug') ? \Input::get('tabslug') : \Session::get('tabslug', '');
        $sessionData = [
            'tabslug' => $tabslug
        ];

        $saveRoute = $this->routeService->getSaveRoute($this->getSlug(), $this->getModelId());

        $successes = (\Session::has('successes')) ? \Session::get('successes') : new MessageBag();

        return view('kms/section.index', [
            'siteSlug'                      => !$this->siteService->getCurrentSite()->exists ? null : $this->siteService->getCurrentSite()->slug,
            'section'                      => $this,
            'saveRoute'                    => $saveRoute,
            'successes'                    => $successes,
            'maxUploadSize'                => KommaHelpers::fileUploadMaxSize(),
            'maxPostSize'                  => KommaHelpers::maxPostSize(),
            'preventNavigationTranslation' => json_encode(__('kms/prevent-navigation'))
        ])->with($sessionData);
    }

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

    /**
     * This method creates or updates a model.
     * Based on the input data of the form.
     *
     * @param Model $model
     * @return $id
     * @throws \Exception
     */
    public function save(Model $model = null)
    {
        $this->fillAttributesFromInput();

        $model = $this->sectionService->saveModel($model, $this->sectionTabItems);

        if(is_a($model, Page::class)) $this->routeService->createOrUpdateRoutesForModelsTranslationsIfChanged($model);

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

        //Return the id
        return $model;
    }

    /**
     * This method calls the destroyModel method
     * from the give repository class.
     *
     * @param Model $model
     * @throws \Exception
     */
    public function destroy(Model $model)
    {
        $this->sectionService->destroyModel($model);
    }

    /**
     * Iterates over all sectionTabItem instances and builds a Validator
     * from the rules and messages in them.
     *
     * @param array $input The input to validate. The function wil retrieve the input itself if you don't specify this.
     * If you specify it must be an associative array containing input names as keys and values as values from
     * those inputs.
     *
     * @return \Validator
     */
    public function validateInputAndReturnValidator(array $input = [])
    {
        if (empty($input)) {
            $input = \Input::all();
        }

        $rules = [];
        $messages = [];

        /** @var AbstractSectionTabItem $sectionTabItem */
        foreach ($this->sectionTabItems as $sectionTabItem) {
            $attribute = $sectionTabItem->getAttribute();
            $set = $attribute->getValidationSet();

            if ( ! $set->hasRulesAndMessages()) {
                continue;
            }

            //prepend the attribute key in front of each message rule followed by a dot to make sure the message is unique for each attribute.
            $set->prefixMessageRulesWith((string)$attribute->getKey());

            //And replace :attribute with the label text of the attribute
            if (in_array(LabelTrait::class, class_uses($attribute))) {
                $set->modifyMessages(":attribute", $attribute->getLabelText());
            }

            $rules = array_merge($rules, [(string)$attribute->getKey() => $set->getRules()]);
            $messages = array_merge($messages, $set->getMessages());
        }

        $validator = \Validator::make($input, $rules, $messages);

        return $validator;
    }

    /**
     * For which model this section works for.
     *
     * @param string $forModel Referencing a eloquent Model
     */
    public function setForModelName(string $forModel)
    {
        $this->forModelName = $forModel;
        $this->routeService->setForModelName($forModel);
    }


    /**
     * Creates copies of the $baseAttribute for each language given.
     * Also retrieves the translation that belongs to the model based on each language that is being processed.
     * The translation is stored inside if it exists the attribute to later on check at which tab in a section it belongs.
     *
     * @param Attribute $baseAttribute
     * @param $languages
     * @return array with the created attributes
     */
    private function createAttributesFromExistingAttributeForTheGivenLanguages(Attribute $baseAttribute, $languages)
    {
        $createdAttributes = [];

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

            $clone = clone $baseAttribute;

            if ($language) {
                $clone->setAssociatedLanguage($language);
            }

            $createdAttributes[] = $clone;
        }

        return $createdAttributes;
    }


    /**
     * This method create copies of the attributes you pass it for all current site languages and
     * injects translations via another method
     *
     * @param $baseAttributes
     * @return array
     */
    protected function createAttributesFromExistingAttributeForCurrentSiteLanguages(Array $baseAttributes)
    {
        //Get the languages
        $languages = $this->siteService->getSiteLanguages();

        $attributes = [];
        foreach ($baseAttributes as $baseAttribute) {
            $attributesCreatedFromBaseAttribute = $this->createAttributesFromExistingAttributeForTheGivenLanguages($baseAttribute,
                $languages);
            $attributes = array_merge($attributes, $attributesCreatedFromBaseAttribute);
        }

        return $attributes;
    }

    /**
     * This method create copies of the attributes you pass it for all used site languages and
     * injects translations via another method.
     *
     * @param $baseAttributes
     * @return array
     */
    protected function createAttributesFromExistingAttributeForAllUsedLanguagesBySites(Array $baseAttributes)
    {
        $languages = Site::has('languages')->with(['languages'])->get()->map(function (Site $site) {
            return $site->languages;
        })->collapse();

        $currentSiteDefaultLanguage = $this->siteService->getCurrentSite()->defaultLanguage;
        $languages = $languages->push($currentSiteDefaultLanguage)->unique('id');

        $attributes = [];
        foreach ($baseAttributes as $baseAttribute) {
            /** @var Attribute $baseAttribute */
            $attributesCreatedFromBaseAttribute = $this->createAttributesFromExistingAttributeForTheGivenLanguages($baseAttribute,
                $languages);
//            if($baseAttribute->getsValueFrom() == Attribute::ValueFromItself && $baseAttribute->getsValueFromReference() == 'value') dd($attributesCreatedFromBaseAttribute); //Debugging helper
            $attributes = array_merge($attributes, $attributesCreatedFromBaseAttribute);
        }

        return $attributes;
    }

    /**
     * Fills all attributes with values from the forms / session
     *
     * @return void
     */
    public function fillAttributesFromInput()
    {
        if(!$this->sectionTabItems) throw new \RuntimeException('No section tab items defined. Please generate them first');

        /** @var AbstractSectionTabItem $sectionTabItem */
        foreach ($this->sectionTabItems as $sectionTabItem) {
            //Insert the the appropriate value in the attribute
            $attribute = $sectionTabItem->getAttribute();
            $input = \Input::get((string)$attribute->getKey());

            if ($input !== null) {
                $attribute->setValue($input);
            }

            //Insert the associated language (if any) into the attribute
            if($attribute->getKey() == null) dd('Attribute without key detected: ', $attribute);
            if ($attribute->getKey()->getTranslationIso2() != '') {
                //get the language associated with the attribute]
                $language = Language::where('iso_2', $attribute->getKey()->getTranslationIso2())->first();

                $attribute->setAssociatedLanguage($language);
            }
        }
    }


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

        return false;
    }

    /**
     * Returns an array containing SectionTabInterfaces representing Tabs for sections
     *
     * @return SectionTabInterface[]|array
     */
    public function getTabs()
    {
        if ( ! $this->sectionTabDirector->getTabsCollection()) {
            return [];
        }

        return $this->sectionTabDirector->getTabsCollection()->getTabs();
    }

    /**
     * Adds attributes to their appropriate tabs.
     *
     * @return void
     */
    protected function addAttributesToTabs()
    {
        $tabsCollection = $this->getSectionTabDirector()->getTabsCollection();
        $tabs = $tabsCollection->getTabs();
        foreach ($tabs as $tab) {
            if ($tab->getGroup() == SectionTabGroups::General) {
                $this->sectionTabItems->each(function ($sectionTabItem, $key) use ($tab) {
                    /** @var AbstractSectionTabItem $sectionTabItem */
                    if ($sectionTabItem->getGroup() == SectionTabGroups::General) {
                        $tab->addItem($sectionTabItem->getAttribute());
                    }
                });
            }elseif ($tab->getGroup() == SectionTabGroups::Languages) {

                $this->sectionTabItems->each(function ($sectionTabItem, $key) use ($tab) {
                    /** @var AbstractSectionTabItem $sectionTabItem */

                    if ($sectionTabItem->getGroup() != SectionTabGroups::Languages) {
                        return;
                    } //Item does not belong to a language section tab. Most likely to the general tab. Skip it.
                    $attribute = $sectionTabItem->getAttribute();


                    if ( ! $attribute->hasAssociatedLanguage()) {
                        return; //attribute does not have a translation. Skip it
                    }

                    if (strtolower($attribute->getAssociatedLanguage()->iso_2) != $tab->getName()) {
                        return;
                    } //Attribute does belong to another language tab, not this one. Skip it.

                    $tab->addItem($attribute);
                });
            }
        }
    }

    /**
     * Returns the sectiontab director which manages the creation of tabs via a builder
     *
     * @return AbstractSectionTabsDirector
     */
    public function getSectionTabDirector(): AbstractSectionTabsDirector
    {
        return $this->sectionTabDirector;
    }

    /**
     * Set the section text
     */
    public function setSectionText()
    {
        $sectionTranslationFile = 'global';
        if($this->slug != '') $sectionTranslationFile = $this->slug;

        $newModelTranslationKey = ''.$sectionTranslationFile.'.section.new';
        $sectionTitleTranslationKey = $sectionTranslationFile.'.section.title';
        $sectionsubtitleTranslationKey = $sectionTranslationFile.'.section.subtitle';

        $newModelTranslationShop = __('shop/'.$newModelTranslationKey);
        if($newModelTranslationShop !== 'shop/'.$newModelTranslationKey) $this->setSectionNewModelTranslation($newModelTranslationShop);
        else $this->setSectionNewModelTranslation(__('kms/'.$newModelTranslationKey));

        $sectionTitleShop = __('shop/'.$sectionTitleTranslationKey);
        if($sectionTitleShop !== 'shop/'.$sectionTitleTranslationKey) $this->setSectionTitleTranslation($sectionTitleShop);
        else $this->setSectionTitleTranslation(__('kms/'.$sectionTitleTranslationKey));

        $sectionsubtitleShop = __('shop/'.$sectionsubtitleTranslationKey);
        if($sectionsubtitleShop !== 'shop/'.$sectionsubtitleTranslationKey) $this->setSectionsubtitleTranslation($sectionsubtitleShop);
        else $this->setSectionsubtitleTranslation(__('kms/'.$sectionsubtitleTranslationKey));

        if( \Lang::has('kms/'.$sectionTranslationFile.'.section.submitButton')){
            $this->setSubmitButtonLabel(__('kms/'.$sectionTranslationFile.'.section.submitButton'));
        }
        else{
            $this->setSubmitButtonLabel(__('kms/global.save'));
        }
    }

    /**
     * @param string $sectionNewModel
     */
    public function setSectionNewModelTranslation(string $sectionNewModel)
    {
        $this->sectionNewModel = $sectionNewModel;
    }

    /**
     * @param string $sectionTitle
     */
    public function setSectionTitleTranslation(string $sectionTitle)
    {
        $this->sectionTitle = $sectionTitle;
    }

    /**
     * @param string $sectionsubtitle
     */
    public function setSectionsubtitleTranslation(string $sectionsubtitle)
    {
        $this->sectionsubtitle = $sectionsubtitle;
    }

    /**
     * @param string $submitButtonLabel
     */
    public function setSubmitButtonLabel(string $submitButtonLabel)
    {
        $this->submitButtonLabel = $submitButtonLabel;
    }

    /**
     * @return string
     */
    public function getSectionNewModel()
    {
        return $this->sectionNewModel;
    }

    /**
     * @return string
     */
    public function getSectionTitle()
    {
        return $this->sectionTitle;
    }

    /**
     * @return string
     */
    public function getSectionsubtitle()
    {
        return $this->sectionsubtitle;
    }

    /**
     * @return string
     */
    public function getSubmitButtonLabel()
    {
        return $this->submitButtonLabel;
    }
}