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/stafa.komma.pro/app/Komma/Kms/Core/Tree/TreeService.php
<?php namespace App\Komma\Kms\Core\Tree;

use App\Helpers\KommaHelpers;
use App\Komma\Kms\Core\Tree\NestedSets\Nodes\TreeModelInterface;
use App\Komma\Kms\Core\Sections\SectionService;
use App\Komma\Kms\Core\Sections\SectionServiceInterface;
use App\Komma\Sites\SiteServiceInterface;
use Closure;
use Illuminate\Database\Eloquent\Model;

/**
 *
 *
 * @author      Komma <info@komma.pro>
 * @copyright   (c) 2012-2016, Komma
 */
class TreeService
{
    /** @var SiteServiceInterface $siteService  */
    protected $siteService;

    /** @var SectionServiceInterface $sectionService */
    protected $sectionService;

    /** @var string $forModelName */
    protected $forModelName;

    public function __construct()
    {
        $this->siteService = app(SiteServiceInterface::class);
    }

    /**
     * @param SectionServiceInterface $sectionService
     */
    public function setSectionService(SectionServiceInterface $sectionService)
    {
        $this->sectionService = $sectionService;
    }

    /**
     * @param string $className
     */
    public function setForModelName(string $className)
    {
        $this->forModelName = $className;
    }

    /**
     * Return the models represented by forModelName as a TreeResource.
     * Can be converted to json for api calls
     *
     * @return TreeResource
     */
    public function getStructure() {
        $model = $this->sectionService->getRootModelForTree();
        $resource = new TreeResource($model);
        return $resource;
    }

    /**
     * @param $dataStructure
     */
    public function setStructure($dataStructure)
    {
        $this->makeArrayChildrenChildOfParent($dataStructure['children'], $dataStructure);
    }

    /**
     * Loop over a dataStructure that looks like this...
     *
     * [
     *  id = 1
     *  routes = []
     *  status = 1
     *  thumbnail = false
     *  title = 'My model'
     *  children [ dataStructure, dataStructure ...]
     * ]
     *
     * ... and re-parent every matching forModelName instance so that it matches the dataStructure
     *
     * @param array $childrenDataStructures
     * @param array $parentDataStructure
     * @return bool Return
     */
    private function makeArrayChildrenChildOfParent(array $childrenDataStructures, array $parentDataStructure)
    {
        $parentTreeModel = $this->forModelName::find($parentDataStructure['id']);
        if(!$parentTreeModel) {
            \Log::error('Could not find parent model with id "'.$parentDataStructure['id'].'" for model with class '.$this->forModelName);
            return false;
        }
        if(!is_a($parentTreeModel, TreeModelInterface::class)) throw new \RuntimeException('Can not set the children of a model that is not a '.TreeModelInterface::class.' but is a '.get_class($parentTreeModel));
        /** @var TreeModelInterface $parentTreeModel */

        foreach($childrenDataStructures as $childDataStructure)
        {
            $childTreeModel = $this->forModelName::find($childDataStructure['id']);
            if(!$childTreeModel) {
                \Log::error('Could not find child model with id "'.$childDataStructure['id'].'" for model with class '.$this->forModelName);
                continue;
            }
            if(!is_a($childTreeModel, TreeModelInterface::class)) throw new \RuntimeException('Can not set the parentTreeModel of a model that is not a '.TreeModelInterface::class.' but is a '.get_class($childTreeModel));
            /** @var TreeModelInterface $childTreeModel */

            $childTreeModel->makeLastChildOf($parentTreeModel);

            if(count($childDataStructure['children']) > 0) {
                $this->makeArrayChildrenChildOfParent($childDataStructure['children'], $childDataStructure);
            }
        }

        return true;
    }

    /**
     * Creates a root model in the database for the for model fully qualified class name if it isn't there yet.
     * But only if it implements the TreeModelInterface
     * And returns the TreeModelInterface
     *
     * @param string $FQCN
     * @param array|null $extraData Extra attributes with their values to fill in the model when the root model does not exist and has to be created
     * @param Closure|null $existsQueryClosure An optional closure that must accept a query builder instance for constraining the query to check if the root model exists
     * @return Tree|Null
     */
    public function makeRootModelForModelNameIfNeeded(string $FQCN, array $extraData = null, Closure $existsQueryClosure = null): ? TreeModelInterface
    {
        if(!class_exists($FQCN)) throw new \RuntimeException('The given FQCN is no instantiatable fully qualified class name');
        $instance = new $FQCN;
        if(!is_a($instance,Model::class)) throw new \RuntimeException('The given FQCN must resolve to a '.Model::class);
        /** @var $instance Model|TreeModelInterface */

        if(!is_a($instance, TreeModelInterface::class)) return null; //Only handle treeModelInterface instances. Ignore the rest

        $table = $instance->getTable();
        $columns = \Schema::getColumnListing($table);

        $requiredColumns = ['lft', 'rgt'];
        if(count(array_intersect($columns, $requiredColumns)) != count($requiredColumns)) throw new \RuntimeException('Make sure the table '.$table.' for model '.$FQCN.' contains the columns '.implode(', ', $requiredColumns));


        $query = $FQCN::where('lft', '=', '1');

        if($existsQueryClosure) {
            $query = $existsQueryClosure->call($this, $query);
            if(!$query) throw new \RuntimeException('The $existsQueryClosure must return the query builder it got as a parameter');
        }


        $exists = $query->count() === 1;
        if(!$exists) {
            $instance->makeRoot();

            if($extraData) {
                $instance->fill($extraData);
                $instance->save();
            }

            return $instance;
        }
        return null;
    }
}