mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2025-06-23 10:18:56 +02:00
Cache the trees structures for treeViews used in the sidebar.
This commit is contained in:
parent
9668d1084b
commit
ad69c32832
13 changed files with 653 additions and 70 deletions
|
@ -27,114 +27,94 @@ use App\Entity\Parts\Footprint;
|
||||||
use App\Entity\Parts\Manufacturer;
|
use App\Entity\Parts\Manufacturer;
|
||||||
use App\Entity\Parts\Storelocation;
|
use App\Entity\Parts\Storelocation;
|
||||||
use App\Entity\Parts\Supplier;
|
use App\Entity\Parts\Supplier;
|
||||||
|
use App\Entity\UserSystem\U2FKey;
|
||||||
|
use App\Entity\UserSystem\User;
|
||||||
use App\Services\ToolsTreeBuilder;
|
use App\Services\ToolsTreeBuilder;
|
||||||
use App\Services\TreeBuilder;
|
use App\Services\TreeBuilder;
|
||||||
|
use App\Services\Trees\TreeViewGenerator;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Component\Routing\Annotation\Route;
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This controller has the purpose to provide the data for all treeviews.
|
* This controller has the purpose to provide the data for all treeviews.
|
||||||
|
* @Route("/tree")
|
||||||
*/
|
*/
|
||||||
class TreeController extends AbstractController
|
class TreeController extends AbstractController
|
||||||
{
|
{
|
||||||
|
protected $treeGenerator;
|
||||||
|
|
||||||
|
public function __construct(TreeViewGenerator $treeGenerator)
|
||||||
|
{
|
||||||
|
$this->treeGenerator = $treeGenerator;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Route("/tree/tools", name="tree_tools")
|
* @Route("/tools", name="tree_tools")
|
||||||
*/
|
*/
|
||||||
public function tools(ToolsTreeBuilder $builder)
|
public function tools(ToolsTreeBuilder $builder)
|
||||||
{
|
{
|
||||||
$tree = $builder->getTree();
|
$tree = $builder->getTree();
|
||||||
|
|
||||||
//Ignore null values, to save data
|
//Ignore null values, to save data
|
||||||
return $this->json($tree, 200, [], ['skip_null_values' => true]);
|
return $this->json($tree, 200, [], ['skip_null_values' => true]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Route("/tree/category/{id}", name="tree_category")
|
* @Route("/category/{id}", name="tree_category")
|
||||||
* @Route("/tree/categories")
|
* @Route("/categories")
|
||||||
*/
|
*/
|
||||||
public function categoryTree(TreeBuilder $builder, Category $category = null)
|
public function categoryTree(Category $category = null)
|
||||||
{
|
{
|
||||||
if (null !== $category) {
|
$tree = $this->treeGenerator->getTreeView(Category::class, $category);
|
||||||
$tree[] = $builder->elementToTreeNode($category);
|
|
||||||
} else {
|
|
||||||
$tree = $builder->typeToTree(Category::class);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->json($tree, 200, [], ['skip_null_values' => true]);
|
return $this->json($tree, 200, [], ['skip_null_values' => true]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Route("/tree/footprint/{id}", name="tree_footprint")
|
* @Route("/footprint/{id}", name="tree_footprint")
|
||||||
* @Route("/tree/footprints")
|
* @Route("/footprints")
|
||||||
*/
|
*/
|
||||||
public function footprintTree(TreeBuilder $builder, Footprint $footprint = null)
|
public function footprintTree(Footprint $footprint = null)
|
||||||
{
|
{
|
||||||
if (null !== $footprint) {
|
$tree = $this->treeGenerator->getTreeView(Footprint::class, $footprint);
|
||||||
$tree[] = $builder->elementToTreeNode($footprint);
|
|
||||||
} else {
|
|
||||||
$tree = $builder->typeToTree(Footprint::class);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->json($tree, 200, [], ['skip_null_values' => true]);
|
return $this->json($tree, 200, [], ['skip_null_values' => true]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Route("/tree/location/{id}", name="tree_location")
|
* @Route("/location/{id}", name="tree_location")
|
||||||
* @Route("/tree/locations")
|
* @Route("/locations")
|
||||||
*/
|
*/
|
||||||
public function locationTree(TreeBuilder $builder, Storelocation $location = null)
|
public function locationTree(Storelocation $location = null)
|
||||||
{
|
{
|
||||||
if (null !== $location) {
|
$tree = $this->treeGenerator->getTreeView(Storelocation::class, $location);
|
||||||
$tree[] = $builder->elementToTreeNode($location);
|
|
||||||
} else {
|
|
||||||
$tree = $builder->typeToTree(Storelocation::class);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->json($tree, 200, [], ['skip_null_values' => true]);
|
return $this->json($tree, 200, [], ['skip_null_values' => true]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Route("/tree/manufacturer/{id}", name="tree_manufacturer")
|
* @Route("/manufacturer/{id}", name="tree_manufacturer")
|
||||||
* @Route("/tree/manufacturers")
|
* @Route("/manufacturers")
|
||||||
*/
|
*/
|
||||||
public function manufacturerTree(TreeBuilder $builder, Manufacturer $manufacturer = null)
|
public function manufacturerTree(Manufacturer $manufacturer = null)
|
||||||
{
|
{
|
||||||
if (null !== $manufacturer) {
|
$tree = $this->treeGenerator->getTreeView(Manufacturer::class, $manufacturer);
|
||||||
$tree[] = $builder->elementToTreeNode($manufacturer);
|
|
||||||
} else {
|
|
||||||
$tree = $builder->typeToTree(Manufacturer::class);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->json($tree, 200, [], ['skip_null_values' => true]);
|
return $this->json($tree, 200, [], ['skip_null_values' => true]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Route("/tree/supplier/{id}", name="tree_supplier")
|
* @Route("/supplier/{id}", name="tree_supplier")
|
||||||
* @Route("/tree/suppliers")
|
* @Route("/suppliers")
|
||||||
*/
|
*/
|
||||||
public function supplierTree(TreeBuilder $builder, Supplier $supplier = null)
|
public function supplierTree(Supplier $supplier = null)
|
||||||
{
|
{
|
||||||
if (null !== $supplier) {
|
$tree = $this->treeGenerator->getTreeView(Supplier::class, $supplier);
|
||||||
$tree[] = $builder->elementToTreeNode($supplier);
|
|
||||||
} else {
|
|
||||||
$tree = $builder->typeToTree(Supplier::class);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->json($tree, 200, [], ['skip_null_values' => true]);
|
return $this->json($tree, 200, [], ['skip_null_values' => true]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Route("/tree/device/{id}", name="tree_device")
|
* @Route("/device/{id}", name="tree_device")
|
||||||
* @Route("/tree/devices")
|
* @Route("/devices")
|
||||||
*/
|
*/
|
||||||
public function deviceTree(TreeBuilder $builder, Device $device = null)
|
public function deviceTree(Device $device = null)
|
||||||
{
|
{
|
||||||
if (null !== $device) {
|
$tree = $this->treeGenerator->getTreeView(Device::class, $device, '');
|
||||||
$tree[] = $builder->elementToTreeNode($device);
|
|
||||||
} else {
|
|
||||||
$tree = $builder->typeToTree(Device::class, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->json($tree, 200, [], ['skip_null_values' => true]);
|
return $this->json($tree, 200, [], ['skip_null_values' => true]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ use Symfony\Component\Validator\Constraints as Assert;
|
||||||
/**
|
/**
|
||||||
* All subclasses of this class have an attribute "name".
|
* All subclasses of this class have an attribute "name".
|
||||||
*
|
*
|
||||||
* @ORM\MappedSuperclass()
|
* @ORM\MappedSuperclass(repositoryClass="App\Repository\UserRepository")
|
||||||
* @ORM\HasLifecycleCallbacks()
|
* @ORM\HasLifecycleCallbacks()
|
||||||
*/
|
*/
|
||||||
abstract class NamedDBElement extends DBElement
|
abstract class NamedDBElement extends DBElement
|
||||||
|
|
|
@ -26,6 +26,7 @@ namespace App\Entity\Base;
|
||||||
use App\Entity\Attachments\AttachmentContainingDBElement;
|
use App\Entity\Attachments\AttachmentContainingDBElement;
|
||||||
use App\Validator\Constraints\NoneOfItsChildren;
|
use App\Validator\Constraints\NoneOfItsChildren;
|
||||||
use Doctrine\Common\Collections\ArrayCollection;
|
use Doctrine\Common\Collections\ArrayCollection;
|
||||||
|
use Doctrine\Common\Collections\Collection;
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||||
use Symfony\Component\Serializer\Annotation\Groups;
|
use Symfony\Component\Serializer\Annotation\Groups;
|
||||||
|
@ -244,13 +245,16 @@ abstract class StructuralDBElement extends AttachmentContainingDBElement
|
||||||
*
|
*
|
||||||
* @param bool $recursive if true, the search is recursive
|
* @param bool $recursive if true, the search is recursive
|
||||||
*
|
*
|
||||||
* @return static[] all subelements as an array of objects (sorted by their full path)
|
* @return Collection<static> all subelements as an array of objects (sorted by their full path)
|
||||||
*/
|
*/
|
||||||
public function getSubelements(): iterable
|
public function getSubelements(): iterable
|
||||||
{
|
{
|
||||||
return $this->children;
|
return $this->children;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Collection<static>
|
||||||
|
*/
|
||||||
public function getChildren(): iterable
|
public function getChildren(): iterable
|
||||||
{
|
{
|
||||||
return $this->children;
|
return $this->children;
|
||||||
|
|
|
@ -21,6 +21,10 @@
|
||||||
|
|
||||||
namespace App\Helpers;
|
namespace App\Helpers;
|
||||||
|
|
||||||
|
use App\Entity\Base\DBElement;
|
||||||
|
use App\Entity\Base\NamedDBElement;
|
||||||
|
use App\Entity\Base\StructuralDBElement;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class represents a node for the bootstrap treeview node.
|
* This class represents a node for the bootstrap treeview node.
|
||||||
* When you serialize an array of these objects to JSON, you can use the serialized data in data for the treeview.
|
* When you serialize an array of these objects to JSON, you can use the serialized data in data for the treeview.
|
||||||
|
@ -35,6 +39,8 @@ class TreeViewNode
|
||||||
|
|
||||||
protected $tags;
|
protected $tags;
|
||||||
|
|
||||||
|
protected $id;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new TreeView node with the given parameters.
|
* Creates a new TreeView node with the given parameters.
|
||||||
*
|
*
|
||||||
|
@ -53,6 +59,28 @@ class TreeViewNode
|
||||||
//$this->state = new TreeViewNodeState();
|
//$this->state = new TreeViewNodeState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the ID of the entity associated with this node.
|
||||||
|
* Null if this node is not connected with an entity.
|
||||||
|
* @return int|null
|
||||||
|
*/
|
||||||
|
public function getId() : ?int
|
||||||
|
{
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the ID of the entity associated with this node.
|
||||||
|
* Null if this node is not connected with an entity.
|
||||||
|
* @param int|null $id
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setId(?int $id): self
|
||||||
|
{
|
||||||
|
$this->id = $id;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the node text.
|
* Returns the node text.
|
||||||
*
|
*
|
||||||
|
@ -104,7 +132,7 @@ class TreeViewNode
|
||||||
/**
|
/**
|
||||||
* Returns the children nodes of this node.
|
* Returns the children nodes of this node.
|
||||||
*
|
*
|
||||||
* @return array|null
|
* @return TreeViewNode[]|null
|
||||||
*/
|
*/
|
||||||
public function getNodes(): ?array
|
public function getNodes(): ?array
|
||||||
{
|
{
|
||||||
|
|
58
src/Helpers/Trees/StructuralDBElementIterator.php
Normal file
58
src/Helpers/Trees/StructuralDBElementIterator.php
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 Jan Böhmer (https://github.com/jbtronics)
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Helpers\Trees;
|
||||||
|
|
||||||
|
|
||||||
|
use App\Entity\Base\StructuralDBElement;
|
||||||
|
use Doctrine\Common\Collections\Collection;
|
||||||
|
use RecursiveIterator;
|
||||||
|
|
||||||
|
class StructuralDBElementIterator extends \ArrayIterator implements \RecursiveIterator
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param $nodes Collection<StructuralDBElement>|StructuralDBElement[]
|
||||||
|
*/
|
||||||
|
public function __construct($nodes)
|
||||||
|
{
|
||||||
|
parent::__construct($nodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function hasChildren()
|
||||||
|
{
|
||||||
|
/** @var StructuralDBElement $element */
|
||||||
|
$element = $this->current();
|
||||||
|
return !empty($element->getSubelements());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function getChildren()
|
||||||
|
{
|
||||||
|
/** @var StructuralDBElement $element */
|
||||||
|
$element = $this->current();
|
||||||
|
return new StructuralDBElementIterator($element->getSubelements()->toArray());
|
||||||
|
}
|
||||||
|
}
|
56
src/Helpers/Trees/TreeViewNodeIterator.php
Normal file
56
src/Helpers/Trees/TreeViewNodeIterator.php
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 Jan Böhmer (https://github.com/jbtronics)
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Helpers\Trees;
|
||||||
|
|
||||||
|
use App\Helpers\TreeViewNode;
|
||||||
|
|
||||||
|
class TreeViewNodeIterator extends \ArrayIterator implements \RecursiveIterator
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $nodes TreeViewNode[]
|
||||||
|
*/
|
||||||
|
public function __construct($nodes)
|
||||||
|
{
|
||||||
|
parent::__construct($nodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function hasChildren()
|
||||||
|
{
|
||||||
|
/** @var TreeViewNode $element */
|
||||||
|
$element = $this->current();
|
||||||
|
return !empty($element->getNodes());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function getChildren()
|
||||||
|
{
|
||||||
|
/** @var TreeViewNode $element */
|
||||||
|
$element = $this->current();
|
||||||
|
return new TreeViewNodeIterator($element->getNodes());
|
||||||
|
}
|
||||||
|
}
|
53
src/Repository/NamedDBElementRepository.php
Normal file
53
src/Repository/NamedDBElementRepository.php
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 Jan Böhmer (https://github.com/jbtronics)
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Repository;
|
||||||
|
|
||||||
|
|
||||||
|
use App\Entity\Base\NamedDBElement;
|
||||||
|
use App\Entity\Base\StructuralDBElement;
|
||||||
|
use App\Helpers\TreeViewNode;
|
||||||
|
use Doctrine\ORM\EntityRepository;
|
||||||
|
use Doctrine\ORM\Mapping\Entity;
|
||||||
|
|
||||||
|
|
||||||
|
class NamedDBElementRepository extends EntityRepository
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Gets a tree of TreeViewNode elements. The root elements has $parent as parent.
|
||||||
|
* The treeview is generic, that means the href are null and ID values are set.
|
||||||
|
* @return TreeViewNode[]
|
||||||
|
*/
|
||||||
|
public function getGenericNodeTree() : array
|
||||||
|
{
|
||||||
|
$result = [];
|
||||||
|
|
||||||
|
$entities = $this->findAll();
|
||||||
|
foreach ($entities as $entity) {
|
||||||
|
/** @var $entity NamedDBElement */
|
||||||
|
$node = new TreeViewNode($entity->getName(), null, null);
|
||||||
|
$node->setId($entity->getID());
|
||||||
|
$result[] = $node;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,9 +22,12 @@
|
||||||
namespace App\Repository;
|
namespace App\Repository;
|
||||||
|
|
||||||
use App\Entity\Base\StructuralDBElement;
|
use App\Entity\Base\StructuralDBElement;
|
||||||
|
use App\Helpers\Trees\StructuralDBElementIterator;
|
||||||
|
use App\Helpers\TreeViewNode;
|
||||||
use Doctrine\ORM\EntityRepository;
|
use Doctrine\ORM\EntityRepository;
|
||||||
|
use Symfony\Component\Stopwatch\Stopwatch;
|
||||||
|
|
||||||
class StructuralDBElementRepository extends EntityRepository
|
class StructuralDBElementRepository extends NamedDBElementRepository
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Finds all nodes without a parent node. They are our root nodes.
|
* Finds all nodes without a parent node. They are our root nodes.
|
||||||
|
@ -36,6 +39,31 @@ class StructuralDBElementRepository extends EntityRepository
|
||||||
return $this->findBy(['parent' => null], ['name' => 'ASC']);
|
return $this->findBy(['parent' => null], ['name' => 'ASC']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a tree of TreeViewNode elements. The root elements has $parent as parent.
|
||||||
|
* The treeview is generic, that means the href are null and ID values are set.
|
||||||
|
* @param StructuralDBElement|null $parent The parent the root elements should have.
|
||||||
|
* @return TreeViewNode[]
|
||||||
|
*/
|
||||||
|
public function getGenericNodeTree(?StructuralDBElement $parent = null) : array
|
||||||
|
{
|
||||||
|
$result = [];
|
||||||
|
|
||||||
|
$entities = $this->findBy(['parent' => $parent], ['name' => 'ASC']);
|
||||||
|
foreach ($entities as $entity) {
|
||||||
|
/** @var StructuralDBElement $entity */
|
||||||
|
//Make a recursive call to find all children nodes
|
||||||
|
$children = $this->getGenericNodeTree($entity);
|
||||||
|
$node = new TreeViewNode($entity->getName(), null, $children);
|
||||||
|
//Set the ID of this entity to later be able to reconstruct the URL
|
||||||
|
$node->setId($entity->getID());
|
||||||
|
$result[] = $node;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a flattened hierarchical tree. Useful for generating option lists.
|
* Gets a flattened hierarchical tree. Useful for generating option lists.
|
||||||
*
|
*
|
||||||
|
@ -49,16 +77,13 @@ class StructuralDBElementRepository extends EntityRepository
|
||||||
|
|
||||||
$entities = $this->findBy(['parent' => $parent], ['name' => 'ASC']);
|
$entities = $this->findBy(['parent' => $parent], ['name' => 'ASC']);
|
||||||
|
|
||||||
/*
|
$elementIterator = new StructuralDBElementIterator($entities);
|
||||||
* I think it is very difficult to replace this recursive array_merge,
|
$recursiveIterator = new \RecursiveIteratorIterator($elementIterator, \RecursiveIteratorIterator::SELF_FIRST);
|
||||||
* so if you want to change it you should have a better idea than adding each list to $result array
|
//$result = iterator_to_array($recursiveIterator);
|
||||||
* and do an array_merge(...$result) at the end.
|
|
||||||
*/
|
|
||||||
|
|
||||||
foreach ($entities as $entity) {
|
//We can not use iterator_to_array here or we get only the parent elements
|
||||||
/* @var StructuralDBElement $entity */
|
foreach($recursiveIterator as $item) {
|
||||||
$result[] = $entity;
|
$result[] = $item;
|
||||||
$result = array_merge($result, $this->toNodesList($entity));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
|
|
|
@ -37,7 +37,7 @@ use Symfony\Component\Security\Core\User\UserInterface;
|
||||||
* @method User[] findAll()
|
* @method User[] findAll()
|
||||||
* @method User[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
* @method User[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||||
*/
|
*/
|
||||||
class UserRepository extends EntityRepository implements PasswordUpgraderInterface
|
class UserRepository extends NamedDBElementRepository implements PasswordUpgraderInterface
|
||||||
{
|
{
|
||||||
protected $anonymous_user;
|
protected $anonymous_user;
|
||||||
|
|
||||||
|
|
114
src/Services/Trees/TreeViewGenerator.php
Normal file
114
src/Services/Trees/TreeViewGenerator.php
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 Jan Böhmer (https://github.com/jbtronics)
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Services\Trees;
|
||||||
|
|
||||||
|
|
||||||
|
use App\Entity\Base\DBElement;
|
||||||
|
use App\Entity\Base\StructuralDBElement;
|
||||||
|
use App\Helpers\Trees\TreeViewNodeIterator;
|
||||||
|
use App\Helpers\TreeViewNode;
|
||||||
|
use App\Repository\StructuralDBElementRepository;
|
||||||
|
use App\Services\EntityURLGenerator;
|
||||||
|
use App\Services\UserCacheKeyGenerator;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Symfony\Contracts\Cache\ItemInterface;
|
||||||
|
use Symfony\Contracts\Cache\TagAwareCacheInterface;
|
||||||
|
|
||||||
|
class TreeViewGenerator
|
||||||
|
{
|
||||||
|
|
||||||
|
protected $urlGenerator;
|
||||||
|
protected $em;
|
||||||
|
protected $cache;
|
||||||
|
protected $keyGenerator;
|
||||||
|
|
||||||
|
public function __construct(EntityURLGenerator $URLGenerator, EntityManagerInterface $em,
|
||||||
|
TagAwareCacheInterface $treeCache, UserCacheKeyGenerator $keyGenerator)
|
||||||
|
{
|
||||||
|
$this->urlGenerator = $URLGenerator;
|
||||||
|
$this->em = $em;
|
||||||
|
$this->cache = $treeCache;
|
||||||
|
$this->keyGenerator = $keyGenerator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTreeView(string $class, ?StructuralDBElement $parent = null, string $href_type = 'list_parts', DBElement $selectedElement = null)
|
||||||
|
{
|
||||||
|
$generic = $this->getGenericTree($class, $parent);
|
||||||
|
$treeIterator = new TreeViewNodeIterator($generic);
|
||||||
|
$recursiveIterator = new \RecursiveIteratorIterator($treeIterator);
|
||||||
|
foreach ($recursiveIterator as $item) {
|
||||||
|
/** @var $item TreeViewNode */
|
||||||
|
if ($selectedElement !== null && $item->getId() === $selectedElement->getID()) {
|
||||||
|
$item->setSelected(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($item->getNodes())) {
|
||||||
|
$item->addTag((string) \count($item->getNodes()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($href_type)) {
|
||||||
|
$entity = $this->em->getPartialReference($class, $item->getId());
|
||||||
|
$item->setHref($this->urlGenerator->getURL($entity, $href_type));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $generic;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* /**
|
||||||
|
* Gets a tree of TreeViewNode elements. The root elements has $parent as parent.
|
||||||
|
* The treeview is generic, that means the href are null and ID values are set.
|
||||||
|
*
|
||||||
|
* @param string $class The class for which the tree should be generated
|
||||||
|
* @param StructuralDBElement|null $parent The parent the root elements should have.
|
||||||
|
* @return TreeViewNode[]
|
||||||
|
*/
|
||||||
|
public function getGenericTree(string $class, ?StructuralDBElement $parent = null) : array
|
||||||
|
{
|
||||||
|
if(!is_a($class, StructuralDBElement::class, true)) {
|
||||||
|
throw new \InvalidArgumentException('$class must be a class string that implements StructuralDBElement!');
|
||||||
|
}
|
||||||
|
if($parent !== null && !is_a($parent, $class)) {
|
||||||
|
throw new \InvalidArgumentException('$parent must be of the type class!');
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var StructuralDBElementRepository $repo */
|
||||||
|
$repo = $this->em->getRepository($class);
|
||||||
|
|
||||||
|
//If we just want a part of a tree, dont cache it
|
||||||
|
if ($parent !== null) {
|
||||||
|
return $repo->getGenericNodeTree($parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
$secure_class_name = str_replace('\\', '_', $class);
|
||||||
|
$key = 'treeview_'.$this->keyGenerator->generateKey().'_'.$secure_class_name;
|
||||||
|
|
||||||
|
$ret = $this->cache->get($key, function (ItemInterface $item) use ($repo, $parent, $secure_class_name) {
|
||||||
|
// Invalidate when groups, a element with the class or the user changes
|
||||||
|
$item->tag(['groups', 'tree_treeview', $this->keyGenerator->generateKey(), $secure_class_name]);
|
||||||
|
return $repo->getGenericNodeTree($parent);
|
||||||
|
});
|
||||||
|
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
}
|
66
tests/Repository/NamedDBElementRepositoryTest.php
Normal file
66
tests/Repository/NamedDBElementRepositoryTest.php
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 Jan Böhmer (https://github.com/jbtronics)
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Tests\Repository;
|
||||||
|
|
||||||
|
use App\Entity\Attachments\AttachmentType;
|
||||||
|
use App\Entity\UserSystem\User;
|
||||||
|
use App\Helpers\TreeViewNode;
|
||||||
|
use App\Repository\NamedDBElementRepository;
|
||||||
|
use App\Repository\StructuralDBElementRepository;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Group DB
|
||||||
|
*/
|
||||||
|
class NamedDBElementRepositoryTest extends WebTestCase
|
||||||
|
{
|
||||||
|
|
||||||
|
private $entityManager;
|
||||||
|
/** @var StructuralDBElementRepository */
|
||||||
|
private $repo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
protected function setUp() : void
|
||||||
|
{
|
||||||
|
$kernel = self::bootKernel();
|
||||||
|
|
||||||
|
$this->entityManager = $kernel->getContainer()
|
||||||
|
->get('doctrine')
|
||||||
|
->getManager();
|
||||||
|
|
||||||
|
$this->repo = $this->entityManager->getRepository(User::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetGenericNodeTree()
|
||||||
|
{
|
||||||
|
$tree = $this->repo->getGenericNodeTree();
|
||||||
|
|
||||||
|
$this->assertIsArray($tree);
|
||||||
|
$this->assertContainsOnlyInstancesOf(TreeViewNode::class, $tree);
|
||||||
|
$this->assertCount(4, $tree);
|
||||||
|
$this->assertEquals('anonymous', $tree[0]->getText());
|
||||||
|
$this->assertEmpty($tree[0]->getNodes());
|
||||||
|
}
|
||||||
|
}
|
123
tests/Repository/StructuralDBElementRepositoryTest.php
Normal file
123
tests/Repository/StructuralDBElementRepositoryTest.php
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 Jan Böhmer (https://github.com/jbtronics)
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Tests\Repository;
|
||||||
|
|
||||||
|
use App\Entity\Attachments\AttachmentType;
|
||||||
|
use App\Helpers\TreeViewNode;
|
||||||
|
use App\Repository\StructuralDBElementRepository;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Group DB
|
||||||
|
*/
|
||||||
|
class StructuralDBElementRepositoryTest extends WebTestCase
|
||||||
|
{
|
||||||
|
|
||||||
|
private $entityManager;
|
||||||
|
/** @var StructuralDBElementRepository */
|
||||||
|
private $repo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
protected function setUp() : void
|
||||||
|
{
|
||||||
|
$kernel = self::bootKernel();
|
||||||
|
|
||||||
|
$this->entityManager = $kernel->getContainer()
|
||||||
|
->get('doctrine')
|
||||||
|
->getManager();
|
||||||
|
|
||||||
|
$this->repo = $this->entityManager->getRepository(AttachmentType::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFindRootNodes() : void
|
||||||
|
{
|
||||||
|
$root_nodes = $this->repo->findRootNodes();
|
||||||
|
$this->assertCount(3, $root_nodes);
|
||||||
|
$this->assertContainsOnlyInstancesOf(AttachmentType::class, $root_nodes);
|
||||||
|
|
||||||
|
//Asc sorting
|
||||||
|
$this->assertEquals('Node 1', $root_nodes[0]->getName());
|
||||||
|
$this->assertEquals('Node 2', $root_nodes[1]->getName());
|
||||||
|
$this->assertEquals('Node 3', $root_nodes[2]->getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetGenericTree() : void
|
||||||
|
{
|
||||||
|
$tree = $this->repo->getGenericNodeTree();
|
||||||
|
$this->assertIsArray($tree);
|
||||||
|
$this->assertContainsOnlyInstancesOf(TreeViewNode::class, $tree);
|
||||||
|
|
||||||
|
$this->assertCount(3, $tree);
|
||||||
|
$this->assertCount(2, $tree[0]->getNodes());
|
||||||
|
$this->assertCount(1, $tree[0]->getNodes()[0]->getNodes());
|
||||||
|
$this->assertEmpty($tree[2]->getNodes());
|
||||||
|
$this->assertEmpty($tree[1]->getNodes()[0]->getNodes());
|
||||||
|
|
||||||
|
//Check text
|
||||||
|
$this->assertEquals('Node 1', $tree[0]->getText());
|
||||||
|
$this->assertEquals('Node 2', $tree[1]->getText());
|
||||||
|
$this->assertEquals('Node 3', $tree[2]->getText());
|
||||||
|
$this->assertEquals('Node 1.1', $tree[0]->getNodes()[0]->getText());
|
||||||
|
$this->assertEquals('Node 1.1.1', $tree[0]->getNodes()[0]->getNodes()[0]->getText());
|
||||||
|
|
||||||
|
//Check that IDs were set correctly
|
||||||
|
$this->assertEquals(1, $tree[0]->getId());
|
||||||
|
$this->assertEquals(2, $tree[1]->getId());
|
||||||
|
$this->assertEquals(7, $tree[0]->getNodes()[0]->getNodes()[0]->getId());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test $repo->toNodesList() for null as parameter
|
||||||
|
*/
|
||||||
|
public function testToNodesListRoot() : void
|
||||||
|
{
|
||||||
|
//List all root nodes and their children
|
||||||
|
$nodes = $this->repo->toNodesList();
|
||||||
|
|
||||||
|
$this->assertCount(7, $nodes);
|
||||||
|
$this->assertContainsOnlyInstancesOf(AttachmentType::class, $nodes);
|
||||||
|
$this->assertEquals('Node 1', $nodes[0]->getName());
|
||||||
|
$this->assertEquals('Node 1.1', $nodes[1]->getName());
|
||||||
|
$this->assertEquals('Node 1.1.1', $nodes[2]->getName());
|
||||||
|
$this->assertEquals('Node 1.2', $nodes[3]->getName());
|
||||||
|
$this->assertEquals('Node 2', $nodes[4]->getName());
|
||||||
|
$this->assertEquals('Node 2.1', $nodes[5]->getName());
|
||||||
|
$this->assertEquals('Node 3', $nodes[6]->getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testToNodesListElement() : void
|
||||||
|
{
|
||||||
|
//List all nodes that are children to Node 1
|
||||||
|
$node1 = $this->repo->find(1);
|
||||||
|
$nodes = $this->repo->toNodesList($node1);
|
||||||
|
|
||||||
|
$this->assertCount(3, $nodes);
|
||||||
|
$this->assertContainsOnlyInstancesOf(AttachmentType::class, $nodes);
|
||||||
|
$this->assertEquals('Node 1.1', $nodes[0]->getName());
|
||||||
|
$this->assertEquals('Node 1.1.1', $nodes[1]->getName());
|
||||||
|
$this->assertEquals('Node 1.2', $nodes[2]->getName());
|
||||||
|
}
|
||||||
|
}
|
76
tests/Services/Trees/TreeGeneratorTest.php
Normal file
76
tests/Services/Trees/TreeGeneratorTest.php
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 Jan Böhmer (https://github.com/jbtronics)
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Tests\Services\Trees;
|
||||||
|
|
||||||
|
use App\Entity\Attachments\AttachmentType;
|
||||||
|
use App\Helpers\TreeViewNode;
|
||||||
|
use App\Services\AmountFormatter;
|
||||||
|
use App\Services\Trees\TreeViewGenerator;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group DB
|
||||||
|
*/
|
||||||
|
class TreeGeneratorTest extends WebTestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var TreeViewGenerator
|
||||||
|
*/
|
||||||
|
protected $service;
|
||||||
|
|
||||||
|
public function setUp() : void
|
||||||
|
{
|
||||||
|
parent::setUp(); // TODO: Change the autogenerated stub
|
||||||
|
|
||||||
|
//Get an service instance.
|
||||||
|
self::bootKernel();
|
||||||
|
$this->service = self::$container->get(TreeViewGenerator::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetGenericTree()
|
||||||
|
{
|
||||||
|
$tree = $this->service->getGenericTree(AttachmentType::class, null);
|
||||||
|
|
||||||
|
$this->assertIsArray($tree);
|
||||||
|
$this->assertContainsOnlyInstancesOf(TreeViewNode::class, $tree);
|
||||||
|
|
||||||
|
$this->assertCount(3, $tree);
|
||||||
|
$this->assertCount(2, $tree[0]->getNodes());
|
||||||
|
$this->assertCount(1, $tree[0]->getNodes()[0]->getNodes());
|
||||||
|
$this->assertEmpty($tree[2]->getNodes());
|
||||||
|
$this->assertEmpty($tree[1]->getNodes()[0]->getNodes());
|
||||||
|
|
||||||
|
//Check text
|
||||||
|
$this->assertEquals('Node 1', $tree[0]->getText());
|
||||||
|
$this->assertEquals('Node 2', $tree[1]->getText());
|
||||||
|
$this->assertEquals('Node 3', $tree[2]->getText());
|
||||||
|
$this->assertEquals('Node 1.1', $tree[0]->getNodes()[0]->getText());
|
||||||
|
$this->assertEquals('Node 1.1.1', $tree[0]->getNodes()[0]->getNodes()[0]->getText());
|
||||||
|
|
||||||
|
//Check that IDs were set correctly
|
||||||
|
$this->assertEquals(1, $tree[0]->getId());
|
||||||
|
$this->assertEquals(2, $tree[1]->getId());
|
||||||
|
$this->assertEquals(7, $tree[0]->getNodes()[0]->getNodes()[0]->getId());
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue