File: D:/HostingSpaces/SBogers10/vangogh.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;
use Illuminate\Support\Facades\App;
/**
* 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()) {
$this->setCurrentSiteToDefault();
return $this->currentSite;
} 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);
}
}