Passed
Push — master ( ad69c3...d9b15d )
by Jan
04:17
created

TreeViewGenerator::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 5
c 1
b 0
f 0
nc 1
nop 5
dl 0
loc 8
rs 10
1
<?php
2
/**
3
 * This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
4
 *
5
 * Copyright (C) 2019 Jan Böhmer (https://github.com/jbtronics)
6
 *
7
 * This program is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU General Public License
9
 * as published by the Free Software Foundation; either version 2
10
 * of the License, or (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
20
 */
21
22
namespace App\Services\Trees;
23
24
25
use App\Entity\Base\DBElement;
26
use App\Entity\Base\NamedDBElement;
27
use App\Entity\Base\StructuralDBElement;
28
use App\Helpers\Trees\TreeViewNodeIterator;
29
use App\Helpers\Trees\TreeViewNode;
30
use App\Repository\StructuralDBElementRepository;
31
use App\Services\EntityURLGenerator;
32
use App\Services\UserCacheKeyGenerator;
33
use Doctrine\ORM\EntityManagerInterface;
34
use Symfony\Contracts\Cache\ItemInterface;
35
use Symfony\Contracts\Cache\TagAwareCacheInterface;
36
use Symfony\Contracts\Translation\TranslatorInterface;
37
38
class TreeViewGenerator
39
{
40
41
    protected $urlGenerator;
42
    protected $em;
43
    protected $cache;
44
    protected $keyGenerator;
45
    protected $translator;
46
47
    public function __construct(EntityURLGenerator $URLGenerator, EntityManagerInterface $em,
48
        TagAwareCacheInterface $treeCache, UserCacheKeyGenerator $keyGenerator, TranslatorInterface $translator)
49
    {
50
        $this->urlGenerator = $URLGenerator;
51
        $this->em = $em;
52
        $this->cache = $treeCache;
53
        $this->keyGenerator = $keyGenerator;
54
        $this->translator = $translator;
55
    }
56
57
    /**
58
     * Gets a TreeView list for the entities of the given class.
59
     * @param  string  $class The class for which the treeView should be generated
60
     * @param  StructuralDBElement|null  $parent The root nodes in the tree should have this element as parent (use null, if you want to get all entities)
61
     * @param  string  $href_type The link type that will be generated for the hyperlink section of each node (see EntityURLGenerator for possible values).
62
     * Set to empty string, to disable href field.
63
     * @param  DBElement|null  $selectedElement The element that should be selected. If set to null, no element will be selected.
64
     * @return TreeViewNode[] An array of TreeViewNode[] elements of the root elements.
65
     */
66
    public function getTreeView(string $class, ?StructuralDBElement $parent = null, string $href_type = 'list_parts', DBElement $selectedElement = null) : array
67
    {
68
        $head = [];
69
70
        //When we use the newEdit type, add the New Element node.
71
        if ('newEdit' === $href_type) {
72
            //Generate the url for the new node
73
            $href = $this->urlGenerator->createURL(new $class());
74
            $new_node = new TreeViewNode($this->translator->trans('entity.tree.new'), $href);
75
            //When the id of the selected element is null, then we have a new element, and we need to select "new" node
76
            if (null == $selectedElement || null == $selectedElement->getID()) {
77
                $new_node->setSelected(true);
78
            }
79
            $head[] = $new_node;
80
            //Add spacing
81
            $head[] = (new TreeViewNode(''))->setDisabled(true);
82
83
            //Every other treeNode will be used for edit
84
            $href_type = 'edit';
85
        }
86
87
        $generic = $this->getGenericTree($class, $parent);
88
        $treeIterator = new TreeViewNodeIterator($generic);
89
        $recursiveIterator = new \RecursiveIteratorIterator($treeIterator, \RecursiveIteratorIterator::SELF_FIRST);
90
        foreach ($recursiveIterator as $item) {
91
            /** @var $item TreeViewNode */
92
            if ($selectedElement !== null && $item->getId() === $selectedElement->getID()) {
93
               $item->setSelected(true);
94
            }
95
96
            if (!empty($item->getNodes())) {
97
                $item->addTag((string) \count($item->getNodes()));
98
            }
99
100
            if (!empty($href_type)) {
101
                $entity = $this->em->getPartialReference($class, $item->getId());
102
                $item->setHref($this->urlGenerator->getURL($entity, $href_type));
103
            }
104
        }
105
106
        return array_merge($head, $generic);
107
    }
108
109
    /**
110
     * /**
111
     * Gets a tree of TreeViewNode elements. The root elements has $parent as parent.
112
     * The treeview is generic, that means the href are null and ID values are set.
113
     *
114
     * @param  string  $class The class for which the tree should be generated
115
     * @param  StructuralDBElement|null  $parent The parent the root elements should have.
116
     * @return TreeViewNode[]
117
     */
118
    public function getGenericTree(string $class, ?StructuralDBElement $parent = null) : array
119
    {
120
        if(!is_a($class, NamedDBElement::class, true)) {
121
            throw new \InvalidArgumentException('$class must be a class string that implements StructuralDBElement or NamedDBElement!');
122
        }
123
        if($parent !== null && !is_a($parent, $class)) {
124
            throw new \InvalidArgumentException('$parent must be of the type $class!');
125
        }
126
127
        /** @var StructuralDBElementRepository $repo */
128
        $repo = $this->em->getRepository($class);
129
130
        //If we just want a part of a tree, dont cache it
131
        if ($parent !== null) {
132
           return $repo->getGenericNodeTree($parent);
133
        }
134
135
        $secure_class_name = str_replace('\\', '_', $class);
136
        $key = 'treeview_'.$this->keyGenerator->generateKey().'_'.$secure_class_name;
137
138
        $ret = $this->cache->get($key, function (ItemInterface $item) use ($repo, $parent, $secure_class_name) {
139
            // Invalidate when groups, a element with the class or the user changes
140
            $item->tag(['groups', 'tree_treeview', $this->keyGenerator->generateKey(), $secure_class_name]);
141
            return $repo->getGenericNodeTree($parent);
142
        });
143
144
        return $ret;
145
    }
146
}