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/stafa.komma.pro/app/Komma/Sites/Kms/SiteService.php
<?php

namespace App\Komma\Sites\Kms;

use App\Helpers\KommaHelpers;
use App\Http\Middleware\SiteSlugResolver;
use App\Komma\Kms\Core\Attributes\Models\SelectOptionInterface;
use App\Komma\Kms\Core\Attributes\Models\Traits\HasThumbnailInterface;
use App\Komma\Kms\Core\Sections\SectionService;
use App\Komma\Kms\Core\Sections\SideBarListItem;
use App\Komma\Globalization\Languages\Models\Language;
use App\Komma\Pages\Kms\PageService;
use App\Komma\Pages\Models\Page;
use App\Komma\Sites\HasSiteInterface;
use App\Komma\Sites\HasSitesInterface;
use App\Komma\Sites\Models\Site;
use App\Komma\Sites\SiteServiceInterface;
use Illuminate\Database\Eloquent\Collection as DatabaseCollection;
use Illuminate\Support\Collection as BaseCollection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;

/**
 * Represents a service that can do all kinds of things with the site model.
 * Make sure you use only 1 instance of this service throughout the whole application because it keeps track of the current site.
 * So handle it like a singleton using the IOC DI service container of laravel.
 *
 * Interface SiteServiceInterface
 * @package App\Komma\Sites
 */
final class SiteService extends SectionService implements SiteServiceInterface
{
    protected $sortable = false;

    /** @var Site $currentSite */
    protected $currentSite;

    /** @var Collection $sites */
    protected $sites;

    protected $siteLanguages = [];

    protected $sitesIndex = [];
    protected $siteLanguageIdIndex;

    function __construct()
    {
        $this->isSiteService = true;
        $this->forModelName = Site::class;
        $this->getSites();

        parent::__construct();
    }

    /**
     * This method will get a specific site
     *
     * @param integer $id
     * @return Site
     */
    public function getSite($id = 1): Site
    {
        $site = $this->sites->where('id', '=', $id)->first();
        if(!$site) throw new \RuntimeException('There is no site with id: '.$id);
        return $site;
    }

    /**
     * This method will get all the sites
     *
     * @return Collection|static[]
     */
    public function getSites()
    {
        if(!$this->sites) $this->sites = Site::all();
        return $this->sites;
    }

    /**
     * This method will get all the models.
     * And add these to the sidebarList.
     *
     * @return array $sidebarList
     */
    public function getModelsForSideBar():array
    {
        $sites = Site::get();

        $sidebarList = [];
        foreach ($sites as $site) {
            //New SidebarListItem
            $sidebarListItem = new SidebarListItem();
            /** @var HasThumbnailInterface $site */
            $site->generateThumbnail();

            //Set the values for the sidebar
            $sidebarListItem->setId($site->id);
            $sidebarListItem->setName($site->name);
            $sidebarListItem->setThumbnail($site->getThumbnail());

            $sidebarList[] = $sidebarListItem;
        }

        return $sidebarList;
    }

    /**
     * @param bool $allowNullableSelectOption
     * @return \Illuminate\Support\Collection
     */
    public function getOptionsForSelect(bool $allowNullableSelectOption = false): BaseCollection
    {
        $siteSelectOptions = collect();

        $sites = Site::get();

        foreach($sites as $site){
            /** @var SelectOptionInterface $selectOption */
            $selectOption = app(SelectOptionInterface::class);
            $selectOption
                ->setValue($site->id)
                ->setContent($site->id)
                ->setHtmlContent($site->name);

            $siteSelectOptions->push($selectOption);
        }
        return $siteSelectOptions;

    }

    /**
     * Makes the AbstractTranslatableModel a child from the sites by id if it isn't a child yet
     *
     * @param HasSitesInterface $model
     * @param string $siteIds comma seperated like this 1,4,2,5 or nothing or an empty string if you don't want to link the model to sites anymore
     */
    public function linkModelToSitesUsingIdCsvString(HasSitesInterface $model, string $siteIds = ''):void
    {
        if($siteIds !== "") {
            $siteIds = array_unique(explode(',', $siteIds));
        } else {
            $siteIds = [];
        }

        $sites = $this->forModelName::whereIn('id', $siteIds)->get();

        if(!$sites) return;

        $modelShortClassName = KommaHelpers::getShortNameFromClass($model, true);
        $relationName = str_plural($modelShortClassName);

        if(!method_exists((new $this->forModelName), $relationName)) {
            throw new \RuntimeException('The class "'.$this->forModelName.'" must have, but did not have a BelongsToMany relation method called "'.$relationName.'". Without it we cannot link "'.get_class($model).'" to "'.$this->forModelName.'"');
        }

        $siteRelation = $model->sites();
        if(is_a($siteRelation, BelongsToMany::class)) {
            if(!$model->id) throw new \RuntimeException('The model must be saved first before we can link it to a site');

            /** @var BelongsToMany $siteRelation */
            $siteRelation->sync($siteIds);
        } else {
            throw new \RuntimeException('The '.$relationName.' method on '.get_class($model).' must be a '.BelongsToMany::class.' relation.');
        }
    }

    /**
     * Makes the AbstractTranslatableModel a child from the sites by id if it isn't a child yet.
     *
     * @param HasSiteInterface $model
     * @param int $siteId the id of a site you want to link the model to or null of you don't want to link it to a site anymore
     */
    public function linkModelToSiteWithId(HasSiteInterface $model, int $siteId = null):void
    {
        $site = $this->forModelName::where('id', '=', $siteId)->first();
        if(!$site) return;

        $relationName = KommaHelpers::getShortNameFromClass($model, true);

        $siteRelation = $model->site();
        if(is_a($siteRelation, BelongsTo::class)) {
            /** @var BelongsTo $model->site() */
            if($siteId) {
                $siteRelation->associate($siteId);
            } else {
                $siteRelation->dissociate();
            }
            $model->save();
        } else {
            throw new \RuntimeException('The '.$relationName.' method on '.get_class($model).' must be a '.BelongsTo::class.' relation.');
        }
    }

    /**
     * Links a given model to the current site if it is needed.
     * It is needed when the model implements the HasSitesInterface
     * as a belongsTo relationship AND if this service holds a "current site" that is not the default site
     *
     * @param Model $model
     */
    public function linkModelToCurrentSite(Model $model)
    {
        $hasSites = is_a($model, HasSitesInterface::class);
        if($hasSites && $this->currentSite->exists) {
            /** @var HasSitesInterface $model */
            if(is_a($model->sites(),BelongsTo::class)) {
                $this->linkModelToSitesUsingIdCsvString($model, $this->currentSite->id);
            }
        }
        return;
    }

    /**
     * Set the site to the default / first one available
     *
     */
    public function setCurrentSiteToDefault(){
        $this->currentSite = Site::first();
    }

    /**
     * Sets the site you are currently using
     *
     * @param $siteSlug
     */
    public function setCurrentSiteBySlug($siteSlug)
    {
        if($siteSlug !== null) {
            $site = $this->sites->where('slug', $siteSlug)->first();
            if(!$site) throw new \RuntimeException('Could not set the current site since a site for slug "'.$siteSlug.'" could not be found. Check configuration in domain.php');
        } else {
            $defaultLanguage = Language::where('native_name', '=', 'Nederlands')->first();
            if(!$defaultLanguage) throw new \RuntimeException('Could not find the default language with a native name of: Nederlands.');

            $site = new Site([
                'default_language_id' => $defaultLanguage->id
            ]);
            $site->setRelation('defaultLanguage', $defaultLanguage);
        }

        $this->currentSite = $site;
    }

    /**
     * Gets the site you are currently using
     *
     * @return Site
     */
    public function getCurrentSite()
    {
        if ($this->currentSite) {
            return $this->currentSite;
        } elseif(\App::runningInConsole()) {
            return $this->currentSite = $this->setCurrentSiteToDefault();
        } else {
            $this->setCurrentSiteToDefault();
            return $this->currentSite;
        }

        //throw new \RuntimeException('The current site is not set. Maybe my buddy '.SiteSlugResolver::class.' fell a sleep since he needs to give me the current site.'.KommaHelpers::parseBacktraceToConsoleString(debug_backtrace()));
    }

    /**
     * @return int
     */
    public function getCurrentSiteDefaultLanguage(): int
    {
        if ($this->currentSite) {
            return $this->currentSite->default_language_id;
        }
        return 104;
    }

    /**
     * Returns the current site's languages
     *
     * @return DatabaseCollection of Language
     */
    public function getSiteLanguages(): DatabaseCollection
    {
        //dd($this->currentSite->languages);
        if ($this->currentSite && $this->currentSite->languages->count() > 0) {
            return $this->currentSite->languages;
        }

        $defaultSiteLanguage = $this->getCurrentSiteDefaultLanguage();
        if($defaultSiteLanguage)
        {
            $language = Language::find($defaultSiteLanguage);
            if($language) return new DatabaseCollection([$language]);
        }



        return collect();
    }

    /**
     * Returns an array if integers or a csv string if asString is true representing the sites
     * of a model or return null if the model does not have sites
     *
     * @param Model $model
     * @param bool $asString
     * @return null|string|array
     */
    public function getSiteIdsForModel(Model $model, bool $asString = true)
    {
        $relationName = null;
        if(is_a($model, HasSiteInterface::class)) {
            /** @var HasSiteInterface $model */
            $relationName = 'site';
        }
        elseif(is_a($model,HasSitesInterface::class))
        {
            /** @var HasSitesInterface $model */
            $relationName = 'sites';
        }

        if(!$relationName) return null;

        $ids = $model->$relationName()->get()->map(function(Site $site) {
            return $site->id;
        });

        if($asString) {
            $ids = implode(',', $ids->toArray());
        }

        return $ids;
    }

    /**
     * This method will remove an TranslatableModelInterface instance
     *
     * @param $model
     * @throws \Exception
     */
    public function destroyModel(Model $model)
    {
        //Delete pages using the page service. Since that will also delete routes and other stuff
        $pageService = new PageService();
        /** @var Site $model */
        $model->pages()->each(function(Page $page) use($pageService) {
            $pageService->destroyModel($page);
        });

        parent::destroyModel($model);
    }


}