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/SBogers10/blije-gasten.komma.pro/app/Komma/Kms/Core/SectionController.php
<?php
namespace App\Komma\Kms\Core;

use App\Helpers\KommaHelpers;
use App\Komma\Components\ComponentArea\ComponentAreaServiceInterface;
use App\Komma\Documents\Kms\DocumentableInterface;
use App\Komma\Documents\Kms\DocumentService;
use App\Komma\Documents\Kms\DocumentServiceInterface;
use App\Komma\Kms\Core\Attributes\Attribute;
use App\Komma\Kms\Core\Attributes\Models\Traits\HasThumbnailInterface;
use App\Komma\Kms\Core\Entities\DisplayNameInterface;
use App\Komma\Kms\Core\Sections\Section;
use App\Komma\Kms\Core\Tree\TreeServiceInterface;
use App\Komma\Routes\AbstractRouteService;
use App\Komma\Routes\RouteService;
use App\Komma\Sites\SiteServiceInterface;
use Illuminate\Contracts\View\View;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Routing\Controller;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Input;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\MessageBag;

class SectionController extends Controller
{
    use AuthorizesRequests;

    /** @var Section $section */
    protected $section;
    protected $slug = null;
    protected $showEntity = true;
    protected $sortable = false;

    /** @var ModelServiceInterface */
    protected $modelService;

    /** @var TranslationServiceInterface */
    protected $translationService;

    /** @var AttributeDataServiceInterface */
    protected $dataService;

    /** @var Model|HasThumbnailInterface|DisplayNameInterface */
    protected $forModelInstance;

    /** @var string $classModelName For which model the controller does its job */
    protected $classModelName;

    /** @var Model|null */
    protected $forTranslationModelName;

    /** @var SiteServiceInterface $siteService */
    protected $siteService;

    /** @var DocumentService */
    protected $documentService;

    /** @var ComponentAreaServiceInterface */
    protected $componentAreaService;

    /** @var TreeServiceInterface */
    protected $treeService;

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

    /** @var RelatedModelServiceInterface */
    private $relatedModelService;

    /** @var Model */
    protected $recentModel;

    public function __construct(Section $transferSection)
    {
        if(app()->runningInConsole()) return;
        $this->section = $transferSection;
        $this->validateClassModelNames();

        $this->dataService = app(AttributeDataServiceInterface::class);
        $this->modelService = app(ModelServiceInterface::class);
        $this->modelService->setModelClassName($this->classModelName);
        $this->forModelInstance = $this->modelService->getForModelFromRoute($this->slug);
        $this->treeService = app(TreeServiceInterface::class);
        $this->treeService->setClassModelName($this->classModelName);
        if($this->forTranslationModelName) {
            $this->translationService = app(TranslationServiceInterface::class);
            $this->translationService->setModelClassName($this->forTranslationModelName);
        }
        $this->documentService = app(DocumentServiceInterface::class);
        $this->componentAreaService = app(ComponentAreaServiceInterface::class);
        $this->routeService = app(AbstractRouteService::class);
        $this->siteService = app(SiteServiceInterface::class);
        $this->relatedModelService = app(RelatedModelServiceInterface::class);
        $this->relatedModelService->setModelClassName($this->classModelName);

        $this->section = $transferSection;
    }

    /**
     * This method is called on the overview page.
     * It will render the section and view.
     *
     * @return mixed
     * @throws \Illuminate\Auth\Access\AuthorizationException
     */
    public function index()
    {
        $this->authorize('index', $this->classModelName);

        //Create a root model if the modelClassName instance implements the treeInterface
        $this->modelService->createRootTreeModelIfNeeded();

        //Disable the right pane
        $this->showEntity = false;

        return $this->render(null);
    }

    /**
     * This method is called when a item is selected.
     * By default it will generate an edit form.
     *
     * @param Model $model
     * @return mixed
     * @throws \Illuminate\Auth\Access\AuthorizationException
     */
    public function show($model)
    {
        $this->authorize('show', $model);

        //Create a root model if the modelClassName instance implements the treeInterface
        $this->modelService->createRootTreeModelIfNeeded();

        //Call the edit method
//        $this->section->loadModels(); //we need to do this here because this won't work in section constructors since there the authenticated user is not available in laravel 5.3
        return $this->edit($model);
    }

    /**
     * This method is called when we want to edit an item.
     * It is called from the $this->show method.
     *
     * @param Model $model
     * @return mixed
     * @throws \Illuminate\Auth\Access\AuthorizationException
     */
    public function edit($model)
    {
        $this->authorize('edit', $model);
        //Create a root model if the modelClassName instance implements the treeInterface
        $this->modelService->createRootTreeModelIfNeeded();

        // Build section tabs
        $this->section->getTabs()->buildTabs();

        return $this->render($model);
    }



    /**
     * This method will generate a new item form
     *
     * @return mixed
     * @throws \Illuminate\Auth\Access\AuthorizationException
     */
    public function create()
    {
        $this->authorize('create', $this->classModelName);

        //Create a root model if the modelClassName instance implements the treeInterface
        $this->modelService->createRootTreeModelIfNeeded();

        // Build section tabs
        $this->section->getTabs()->buildTabs();

        //Render the form
        return $this->render();
    }

    /**
     * This method will validate and save the model
     * It is called on create form submit,
     * and it is called on the form edit.
     *
     * @return mixed
     * @throws \Illuminate\Auth\Access\AuthorizationException
     * @throws \Throwable
     */
    public function store()
    {
        $this->authorize('store', $this->classModelName);
        $this->modelService->createRootTreeModelIfNeeded();

        //Prepare the new model, and attributes
        $model = $this->modelService->newModel();
        if($this->forTranslationModelName) $model = $this->translationService->makeAndInjectEmptyTranslationsIntoTranslatableIfNeeded($model);
        $this->section->generateAttributesAndAddThemToTabs($model);
        $attributes = $this->section->getAttributes();

        //Validate the form data and fill the attributes from input
        $validator = $this->dataService->validateInputAndReturnValidator($attributes);
        if ($validator->fails()) return redirect()->back()->withInput()->withErrors($validator);
        $attributes = $this->dataService->fillAttributesFromInput($attributes);

        $byValueFrom = $attributes->mapToGroups(function($attribute, $index) {
            /** @var Attribute $attribute */
           return [$attribute->getsValueFrom() => $attribute];
        });

        $model = $this->save($model, $byValueFrom);

        //Set the siteSlug variable for routes that need the siteSlug variable in their route
        $routeParameters = [];
        $site = $this->siteService->getCurrentSite();
        if($site->exists)
            $routeParameters['siteSlug'] = $site->slug;
        $routeParameters[$this->slug] = $model;

        $sessionData = [
            'tabslug' => Input::get('tabslug'),
            'success' => __('kms/global.saved')
        ];

        //TODO AFTER MERGING DEVELOPMENT INTO KMS 2.0: Check if validation did pass. if not, get the uploadedDocuments, and merge them in the request with:             return redirect()->back()->withInput(array_merge(Input::all(), $uploadedDocuments))->withErrors($validator);

        $this->recentModel = $model;
        return Redirect::action('\\'.get_class($this) . '@show', $routeParameters)->with($sessionData);
    }

    /**
     * This method handles the update functionality.
     * And is called by the edit form.
     *
     * @param $model Model
     * @return mixed
     * @throws \Exception
     * @throws \Throwable
     */
    public function update($model)
    {
        $this->authorize('update', $model);
        $this->modelService->createRootTreeModelIfNeeded();

        //Prepare the model and the attributes
        if($this->forTranslationModelName) $model = $this->translationService->makeAndInjectEmptyTranslationsIntoTranslatableIfNeeded($model);
        $this->section->generateAttributesAndAddThemToTabs($model);
        $attributes = $this->section->getAttributes();

        //Validate the form data and fill the attributes from input
        $validator = $this->dataService->validateInputAndReturnValidator($attributes);
        //TODO AFTER MERGING DEVELOPMENT INTO KMS 2.0: Check if validation did pass. if not, get the uploadedDocuments, and merge them in the request with:             return redirect()->back()->withInput(array_merge(Input::all(), $uploadedDocuments))->withErrors($validator);

        if ($validator->fails()) return redirect()->back()->withInput()->withErrors($validator);
        $attributes = $this->dataService->fillAttributesFromInput($attributes);

        $byValueFrom = $attributes->mapToGroups(function($attribute, $index) {
            /** @var Attribute $attribute */
            return [$attribute->getsValueFrom() => $attribute];
        });

        $model = $this->save($model, $byValueFrom);

        //Set the siteSlug variable for routes that need the siteSlug variable in their route
        $routeParameters = [];
        $site = $this->siteService->getCurrentSite();
        if($site->exists)
            $routeParameters['siteSlug'] = $site->slug;
        $routeParameters[$this->slug] = $model;

        $sessionData = [
            'tabslug' => Input::get('tabslug'),
            'success' => __('kms/global.saved')
        ];

        //Redirect the users to the "show" page.
//        return \Redirect::action('\\'.get_class($this) . '@show', $routeParameters)->with($sessionData);
        return \Redirect::action('\\'.get_class($this) . '@show', $routeParameters)->with($sessionData);
    }

    /**
     * This method is called when a item will be deleted
     *
     * @param Model $model
     * @return mixed
     * @throws \Exception
     */
    public function destroy(Model $model)
    {
        $this->authorize('destroy', $model);

        $this->modelService->createRootTreeModelIfNeeded();

        //Set the siteSlug variable for routes that need the siteSlug variable in their route
        $routeParameters = [];
        $site = $this->siteService->getCurrentSite();
        if($site->exists)
            $routeParameters['siteSlug'] = $site->slug;
        $routeParameters[$this->slug] = $model;

        /** @var Model $model */
        $this->componentAreaService->destroyForModel($model);
        $this->documentService->destroyForModel($model);
        $this->routeService->destroyForModel($model);
        if($this->forTranslationModelName) $model = $this->translationService->destroyForModel($model);
        $model = $this->modelService->destroyForModel($model);
        $model->delete();

        //Return to the item index
        return Redirect::action('\\' . get_class($this) . '@index', $routeParameters)->with('message', __('kms/global.removed'));
    }


    /**
     * Returns a rendered view
     *
     * @param Model $model
     * @return View
     */
    protected function render(Model $model = null)
    {
        if ($this->showEntity) $this->section->generateAttributesAndAddThemToTabs($this->forModelInstance);
        if (!$model) return $this->makeView(); //Return a view since we can't fill it with data because the model is not set

        if($this->showEntity) {
            $byValueFrom = $this->section->getAttributes()->mapToGroups(function($attribute, $index) {
                /** @var Attribute $attribute */
                return [$attribute->getsValueFrom() => $attribute];
            });
            $this->load($model, $byValueFrom);
        }

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

        $modelId = ($this->forModelInstance) ? $this->forModelInstance->id : null;
        $saveRoute = $this->routeService->getSaveRoute($this->slug, $modelId);
        $successes = (Session::has('successes')) ? Session::get('successes') : new MessageBag();

        $thumbnail = '';
        if(is_a($this->forModelInstance, HasThumbnailInterface::class)) {
            $thumbnail = $this->forModelInstance->getThumbnail();
        };

        if(is_a($this->forModelInstance, DisplayNameInterface::class)) {
            $displayName = $this->forModelInstance->getDisplayName();
        } else {

            $displayName = $this->section->getSectionNewModel();
        }

//        $sideBarModels = $this->modelService->getModelsForSideBar();p
        $siteSlug = !$this->siteService->getCurrentSite()->exists ? null : $this->siteService->getCurrentSite()->slug;
        return \View::make('kms/section.index', [
            'sectionTitle'                 => $this->section->getSectionTitle(),
            'sectionSubtitle'              => $this->section->getSectionSubtitle(),
            'sectionTabs'                  => $this->section->getTabs(),
            'slug'                         => $this->slug,
            'siteSlug'                     => $siteSlug,
            'saveRoute'                    => $saveRoute,
            'successes'                    => $successes,
            'models'                       => $this->modelService->getModelsForSideBar(),
            'maxUploadSize'                => KommaHelpers::fileUploadMaxSize(),
            'maxPostSize'                  => KommaHelpers::maxPostSize(),
            'modelClassName'                 => $this->classModelName,
            'sortable'                     => $this->sortable,
            'showEntity'                   => $this->showEntity,
            'thumbnail'                    => $thumbnail,
            'displayName'                  => $displayName,
            'currentModel'                 => $this->forModelInstance,
            'submitButtonLabel'            => $this->section->getSubmitButtonLabel(),
            'preventNavigationTranslation' => json_encode(__('kms/prevent-navigation'))
        ])->with($sessionData);
    }

    /**
     * Get the models a a tree for api calls
     *
     * @throws \Illuminate\Auth\Access\AuthorizationException
     */
    public function getStructureAsJson()
    {
        $this->authorize('index', $this->classModelName);
        $rootModel = $this->modelService->getRootModelForTree();
        $structure = $this->treeService->getStructure($rootModel);
        return json_encode($structure);
    }

    /**
     * Change the model tree
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function setStructureAsJson()
    {
        // Special way to get POST data send by ajax on IIS servers
        $data = json_decode(request()->getContent());
        $tree = json_decode($data->tree, true);

        $this->treeService->setStructure($tree);

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

    /**
     * Validate for model
     */
    private function validateClassModelNames()
    {
        if(!$this->classModelName) throw new \RuntimeException('Make sure you set (override) the $classModelName property in the controller ('.get_class($this).') to the eloquent model the controller does it\'s job for.');
        if(!class_exists($this->classModelName)) throw new \RuntimeException('The modelClassName must be a class but was not.');
    }

    /**
     * A function that MUST delegate to services to accomplish saving.
     * It MUST NOT act like a service.
     *
     * @param Model $model
     * @param Collection $attributesByValueFrom Keys must be ValueFrom integers. Values must be Attributes that have the ValueFrom integers
     * @return Model
     */
    protected function save(Model $model, Collection $attributesByValueFrom = null): Model
    {
        if($attributesByValueFrom == null) return $model;

        //Delegate to services to handle to process the model
        /** @var Attribute $attribute */
        $model = $this->modelService->save($model, $attributesByValueFrom->collapse());
        if($this->forTranslationModelName) $model = $this->translationService->save($model, $attributesByValueFrom->get(Attribute::ValueFromTranslationModel));
        $model = $this->documentService->save($model, $attributesByValueFrom->get(Attribute::ValueFromDocuments));

        //Save component area attributes
        if($this->forTranslationModelName) {
            $componentAreaAttributes = $attributesByValueFrom->get(Attribute::ValueFromComponentArea);
            if($componentAreaAttributes) {
                $componentAreaAttributes->each((function (Attribute $attribute) use ($model) {
                    if ($attribute->getValue() == '') return;
                    //Check if the component area attribute is empty. If it is. We don't need to save it
                    //check if the translation if empty. If so, we need to save it in order to save the component area
                    $translationModel = $this->translationService->getTranslationModelForModelByLanguage($model,
                        $attribute->getAssociatedLanguage());
                    if ($translationModel->isEmpty()) {
                        $translationModel->translatable()->associate($model);
                        $translationModel->save();
                    }
                    $this->componentAreaService->saveAttribute($translationModel, $attribute);
                })->bindTo($this));
            }
        }

        $model = $this->siteService->save($model, $attributesByValueFrom->collapse()->filter(function (Attribute $attribute) use ($model) {
            return $attribute->getsValueFromReference() == 'site_id';
        }));

        $model = $this->relatedModelService->save($model, $attributesByValueFrom->get(Attribute::ValueFromModelHasManyRelation));
        $model = $this->routeService->createOrUpdateRoutesForModelsTranslationsIfChanged($model);

        return $model;
    }

    /**
     * A function that MUST delegate to services to accomplish loading.
     * It MUST NOT act like a service.
     *
     * @param Model $model
     * @param Collection $attributesByValueFrom Keys must be ValueFrom integers. Values must be Attributes that have the ValueFrom integers
     * @return Collection The same collection as you've passed in. Only "filled".
     */
    protected function load(Model $model, Collection $attributesByValueFrom = null): Collection
    {
        if($attributesByValueFrom === null) return new Collection();

        /** @var Attribute $attribute */
        $this->modelService->load($model, $attributesByValueFrom->collapse());
        if($this->forTranslationModelName) $this->translationService->load($model, $attributesByValueFrom->get(Attribute::ValueFromTranslationModel));
        $this->documentService->load($model, $attributesByValueFrom->get(Attribute::ValueFromDocuments));

        //Load component area attributes
        if($this->forTranslationModelName) {
            $componentAreaAttributes = $attributesByValueFrom->get(Attribute::ValueFromComponentArea);
            if($componentAreaAttributes) {
                $componentAreaAttributes->each(function (Attribute $attribute) use ($model) {
                    if (($language = $attribute->getAssociatedLanguage()) && $model) {
                        $translationModel = $this->translationService->getTranslationModelForModelByLanguage($model, $language);
                        if ($translationModel) {
                            $this->componentAreaService->loadAttribute($translationModel, $attribute);
                        }
                    }
                });
            }
        }

        $this->siteService->load($model, $attributesByValueFrom->collapse()->filter(function (Attribute $attribute) use ($model) {
            return $attribute->getsValueFromReference() == 'site_id';
        }));
        $this->relatedModelService->load($model, $attributesByValueFrom->get(Attribute::ValueFromModelHasManyRelation));

        return $attributesByValueFrom;
    }
}