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;
}
}