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/shop.komma.nl/app/Categories/Kms/CategoryTreeService.php
<?php declare(strict_types=1);


namespace App\Categories\Kms;


use App\Categories\Models\Category;
use App\Http\Middleware\WildcardResolver;
use Illuminate\Database\Eloquent\Collection;
use Komma\KMS\Core\AbstractTranslatableModel;
use Komma\KMS\Core\Tree\NestedSets\Nodes\TreeModelInterface;
use Komma\KMS\Core\Tree\TreeService;

class CategoryTreeService extends TreeService
{
    public function __construct()
    {
        $this->classModelName = Category::class;
    }

    /**
     * Returns a root category with all children till the given depth.
     * And every category will have a transient "is_current" attribute set to true if it matches the tail of the url.
     * They will also have a transient attribute called "link" which refers to the category detail page.
     *
     * @param int $depth
     * @return Category|TreeModelInterface|mixed
     */
    public function treeWithTranslationsLinksAndActiveStates($depth = 0)
    {
        /** @var TreeModelInterface|Category $rootCategory */
        $rootCategory = $this->classModelName::where('lft', '=', 1)->first();
        $rootCategory->findChildren($depth);
        $allIds = $this->getAllIdsFromCategoryTree($rootCategory);
        $eagerLoadedCategoriesById = Category::whereIn('id', $allIds)->with('translation')->get()->keyBy('id');
        $rootCategory = $this->remapCategoriesWithEagerLoadedOnes($rootCategory, $eagerLoadedCategoriesById);
        $rootCategory = $this->addLinkInformation($rootCategory);

        if(WildcardResolver::getLatestResolvedWildCardRoute()) {
            $breadcrumbCategories = $this->breadcrumbToStack($rootCategory, WildcardResolver::getLatestResolvedWildCardRoute()->tail);
            foreach ($breadcrumbCategories as $category) $category->is_current = true;
        }

        return $rootCategory;
    }

    /**
     * Returns all ids of categories in the tree of categories
     *
     * @param Category $category
     * @param array $accumulatorArray
     * @return array
     */
    private function getAllIdsFromCategoryTree(Category $category, $accumulatorArray = []) {
        $accumulatorArray[] = $category->id;
        foreach($category->getChildren() as $childCategory) {
            /** @var Category $childCategory */
            $childCategoryChildren = $this->getAllIdsFromCategoryTree($childCategory);
            $accumulatorArray = array_merge($accumulatorArray, $childCategoryChildren);
        }
        return $accumulatorArray;
    }

    /**
     * Receives a category that may have children, loops over all it's children and replaces those children
     * with the same categories from the eager loaded categories. So that we have an eager loaded tree!
     *
     * @param Category $category
     * @param Collection $eagerLoadedCategories
     * @return mixed
     */
    private function remapCategoriesWithEagerLoadedOnes(Category $category, Collection &$eagerLoadedCategories) {
        $eagerLoadedCategory = $eagerLoadedCategories->get($category->id);
        $eagerLoadedCategory->setChildren($category->getChildren());
        $eagerLoadedCategories = $eagerLoadedCategories->forget($category->id);

        $remappedChildren = [];
        foreach($eagerLoadedCategory->getChildren() as $childCategory) {
            /** @var Category $childCategory */
            $remappedChildren[] = $this->remapCategoriesWithEagerLoadedOnes($childCategory, $eagerLoadedCategories);
        }
        $eagerLoadedCategory->setChildren($remappedChildren);

        return $eagerLoadedCategory;
    }

    /**
     * Gives each category a link to its wildcard route.
     * And determines if the request url matches the current categorie and thus if it is active. It stores that result in the is_current transient property.
     *
     * @param Category $category
     * @return Category
     */
    private function addLinkInformation(Category $category) {

        if(!$category->link) $category->link = WildcardResolver::getWildCardIndexRouteForPageWithCodeName('categories')->alias;
        if($category->translation && !empty($category->translation->slug)) $category->link .= '/'.$category->translation->slug;

        foreach($category->getChildren() as $childCategory) {
            $childCategory->link = $category->link;
            $this->addLinkInformation($childCategory);
        }

        return $category;
    }

    /**
     * TODO May be a candidate to put in the tree service directly
     *
     * @param TreeModelInterface $category
     * @param string $breadcrumb a/string/that/looks/like/this/and/represents/a/breadcrumb
     * @param array $stack Variable used for recursion. Not to be used by callers of this function, except this function.
     * @return array
     */
    public function breadcrumbToStack(TreeModelInterface $category, string $breadcrumb, $stack = []) {
        $parts = explode('/', $breadcrumb);
        $currentPart = array_shift($parts);

        $stack[] = $category;
        foreach ($category->getChildren() as $child)
        {
            /** @var TreeModelInterface|AbstractTranslatableModel $child */
            if($child->translation->slug == $currentPart) {
                if(count($parts) > 0) $stack = $this->breadcrumbToStack($child, implode('/', $parts), $stack);
                else $stack[] = $child;
                break;
            }
        }

        return $stack;
    }

    /**
     * TODO may be a candidate to put in the tree service directly
     *
     * @param TreeModelInterface|AbstractTranslatableModel $category
     * @param array $stack
     * @return array
     */
    public function flatten(TreeModelInterface $category, array $stack = []) {
        $stack[] = $category;
        foreach($category->getChildren() as $childCategory) {
            $stack = $this->flatten($childCategory, $stack);
        }
        return $stack;
    }
}