File: D:/HostingSpaces/SBogers10/ehbo.today/app/KommaApp/ArchivedCourses/Kms/ArchivedCourseService.php
<?php
/**
* Created by PhpStorm.
* ArchivedCourse: julesgraus
* Date: 31/01/2018
* Time: 13:13
*/
namespace App\KommaApp\ArchivedCourses\Kms;
use App\KommaApp\Competences\Kms\CompetenceService;
use App\KommaApp\Competences\Models\Competence;
use App\KommaApp\Kms\Core\AbstractTranslatableModel;
use App\KommaApp\Kms\Core\Attributes\Attribute;
use App\KommaApp\Kms\Core\Sections\AbstractSectionTabItem;
use App\KommaApp\Kms\Core\Sections\SectionService;
use App\KommaApp\ArchivedCourses\Models\ArchivedCourse;
use App\KommaApp\Kms\Core\Sections\SectionTabItem;
use App\KommaApp\Users\Kms\UserService;
use App\KommaApp\Users\Models\User;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Query\Builder;
class ArchivedCourseService extends SectionService
{
protected $sortable = false;
protected $orderBy = 'date';
/** @var CompetenceService $competenceService */
protected $competenceService;
/** @var UserService $userService */
private $userService;
function __construct()
{
$this->forModelName = ArchivedCourse::class;
$this->competenceService = \App::make(CompetenceService::class);
$this->userService = \App::make(UserService::class);
parent::__construct();
}
public function saveModel(Model $model = null, Collection $sectionTabItems): Model
{
$userPresenceData = [];
/** @var ArchivedCourse $model */
$sectionTabItems->each(function($sectionTabItem, $key) use($model, &$userPresenceData) {
/** @var SectionTabItem $sectionTabItem */
$attribute = $sectionTabItem->getAttribute();
$value = $attribute->getValue();
$reference = $attribute->getsValueFromReference();
switch ($attribute->getsValueFrom())
{
case Attribute::ValueFromItself:
if($reference == 'subscribed_users' || $reference == 'present_users') {
if($reference == 'subscribed_users') $status = ArchivedCourse::UserStatusSubscribed;
elseif($reference == 'present_users') $status = ArchivedCourse::UserStatusPresent;
if($value == '') break;
$idsToProcess = collect(explode(',', $value));
$syncData = $idsToProcess->mapWithKeys(function($userId) use ($status) {
return [$userId => ['user_status' => $status]];
})->toArray();
$userPresenceData = $userPresenceData + $syncData; //Union operation (combine arrays, left one is leading of both have same key)
}
break;
}
});
$model->save(); //Save the page
$model = parent::saveModel($model, $sectionTabItems); //First make sure we have a model and save the attributes in them from the SectionTabItem attributes
$statusArray = $model->users()->sync($userPresenceData);
//Ids (Users) that are attached should get the competences of the archivedCourse
$competences = $model->competences()->get();
foreach($statusArray['attached'] as $attachedId) {
$user = User::find($attachedId);
$competences->each(function(Competence $competence) use ($user) {
$this->competenceService->userAcquiredCompetence($user, $competence);
});
}
foreach($statusArray['detached'] as $attachedId) {
$user = User::find($attachedId);
$competences->each(function(Competence $competence) use ($user) {
$this->competenceService->revertAcquiredCompetence($user, $competence);
});
}
//Return the page
return $model;
}
/**
* This method will remove an TranslatableModelInterface instance
*
* @param $model
* @throws \Exception
*/
public function destroyModel(Model $model)
{
//delete the images
$this->imageService->deleteModelImages($model);
if(is_a($model, DocumentableInterface::class)) $this->documentService->deleteDocumentsForModel($model);
if(is_a($model,AbstractTranslatableModel::class)) {
foreach ($model->translations()->get() as $translation) {
//Delete the route of the translation
if(is_a($model, HasRoutesInterface::class)){
$translation->routes()->delete();
}
//Delete the translation
$translation->delete();
}
}
$model->users()->detach();
$model->competences()->detach();
$model->delete();
}
public function fillAttributesWithData(Collection $sectionTabItems, Model $model)
{
//Validate that each Collection item is an instance of AbstractSectionTabItem
$sectionTabItems->every(function($item, $key) {
if(!is_a($item, AbstractSectionTabItem::class)) throw new \InvalidArgumentException("The attributes passed must be a Collection of AbstractSectionTabItem instances but was not");
});
$filledAttributes = new Collection();
if(is_a($model, AbstractTranslatableModel::class)) $model->load('translations');
/** @var ArchivedCourse $model */
$sectionTabItems->each(
function ($sectionTabItem, $key) use ($model, $filledAttributes) {
/** @var $sectionTabItem SectionTabItem */
if(!is_a($sectionTabItem->getAttribute(), Attribute::class)) throw new \InvalidArgumentException("One of the attributes in a AbstractSectionTabItem instance is not but must be an child instance of Attribute.");
$value = null;
$valueReference = $sectionTabItem->getAttribute()->getsValueFromReference();
switch($sectionTabItem->getAttribute()->getsValueFrom())
{
case Attribute::ValueFromItself:
switch ($valueReference)
{
case 'subscribed_users':
$ids = $model->users()->wherePivot('user_status', '=', ArchivedCourse::UserStatusSubscribed)->get()->map(function(User $user) {
return $user->id;
})->toArray();
$value = implode(',', $ids);
break;
case 'present_users':
$ids = $model->users()->wherePivot('user_status', '=', ArchivedCourse::UserStatusPresent)->get()->map(function(User $user) {
return $user->id;
})->toArray();
$value = implode(',', $ids);
break;
}
break;
}
//Finally when we have a value we will set it on the attribute and then process the next one.
if($value !== null) {
$sectionTabItem->getAttribute()->setValue((string)$value);
}
$filledAttributes->push($sectionTabItem);
}
);
$filledAttributes = parent::fillAttributesWithData($sectionTabItems, $model);
return $filledAttributes;
}
/**
* @param User $user
* @return \Illuminate\Support\Collection
*/
public function recommendedArchivedCourses(User $user)
{
//Get the competences for a user that are expired and missing. Collect them into a new collection
$expiredCompetences = $this->getExpiredCompetences($user);
$missingCompetences = $this->getMissingCompetences($user);
$almostExpired = $this->getAlmostExpiredCompetences($user);
$neededCompetences = collect($expiredCompetences)->merge($missingCompetences)->merge($almostExpired);
//Find upcoming archivedCourses
$archivedCourses = ArchivedCourse::has('competences')->with('competences')->whereDate('date', '>=', Carbon::now()->startOfDay())->get();
//Use the expired competences to find upcoming archivedCourses that cover those competences.
$recommendedArchivedCourses = collect();
$neededCompetences->each(function(Competence $neededCompetence) use (&$recommendedArchivedCourses, $archivedCourses) {
//dd($archivedCourses);
$archivedCourses->each(function (ArchivedCourse $archivedCourse) use (&$recommendedArchivedCourses, $neededCompetence) {
$archivedCourse->competences->each(function(Competence $currentArchivedCourseCompetence) use(&$recommendedArchivedCourses, $archivedCourse, $neededCompetence) {
if($neededCompetence->id == $currentArchivedCourseCompetence->id) $recommendedArchivedCourses->push($archivedCourse);
});
});
});
//Filter out doubles
$recommendedArchivedCourses = $recommendedArchivedCourses->unique();
$recommendedArchivedCourses = $recommendedArchivedCourses->sortBy('date');
//Filter out archivedCourses that the user already signed up on or is present in
// $recommendedArchivedCourses = $recommendedArchivedCourses->filter(function(ArchivedCourse $archivedCourse) use ($user) {
// return $user->archivedCourses()->get()->contains('id','=',$archivedCourse->id);
// });
return $recommendedArchivedCourses;
}
/**
* @param User $user
* @param bool $includeUserCompetenceStatuses
* @return Collection
*/
public function subscribedArchivedCourses(User $user)
{
$subscribedArchivedCourses = $user->archivedCourses()->withPivot(['user_status'])->wherePivot('user_status', '=', ArchivedCourse::UserStatusSubscribed)->whereDate('date', '>=', Carbon::now()->startOfDay()->toDateString())->orderBy('date')->get();
return $subscribedArchivedCourses;
}
/**
* @param User $user
* @param bool $includeUserCompetenceStatuses
* @return Collection
*/
public function completedArchivedCourses(User $user)
{
$completedArchivedCourses = $user->archivedCourses()->whereDate('date', '<=', Carbon::now()->startOfDay())->withPivot(['user_status'])->wherePivot('user_status', '=', ArchivedCourse::UserStatusPresent)->orderBy('date', 'desc')->get();
return $completedArchivedCourses;
}
/**
* @param ArchivedCourse|Collection $archivedCourse
* @param User $user
* @return ArchivedCourse|\Illuminate\Support\Collection
*/
public function includeUserCompetenceStatusesForArchivedCourses($archivedCourse, User $user) {
//Convert archivedCourse to collection if needed
if(!is_a($archivedCourse, ArchivedCourse::class)) {
$archivedCourses = collect($archivedCourse);
} else {
$archivedCourses = $archivedCourse;
}
//Validate that each collection member is a archivedCourse
$archivedCourses->each(function($archivedCourse) { if(!is_a($archivedCourse, ArchivedCourse::class)) throw new \RuntimeException('One of the given "archivedCourses" was no instance of "'.ArchivedCourse::class.'"'); });
$archivedCourses->each(function(ArchivedCourse $archivedCourse) use ($user) {
$archivedCourse->load(['translations', 'competences', 'competences.translations']);
$this->includeUserCompetenceStatusesForCompetences($archivedCourse->competences, $user);
});
if(!is_a($archivedCourse, ArchivedCourse::class)) {
return $archivedCourses;
} else {
return $archivedCourses->first();
}
}
/**
* @param ArchivedCourse|Collection $archivedCourse
* @param User $user
* @return ArchivedCourse|\Illuminate\Support\Collection
*/
public function includeUserCompetenceStatusesForCompetences($competence, User $user) {
//Convert archivedCourse to collection if needed
if(!is_a($competence, Competence::class)) {
$competences = collect($competence);
} else {
$competences = $competence;
}
$missing = $this->getMissingCompetences($user);
$expired = $this->getExpiredCompetences($user);
$almost_expired = $this->getAlmostExpiredCompetences($user);
$valid = $this->getValidCompetences($user);
$competences->each(function(Competence $archivedCourseCompetence) use ($missing, $expired, $almost_expired, $valid) {
$archivedCourseCompetence->authUserCompetenceStatus = Competence::StatusUnknown;
if($missing->contains($archivedCourseCompetence->id)) $archivedCourseCompetence->authUserCompetenceStatus = Competence::StatusMissing;
if($expired->contains($archivedCourseCompetence->id)) $archivedCourseCompetence->authUserCompetenceStatus = Competence::StatusExpired;
if($almost_expired->contains($archivedCourseCompetence->id)) $archivedCourseCompetence->authUserCompetenceStatus = Competence::StatusAlmostExpired;
if($valid->contains($archivedCourseCompetence->id)) $archivedCourseCompetence->authUserCompetenceStatus = Competence::StatusValid;
});
if(!is_a($competence, Competence::class)) {
return $competences;
} else {
return $competences->first();
}
}
/**
* Get the competences that are not expired yet and thus are valid
*
* @param User $user
* @return Collection
*/
public function getValidCompetences(User $user):Collection
{
$userCompetences = $user->competences()->withPivot(['expires_at', 'acquired_at'])->with('translations')->get();
$validCompetences = $userCompetences->filter(function(Competence $competence) {
$currentExpireDate = Carbon::parse($competence->pivot->expires_at);
return Carbon::now()->diffInMonths($currentExpireDate, false) >= 2;
});
return $validCompetences;
}
/**
* Get the competences that are almost expiring (in one month)
*
* @param User $user
* @return Collection
*/
public function getAlmostExpiredCompetences(User $user):Collection
{
$userCompetences = $user->competences()->withPivot(['expires_at', 'acquired_at'])->with('translations')->get();
$validCompetences = $userCompetences->filter(function(Competence $competence) {
$currentExpireDate = Carbon::parse($competence->pivot->expires_at);
$diffInMonths = Carbon::now()->diffInMonths($currentExpireDate, false);
return $currentExpireDate->isFuture() && $diffInMonths < 2;
});
return $validCompetences;
}
/**
* Get the expired competences
*
* @param User $user
* @return Collection
*/
public function getExpiredCompetences(User $user):Collection
{
//Get the competences from the user that are expired
$userCompetences = $user->competences()->withPivot(['expires_at', 'acquired_at'])->with('translations')->get();
$expiredCompetences = $userCompetences->filter(function(Competence $competence) {
return Carbon::parse($competence->pivot->expires_at)->isPast();
});
return $expiredCompetences;
}
/**
* Get the missing competences
*
* @param User $user
* @return Collection
*/
public function getMissingCompetences(User $user):Collection
{
//Get the competences that the user does not have
$allCompetences = Competence::with('users')->get();
$missingCompetences = $allCompetences->filter(function(Competence $competence) use ($user) {
return !$competence->users->contains($user);
});
return $missingCompetences;
}
}