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/SBogers47/leden.ehbocranendonck.nl/app/KommaApp/Courses/Kms/CourseService.php
<?php
/**
 * Created by PhpStorm.
 * Course: julesgraus
 * Date: 31/01/2018
 * Time: 13:13
 */

namespace App\KommaApp\Courses\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\Courses\Models\Course;
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 CourseService extends SectionService
{
    protected $sortable = false;
    protected $orderBy = 'date';

    /** @var CompetenceService $competenceService */
    protected $competenceService;

    /** @var UserService $userService */
    private $userService;

    function __construct()
    {
        $this->forModelName = Course::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 Course $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 = Course::UserStatusSubscribed;
                        elseif($reference == 'present_users') $status = Course::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 course
        $competences = $model->competences()->get();
//        dd($userPresenceData, $competences, $statusArray);
        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 Course $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', '=', Course::UserStatusSubscribed)->get()->map(function(User $user) {
                                   return $user->id;
                                })->toArray();
                                $value = implode(',', $ids);
                                break;
                            case 'present_users':
                                $ids = $model->users()->wherePivot('user_status', '=', Course::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 recommendedCourses(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 courses
        $courses = Course::has('competences')->with('competences')->whereDate('date', '>=', Carbon::now()->startOfDay())->get();

        //Use the expired competences to find upcoming courses that cover those competences.
        $recommendedCourses = collect();
        $neededCompetences->each(function(Competence $neededCompetence) use (&$recommendedCourses, $courses) {
            //dd($courses);
            $courses->each(function (Course $course) use (&$recommendedCourses, $neededCompetence) {
                $course->competences->each(function(Competence $currentCourseCompetence) use(&$recommendedCourses, $course, $neededCompetence) {
                    if($neededCompetence->id == $currentCourseCompetence->id) $recommendedCourses->push($course);
                });
            });
        });

        //Filter out doubles
        $recommendedCourses = $recommendedCourses->unique();
        $recommendedCourses = $recommendedCourses->sortBy('date');

        //Filter out courses that the user already signed up on or is present in
//        $recommendedCourses = $recommendedCourses->filter(function(Course $course) use ($user) {
//            return $user->courses()->get()->contains('id','=',$course->id);
//        });

        return $recommendedCourses;
    }

    /**
     * @param User $user
     * @param bool $includeUserCompetenceStatuses
     * @return Collection
     */
    public function subscribedCourses(User $user)
    {
        $subscribedCourses = $user->courses()->withPivot(['user_status'])->wherePivot('user_status', '=', Course::UserStatusSubscribed)->whereDate('date', '>=', Carbon::now()->startOfDay()->toDateString())->orderBy('date')->get();

        return $subscribedCourses;
    }

    /**
     * @param User $user
     * @param bool $includeUserCompetenceStatuses
     * @return Collection
     */
    public function completedCourses(User $user)
    {
        $completedCourses = $user->courses()->whereDate('date', '<=', Carbon::now()->startOfDay())->withPivot(['user_status'])->wherePivot('user_status', '=', Course::UserStatusPresent)->orderBy('date', 'desc')->get();

        return $completedCourses;
    }

    /**
     * @param Course|Collection $course
     * @param User $user
     * @return Course|\Illuminate\Support\Collection
     */
    public function includeUserCompetenceStatusesForCourses($course, User $user) {
        //Convert course to collection if needed
        if(!is_a($course, Course::class)) {
            $courses = collect($course);
        } else {
            $courses = $course;
        }

        //Validate that each collection member is a course
        $courses->each(function($course) { if(!is_a($course, Course::class)) throw new \RuntimeException('One of the given "courses" was no instance of "'.Course::class.'"'); });

        $courses->each(function(Course $course) use ($user) {
            $course->load(['translations', 'competences', 'competences.translations']);

            $this->includeUserCompetenceStatusesForCompetences($course->competences, $user);
        });

        if(!is_a($course, Course::class)) {
            return $courses;
        } else {
            return $courses->first();
        }
    }

    /**
     * @param Course|Collection $course
     * @param User $user
     * @return Course|\Illuminate\Support\Collection
     */
    public function includeUserCompetenceStatusesForCompetences($competence, User $user) {
        //Convert course 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 $courseCompetence) use ($missing, $expired, $almost_expired, $valid) {
            $courseCompetence->authUserCompetenceStatus = Competence::StatusUnknown;
            if($missing->contains($courseCompetence->id)) $courseCompetence->authUserCompetenceStatus = Competence::StatusMissing;
            if($expired->contains($courseCompetence->id)) $courseCompetence->authUserCompetenceStatus = Competence::StatusExpired;
            if($almost_expired->contains($courseCompetence->id)) $courseCompetence->authUserCompetenceStatus = Competence::StatusAlmostExpired;
            if($valid->contains($courseCompetence->id)) $courseCompetence->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;
    }


}