diff --git a/assets/js/app.js b/assets/js/app.js index 0d113850..6ad44053 100644 --- a/assets/js/app.js +++ b/assets/js/app.js @@ -23,6 +23,8 @@ import 'datatables.net-select-bs4/css/select.bootstrap4.css' import 'bootstrap-select/dist/css/bootstrap-select.css' import 'awesome-bootstrap-checkbox/awesome-bootstrap-checkbox.css' +import "bootstrap-treeview/src/css/bootstrap-treeview.css" + //require( 'jszip' ); //#require( 'pdfmake' ); require( 'datatables.net-bs4' ); @@ -33,10 +35,13 @@ require( 'datatables.net-buttons/js/buttons.print.js' ); //require( 'datatables.net-colreorder-bs4' )(); require( 'datatables.net-fixedheader-bs4' ); require( 'datatables.net-select-bs4' ); -require('bootstrap-select') +require('bootstrap-select'); +//require('bootstrap-treeview/src/js/bootstrap-treeview'); //Define jquery globally window.$ = window.jQuery = require("jquery"); -//console.log('Hello Webpack Encore! Edit me in assets/js/app.js'); +require('bootstrap-treeview/src/js/bootstrap-treeview'); + +//console.log('Hello Webpack Encore! Edit me in assets/js/app.js'); \ No newline at end of file diff --git a/package.json b/package.json index 5b4b84c9..e61ff559 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "@ckeditor/ckeditor5-build-classic": "^12.0.0", "awesome-bootstrap-checkbox": "^1.0.1", "bootstrap-select": "^1.13.8", + "bootstrap-treeview": "jbtronics/bootstrap-treeview", "datatables.net-bs4": "^1.10.19", "datatables.net-buttons-bs4": "^1.5.4", "datatables.net-fixedheader-bs4": "^3.1.5", diff --git a/src/Controller/TreeBuilder.php b/src/Controller/TreeBuilder.php new file mode 100644 index 00000000..2545c429 --- /dev/null +++ b/src/Controller/TreeBuilder.php @@ -0,0 +1,104 @@ +url_generator = $URLGenerator; + $this->em = $em; + } + + /** + * Generates a tree for the given Element. The given element is the top node, all children are child nodes. + * @param StructuralDBElement $element The element for which the tree should be generated. + * @param string $href_type The type of the links that should be used for the links. Set to null, to disable links. + * See EntityURLGenerator::getURL for possible types. + * @return TreeViewNode The Node for the given Element. + */ + public function elementToTreeNode(StructuralDBElement $element, string $href_type = 'list_parts') : TreeViewNode + { + $children = $element->getSubelements(); + + $children_nodes = null; + foreach ($children as $child) { + $children_nodes[] = $this->elementToTreeNode($child); + } + + //Check if we need to generate a href type + $href = null; + + if (!empty($href_type)) { + $href = $this->url_generator->getURL($element, $href_type); + } + + return new TreeViewNode($element->getName(), $href, $children_nodes); + } + + /** + * Generates a tree for all elements of the given type + * @param StructuralDBElement $class_name The class name of the StructuralDBElement class for which the tree should + * be generated. + * @param string $href_type The type of the links that should be used for the links. Set to null, to disable links. + * See EntityURLGenerator::getURL for possible types. + * @return TreeViewNode[] Returns an array, containing all nodes. It is empty if the given class has no elements. + */ + public function typeToTree(StructuralDBElement $class_name, string $href_type = 'list_parts') : array + { + /** + * @var $repo StructuralDBElementRepository + */ + $repo = $this->em->getRepository($class_name); + $root_nodes = $repo->findRootNodes(); + + $array = array(); + foreach ($root_nodes as $node) { + $array = $this->elementToTreeNode($node, $href_type); + } + + return $array; + } +} diff --git a/src/Controller/TreeController.php b/src/Controller/TreeController.php new file mode 100644 index 00000000..10898734 --- /dev/null +++ b/src/Controller/TreeController.php @@ -0,0 +1,74 @@ +getTree(); + + //Ignore null values, to save data + return $this->json($tree, 200, [], ['skip_null_values' => true]); + } + + /** + * @Route("/tree/category/{id}", name="tree_category") + */ + public function categoryTree(TreeBuilder $builder, Category $category = null) + { + if($category != null) { + $tree[] = $builder->elementToTreeNode($category); + } else { + $tree = $builder->typeToTree(Category::class); + } + + + return $this->json($tree, 200, [], ['skip_null_values' => true]); + } + + + + +} diff --git a/src/Entity/StructuralDBElement.php b/src/Entity/StructuralDBElement.php index b10e6946..8390e69d 100644 --- a/src/Entity/StructuralDBElement.php +++ b/src/Entity/StructuralDBElement.php @@ -37,6 +37,7 @@ use Doctrine\ORM\PersistentCollection; * an attribute of a root element, you will get an exception! * * @ORM\MappedSuperclass() + * //@ORM\Entity(repositoryClass="App\Repository\StructuralDBElementRepository") */ abstract class StructuralDBElement extends AttachmentContainingDBElement { @@ -207,23 +208,9 @@ abstract class StructuralDBElement extends AttachmentContainingDBElement * * @return static[] all subelements as an array of objects (sorted by their full path) */ - public function getSubelements(bool $recursive): PersistentCollection + public function getSubelements(): PersistentCollection { - if (null == $this->children) { - $this->children = new ArrayCollection(); - } - - if (!$recursive) { - return $this->children; - } - - $all_elements = array(); - foreach ($this->children as $subelement) { - $all_elements[] = $subelement; - $all_elements = array_merge($all_elements, $subelement->getSubelements(true)); - } - - return $all_elements; + return $this->children; } /****************************************************************************** diff --git a/src/Helpers/TreeViewNode.php b/src/Helpers/TreeViewNode.php new file mode 100644 index 00000000..ac282680 --- /dev/null +++ b/src/Helpers/TreeViewNode.php @@ -0,0 +1,118 @@ +text = $text; + $this->href = $href; + $this->nodes = $nodes; + } + + /** + * Returns the node text. + * @return string + */ + public function getText(): string + { + return $this->text; + } + + /** + * Sets the node text + * @param string $text The new node text. + * @return TreeViewNode + */ + public function setText(string $text): self + { + $this->text = $text; + return $this; + } + + /** + * Returns the href link. + * @return string|null + */ + public function getHref(): ?string + { + return $this->href; + } + + /** + * Sets the href link. + * @param string|null $href The new href link. + * @return TreeViewNode + */ + public function setHref(?string $href): self + { + $this->href = $href; + return $this; + } + + /** + * Returns the children nodes of this node. + * @return array|null + */ + public function getNodes(): ?array + { + return $this->nodes; + } + + /** + * Sets the children nodes. + * @param array|null $nodes The new children nodes + * @return TreeViewNode + */ + public function setNodes(?array $nodes): self + { + $this->nodes = $nodes; + return $this; + } + +} diff --git a/src/Repository/StructuralDBElementRepository.php b/src/Repository/StructuralDBElementRepository.php new file mode 100644 index 00000000..9f952888 --- /dev/null +++ b/src/Repository/StructuralDBElementRepository.php @@ -0,0 +1,52 @@ +findBy(['parent' => null]); + } + +} \ No newline at end of file diff --git a/src/Services/EntityURLGenerator.php b/src/Services/EntityURLGenerator.php index c309ea9f..c94a2c91 100644 --- a/src/Services/EntityURLGenerator.php +++ b/src/Services/EntityURLGenerator.php @@ -29,6 +29,7 @@ namespace App\Services; +use App\Entity\Category; use App\Entity\NamedDBElement; use App\Entity\Part; use App\Exceptions\EntityNotSupported; @@ -46,13 +47,41 @@ class EntityURLGenerator $this->urlGenerator = $urlGenerator; } + /** + * Generates an URL to the page using the given page type and element. + * For the given types, the [type]URL() functions are called (e.g. infoURL()). + * Not all entity class and $type combinations are supported. + * + * @param $entity mixed The element for which the page should be generated. + * @param string $type The page type. Currently supported: 'info', 'edit', 'create', 'clone', 'list'/'list_parts' + * @return string The link to the desired page. + * @throws EntityNotSupported Thrown if the entity is not supported for the given type. + * @throws \InvalidArgumentException Thrown if the givent type is not existing. + */ + public function getURL($entity, string $type) + { + switch ($type) { + case 'info': + return $this->infoURL($entity); + case 'edit': + return $this->editURL($entity); + case 'create': + return $this->createURL($entity); + case 'clone': + return $this->cloneURL($entity); + case 'list': + case 'list_parts': + return $this->listPartsURL($entity); + } + + throw new \InvalidArgumentException('Method is not supported!'); + } + /** * Generates an URL to a page, where info about this entity can be viewed. * * @param $entity mixed The entity for which the info should be generated. - * * @return string The URL to the info page - * * @throws EntityNotSupported If the method is not supported for the given Entity */ public function infoURL($entity): string @@ -65,6 +94,13 @@ class EntityURLGenerator throw new EntityNotSupported('The given entity is not supported yet!'); } + /** + * Generates an URL to a page, where this entity can be edited. + * + * @param $entity mixed The entity for which the edit link should be generated. + * @return string The URL to the edit page. + * @throws EntityNotSupported If the method is not supported for the given Entity + */ public function editURL($entity): string { if ($entity instanceof Part) { @@ -75,6 +111,13 @@ class EntityURLGenerator throw new EntityNotSupported('The given entity is not supported yet!'); } + /** + * Generates an URL to a page, where a entity of this type can be created. + * + * @param $entity mixed The entity for which the link should be generated. + * @return string The URL to the page. + * @throws EntityNotSupported If the method is not supported for the given Entity + */ public function createURL($entity): string { if ($entity instanceof Part) { @@ -84,6 +127,14 @@ class EntityURLGenerator throw new EntityNotSupported('The given entity is not supported yet!'); } + /** + * Generates an URL to a page, where a new entity can be created, that has the same informations as the + * given entity (element cloning) + * + * @param $entity mixed The entity for which the link should be generated. + * @return string The URL to the page. + * @throws EntityNotSupported If the method is not supported for the given Entity + */ public function cloneURL($entity): string { if ($entity instanceof Part) { @@ -93,6 +144,22 @@ class EntityURLGenerator throw new EntityNotSupported('The given entity is not supported yet!'); } + /** + * Generates an URL to a page, where all parts are listed, which are contained in the given element. + * + * @param $entity mixed The entity for which the link should be generated. + * @return string The URL to the page. + * @throws EntityNotSupported If the method is not supported for the given Entity + */ + public function listPartsURL($entity) : string + { + if ($entity instanceof Category) { + return $this->urlGenerator->generate('app_partlists_showcategory', ['id' => $entity->getID()]); + } + throw new EntityNotSupported('The given entity is not supported yet!'); + + } + /** * Generates an HTML link to the info page about the given entity. * diff --git a/src/Services/ToolsTreeBuilder.php b/src/Services/ToolsTreeBuilder.php new file mode 100644 index 00000000..c00238ab --- /dev/null +++ b/src/Services/ToolsTreeBuilder.php @@ -0,0 +1,57 @@ +entityURLGenerator->infoURL($entity); - case 'edit': - return $this->entityURLGenerator->editURL($entity); - case 'create': - return $this->entityURLGenerator->createURL($entity); - case 'clone': - return $this->entityURLGenerator->cloneURL($entity); - } - - throw new \InvalidArgumentException('method is not supported!'); + return $this->entityURLGenerator->getURL($entity, $method); } public function parseBBCode(string $bbcode): string diff --git a/templates/base.html.twig b/templates/base.html.twig index be783c1d..05b0ee2f 100644 --- a/templates/base.html.twig +++ b/templates/base.html.twig @@ -309,6 +309,24 @@ {% endblock %} + + + {% block scripts %} {% endblock %} diff --git a/webpack.config.js b/webpack.config.js index 2f7e205c..23356009 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -48,7 +48,7 @@ Encore //.enableTypeScriptLoader() // uncomment if you're having problems with a jQuery plugin - //.autoProvidejQuery() + .autoProvidejQuery() // uncomment if you use API Platform Admin (composer req api-admin) //.enableReactPreset() diff --git a/yarn.lock b/yarn.lock index e3644fce..356e568a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1195,6 +1195,10 @@ bootstrap-select@^1.13.8: resolved "https://registry.yarnpkg.com/bootstrap-select/-/bootstrap-select-1.13.8.tgz#c47047410511f6d8a8917a7738d1b03c95717d5d" integrity sha512-WF6GJPgb98cv75X6/zoCWUNwM/HPoYKP6JDBryTNDCHMPV9YyMqU7xXncC7Se2M5VAt7kZQ/i2GSYwaf5Q/Z3w== +bootstrap-treeview@jbtronics/bootstrap-treeview: + version "1.2.1" + resolved "https://codeload.github.com/jbtronics/bootstrap-treeview/tar.gz/0855394d4fa06c99289d2ba9a164a987228456c5" + bootstrap@^4.3.1: version "4.3.1" resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.3.1.tgz#280ca8f610504d99d7b6b4bfc4b68cec601704ac"