File: D:/HostingSpaces/SBogers10/structura.komma.pro/app/KommaApp/Kms/Core/Sections/Section.php
<?php
namespace App\KommaApp\Kms\Core\Sections;
use App\Helpers\KommaHelpers;
use App\KommaApp\Images\ImageService;
use App\KommaApp\Kms\Core\Attributes\Attribute;
use App\KommaApp\Kms\Core\Attributes\ImageableAttribute;
use App\KommaApp\Kms\Core\Attributes\Traits\LabelTrait;
use App\KommaApp\Kms\Core\KmsInterface;
use App\KommaApp\Languages\Models\Language;
use App\KommaApp\Routes\RouteService;
use Illuminate\Contracts\View\View;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\MessageBag;
use Illuminate\Support\ViewErrorBag;
/**
* Class Section. Will replace KmsSection
* @package App\KommaApp\Kms\Core\Sections
*/
abstract class Section
{
/** @var KmsInterface $kms */
protected $kms;
/**
* @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;
private $processedAttributes = [];
/** @var Model $model */
private $model = null;
protected $models = [];
//True if the models uses an eav
protected $eav = false;
protected $errors = [];
protected $successes = [];
protected $title = "";
protected $subTitle = "";
protected $slug = "";
public $submitButtonLabel = 'save';
// 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;
/*
* 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;
/** @var Model $forModelName */
private $forModelName;
function __construct (SectionServiceInterface $sectionService, RouteService $routeService, AbstractSectionTabsDirector $sectionTabDirector)
{
$this->submitButtonLabel = __('kms/global.save');
$this->kms = \App::make(KmsInterface::class);
$this->sectionService = $sectionService;
$this->routeService = $routeService;
$this->sectionTabDirector = $sectionTabDirector;
//localize
$this->submitButtonLabel = \Lang::get('kms/global.save');
}
public function getSectionService()
{
return $this->sectionService;
}
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->sectionService->getModelsForSideBar();
}
/**
* This method returns the thumbnail for the top bar
*
* @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 as array, return only the string
elseif (isset($this->model->thumbnail['string'])) {
return $this->model->thumbnail['string'];
}
//return thumbnail
else return '';
}
//Return empty string
return '';
}
/**
* 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, Model::class))
{
$this->model = $idOrModel;
$this->sectionService->setThumbnail($idOrModel);
} else {
throw new \InvalidArgumentException("KmsSection loadModel expected a variable of type int or numeric string or eloquent model 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 = $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;
}
/**
* 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;
}
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 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 ($this->model && $this->model->exists && ($this->model->title || $this->model->title != "")) {
return $this->model->title;
}
//No model title return new {type}
return trans('kms/' . $this->slug . '.new');
}
/**
* Generates the attributes for this section. They all must extend the App\KommaApp\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()
{
// \Log::debug("KmsSection:300 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();
}
// private function routes()
// {
// $modelId = $this->getModelId(); //43 for example
// $slug = $this->getSlug(); //Pages for example
// $siteSlug = $this->kms->getSiteSlug(); //default for example
//
//
// //If we have a modelId, then we need to update (PUT) the model. Else we need to store (POST) a new model.
// $saveRoute = ($modelId) ? strtolower($this->slug).'.update' : strtolower($this->slug).'.store';
// $saveMethod = ($modelId) ? 'PUT': 'POST';
//
// //Set route parameters
// $routeParameters = [];
// if($siteSlug) $routeParameters['siteSlug'] = $siteSlug;
// if($siteSlug) $routeParameters[$this->sectionService->] = $siteSlug;
//
//
// route($saveRoute, $routeParameters);
// }
/**
* Makes the view and returns it
*
* @return View
*/
protected function makeView(): View
{
$saveRoute = $this->routeService->getSaveRoute($this->getSlug(), $this->getModelId());
$successes = (\Session::has('successes')) ? \Session::get('successes') : new MessageBag();
return \View::make('kms/section.index', [
'kms' => $this->kms,
'section' => $this,
'saveRoute' => $saveRoute,
'successes' => $successes,
'maxUploadSize' => KommaHelpers::fileUploadMaxSize()
]);
}
/**
* 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);
$this->processImageableAttributesFromInput($model);
$this->createOrUpdateRoutesForModelIfChanged($model);
//Fire the event saved method
\Event::fire('kms.entity.saved.' . $this->slug, $this->model);
//Return the id
return $model;
}
private function createOrUpdateRoutesForModelIfChanged(Model $model)
{
$this->routeService->createOrUpdateRoutesForModelIfChanged($model);
return null;
}
/**
* This method calls the destroyModel method
* from the give repository class.
*
* @param Model $model
* @throws \Exception
*/
public function destroy(Model $model)
{
if($this->hasRoutes) $this->routeService->deleteRoutesForModel($model);
$this->sectionService->destroyModel($model);
}
// /**
// * This 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(); //Returns an array with an attribute key as key and an array of error strings as value.
//
// if(!$this->sectionTabItems) return;
//
// $this->sectionTabItems->each(function($sectionTabItem, $key) {
// /** @var SectionTabItem $sectionTabItem */
// $attribute = $sectionTabItem->getAttribute();
//
// if (isset($errors)) {
// $errors = $this->errors[$attribute->getKey().''];
// $attribute->getValidationSet()->setErrors($errors);
// }
// });
// }
//
// /**
// * This method creates a success list for each attribute
// *
// * @param MessageBag $successes
// */
// public function setSuccesses(MessageBag $successes = null)
// {
// //If errors are empty; return
// if (!$successes) return;
// //Get the errors from the error
// $this->successes = $successes->getMessages(); //Returns an array with an attribute key as key and an array of success message strings as value.
//
// if(!$this->sectionTabItems) return;
//
// $this->sectionTabItems->each(function($sectionTabItem, $key) {
// /** @var SectionTabItem $sectionTabItem */
// $attribute = $sectionTabItem->getAttribute();
//
// if (isset($successes)) {
// $successes = $this->successes[$attribute->getKey().''];
// $attribute->getValidationSet()->setSuccesses($successes);
// }
// });
// }
/**
* 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 = [])
{
$this->extendValidator();
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());
}
// dd($rules);
$validator = \Validator::make($input, $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()
{
if (is_array($this->showCreate)) {
return in_array(\Auth::user()->role->id, $this->showCreate);
}
return $this->showCreate == 'all' || ($this->showCreate == 'admin' && \Auth::user()->role->id == 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()
{
if (is_array($this->showDelete)) {
return in_array(\Auth::user()->role->id, $this->showDelete);
}
return $this->showDelete == 'all' || ($this->showDelete == 'admin' && \Auth::user()->role->id == 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()
{
if (is_array($this->showSave)) {
return in_array(\Auth::user()->role->id, $this->showSave);
}
return $this->showSave == 'all' || ($this->showSave == 'admin' && \Auth::user()->role->id == 1);
}
/**
* 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);
}
// /**
// * Create a list with KmsAttribute Objects, based on $this->modelAttributes
// * The data is from the modelSection file
// *
// * @return array
// */
// protected function parseModelAttributesData($test = false)
// {
// //TODO JULES: REBUILD THIS OOP. THIS METHOD PROBABLE CAN BE DELETED IN THE FUTURE
//
// //Create empty attributes
// $this->sectionTabItems = [];
//
//
// foreach ($this->sectionTabItems as $attributeKey => $attribute) {
// if(is_object($attribute)) {
// //Detected a new type of object! This branch is used for transitioning from not so OOP objects to OOP and will become obsolete in the future
//
// $this->sectionTabItems[] = $attribute;
//// $this->tabDirector->addItem($attribute, \Config::get('kms.main.defaultTabName')); TODO: This is now done in the section constructor
// } else {
// if (isset($attribute['role']) && !in_array(\Auth::user()->role->id, $attribute['role'] )) continue;
//
// //Set the specific type of foreach
// $forEach = isset($attribute['forEach']) ? $attribute['forEach'] : null;
//
// //TODO JULES MAYBE WE SHOULD CREATE FACTORYS / BUIDERS FOR THIS STUFF BELOW
// // create attributes
// switch ($forEach) {
// case "CurrentSiteLanguages":
//// $this->createAttributeForCurrentSiteLanguages($attributeKey, $attribute);
// $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;
// }
// }
// }
//
//// dd($this->attributes);
// return $this->sectionTabItems;
// }
/**
* 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->kms->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)
{
// Get all used languages from the site_languages table
$languages = Language::has('Sites')->get();
$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;
}
/**
* 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->getSiteLanguages();
$this->createAttributeForLanguages($key, $attributeData, $languages);
}
/**
* This method will create the fields for all the Languages
*
* @param array $baseAttributes
* @return null
*/
protected function createAttributeFromExistingAttributeForAllLanguages(Array $baseAttributes)
{
//Get the languages
$languages = $this->kms->getSiteLanguages();
$attributes = [];
foreach($baseAttributes as $baseAttribute) {
$attributesCreatedFromBaseAttribute = $this->createAttributesFromExistingAttributeForTheGivenLanguages($baseAttribute, $languages);
$attributes = array_merge($attributes, $attributesCreatedFromBaseAttribute);
}
return $attributes;
}
/**
* This method creates the fields for all the languages in all the sites
*
* @param $key
* @param $attributeData
* @deprecated
*/
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->sectionTabItems[] = new $attributeData['type']($currentKey, $value, $options, [], $site->id, $language->id, $this);
//Add the item to the tab
// $this->tabDirector->addItem($item, $tab, $subTab);
}
}
}
/**
* This method creates the fields for all the sites
*
* @param $key
* @param $attributeData
*/
protected function createAttributeForAllSites($key, $attributeData, $subTab = false)
{
//NOTE: METHOD IS DEPRECATED. Don't use it anymore
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->sectionTabItems[] =
new $attributeData['type']($currentKey, $value, $options, [], $site->id, null, $this, $foreach);
//Add the item to the tab
if ($subTab) {
// $this->tabDirector->addItem($item, null, $tab);
} else {
// $this->tabDirector->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)
{
//NOTE: METHOD IS DEPRECATED. Don't use it anymore
//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->sectionTabItems[] =
new $attributeData['type']($currentKey, $model, $options, [], $model->id, null, $this, $loopKey);
// $this->tabDirector->addItem($item, $tabName);
}
}
}
public function forEachModelAllSites($key, $attributeData, $model, $count, $tabName)
{
//NOTE: METHOD IS DEPRECATED. Don't use it anymore
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->sectionTabItems[] =
new $attributeData['type']($currentKey, $value, $options, [], $site->id, null, $this, null);
// $this->tabDirector->addItem($item, $tabName, $site->short_name);
}
}
public function forEachModelAllSitesAndLanguages($key, $attributeData, $model, $count, $tabName)
{
//NOTE: METHOD IS DEPRECATED. Don't use it anymore
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->sectionTabItems[] =
new $attributeData['type']($currentKey, $value, $options, [], $site->id, $language->id, $this, null);
// $this->tabDirector->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;
}
// TODO: We should not need this. We may implement related attribtutes as embeded child attributes in attributes themselves.
// 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);
//
// }
// TODO: We should not need this. We may implement related attribtutes as embeded child attributes in attributes themselves.
// 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 && $model->$key) return $model->$key;
//
// return $model;
// }
// TODO: We should not need this. We may implement related attribtutes as embeded child attributes in attributes themselves.
// 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)
// $orgModel = $model;
//
// $model = $this->getSubModel($model, $deeperLevel, $attributeData, $keyBy, $keyId);
// if(!$model && $orgModel) {
// //throw new \RuntimeException("Could not get subModel '".$deeperLevel."' from ".get_class($orgModel));
// }
// }
//
// }
//
//// if(!$model) throw new \RuntimeException("Model wasn't found for key: ".$key." Models: ".$attributeData['model']);
//
// 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)
{
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
$collection = $subModelCollection->get($keyId);
// if($subModelName == "routes") { dd($subModelCollection); }
return $collection;
}
/**
* 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->sectionTabItems 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->sectionTabItems as $key => $attribute) {
$attribute->process();
$this->processedAttributes[$attribute->getKey()] = $attribute;
}
}
// //TODO Jules: We don't need this mess anymore because we handle this stuff in attributes them self via getters and setters in a more clear and concise way
// /**
// * 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);
// else {
// $site = $this->kms->getSite();
//
// }
// 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)) {
//
// if(isset($this->model->translations)){
// // Replace routable id in validation rule
// $translations = $this->model->translations->keyBy('language_id');
// }
//
// if(isset($translations[$languageId]))
// {
// $translationId = $translations[$languageId]->id;
// $options[$key] = $option = str_replace('[[routeableId]]', $translationId, $option);
// }
//
// 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;
// }
/**
* Fills all attributes with values from the forms / session
*
* @return void
*/
public function fillAttributesFromInput()
{
// $imageService = new ImageService();
/** @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) {
$attribute->setValue($input);
}
//Insert the associated language (if any) into the attribute
if($attribute->getKey()->getTranslationIso2() != '')
{
//get the language associated with the attribute]
$language = Language::where('iso_2', $attribute->getKey()->getTranslationIso2())->first();
$attribute->setAssociatedLanguage($language);
}
}
}
/**
* Iterates over all attributes and checks if they are have Imageable interfaces.
* If they do, it checks if the input contains an image for them and adds them to
*
* @param Model $model
* @throws \Exception
*/
public function processImageableAttributesFromInput(Model $model)
{
$imageService = new ImageService();
/** @var AbstractSectionTabItem $sectionTabItem */
foreach ($this->sectionTabItems as $sectionTabItem) {
$attribute = $sectionTabItem->getAttribute();
$input = \Input::get((string)$attribute->getKey());
if(is_a($attribute, ImageableAttribute::class)) {
$imageService->setSubFolder($attribute->getSubfolder());
$imageAndStates = $imageService->uploadAndDeleteImagesFromInput($input, $attribute->getImageSizes());
if($imageAndStates) $imageService->updateImageReferencesInDatabase($imageAndStates, $model);
}
}
}
/*
* 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->sectionTabItems 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->sectionService, 'getSortable')) return $this->sectionService->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->sectionTabItems[$key]['data_type'])) return false;
return $this->sectionTabItems[$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;
}
/**
* 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;
}
}