diff --git a/config/module.config.php b/config/module.config.php index 78d6e4b..ce7f6b7 100644 --- a/config/module.config.php +++ b/config/module.config.php @@ -54,6 +54,16 @@ ], ], ], + 'update' => [ + 'type' => Literal::class, + 'options' => [ + 'route' => '/update', + 'defaults' => [ + 'controller' => Controller\IndexController::class, + 'action' => 'update', + ], + ], + ], ], ], ], diff --git a/pickletree/pickletree.css b/pickletree/pickletree.css index 62dda21..743165f 100644 --- a/pickletree/pickletree.css +++ b/pickletree/pickletree.css @@ -164,3 +164,6 @@ ul li a { font-size: larger; margin: 3px 5px 3px 5px; } +div[id^='div_g_node']:hover{ + background-color: var(--bs-gray-200); +} diff --git a/pickletree/pickletree.js b/pickletree/pickletree.js index c4555b9..bdb4918 100644 --- a/pickletree/pickletree.js +++ b/pickletree/pickletree.js @@ -97,9 +97,7 @@ class PickleTree { } else { node.parent = this.getNode(this.drag_target); } - console.log(this.dragstartNode.parent.id); - console.log(node.old_parent.id); - console.log(node.old_parent.id === this.dragstartNode.parent.id); + if( node.old_parent.id !== this.dragstartNode.parent.id ){ //save node in an object array of ids this.changeParentNodes[node.id] = node; @@ -378,6 +376,12 @@ class PickleTree { id: 'node_' + id, //node title title: 'untitled ' + id, + //node element value + route: 'route ' + id, + //node element value + uri: 'uri ' + id, + //node element value + slug: 'uri ' + id, //node html elements elements: [], //node parent element @@ -419,7 +423,6 @@ class PickleTree { //logged this.log('Node is created (' + node.id + ')'); if (node.id.indexOf('lrphpt') > 0 ){ - console.log('new node id is ' + node.id); this.nodeCreatedAtRuntime[node.id] = node; } //node is returned @@ -465,6 +468,28 @@ class PickleTree { return node; } + /** + * + * @param {JSON} jsonValues + * @returns {type} bool + */ + updateNodeValues(jsonValues){ + let updated = false; + try{ + document.getElementById('a_dr_node_' + jsonValues.id).setAttribute('drag-title', jsonValues.title); + let ele = document.getElementById('a_toggle_node_' + jsonValues.id); + let changeText = ele.innerHTML.replace(this.nodeList[jsonValues.id].title, jsonValues.title); + ele.innerHTML = changeText; + this.nodeList[jsonValues.id].title = jsonValues.title; + this.nodeList[jsonValues.id].uri = jsonValues.uri; + this.nodeList[jsonValues.id].route = jsonValues.route_name; + updated = true; + }catch(e){ + updated = false; + } + return updated; + } + /** * * @param {object} node object for creating html element @@ -637,22 +662,15 @@ class PickleTree { let next = li.nextElementSibling; // <-- Code changed if (next != null) next = next.nextElementSibling; // <-- Code inserted let prev = li.previousElementSibling; - //console.log(clicked.classList.contains('fa-level-up')); let node = this.getNode(e.target.parentNode.parentNode.parentNode.id.split('_')[1]); - console.log(node); + if (clicked.classList.contains('fa-level-down')) { ul.insertBefore(li, next); this.saveNodeChanges(node, li, 'move-down'); } else if (clicked.classList.contains('fa-level-up')) { ul.insertBefore(li, prev); this.saveNodeChanges(node, li, 'move-up'); - } else if (clicked.classList.contains('fa-trash')) { - li.remove(); - this.saveNodeChanges(node, li, 'delete'); - } else { - this.saveNodeChanges(node, li, 'edit'); } - //console.log(e.target.parentNode.parentNode.parentNode.id); }); } } @@ -665,8 +683,6 @@ class PickleTree { }else if(action === 'move-up'){ node.sibling = 'moveup_' + element.nextElementSibling.id; this.moveNodes[node.id] = node; - }else if(action === 'delete'){ - this.deletedNodes[node.id] = node; } } @@ -698,6 +714,9 @@ class PickleTree { this.createNode({ n_value: list[i].n_id, n_title: list[i].n_title, + n_route: list[i].n_route, + n_uri: list[i].n_uri, + n_slug: list[i].n_slug, n_id: list[i].n_id, n_elements: list[i].n_elements, n_parent: this.getNode(list[i].n_parentid), diff --git a/src/Controller/IndexController.php b/src/Controller/IndexController.php index 288b748..fcf465e 100644 --- a/src/Controller/IndexController.php +++ b/src/Controller/IndexController.php @@ -60,4 +60,37 @@ public function menutreeAction(){ } return new ViewModel(['treeArray' => $arr, 'rootNode' => $dummyParentNode]); } -} \ No newline at end of file + + public function updateAction(){ + $request = $this->getRequest(); + $data = ['status' => '404', 'message' => 'Failure']; + $viewModel = new \Laminas\View\Model\JsonModel(); + if($request->isPost() && $request->isXmlHttpRequest()){ + $repo = $this->entityManager->getRepository(Menu::class); + $postDataArr = $request->getPost()->toArray(); + $return = null; + + $return = $repo->editPostedNode($postDataArr); + if($return){ + $uow = $this->entityManager->getUnitOfWork(); + $return = $uow->getOriginalEntityData($return); + + $arrReturn = [ + 'id' => $postDataArr['id'], + 'title' => $return['label'], + 'route_name' => $return['route'], + 'uri' => $return['uri'], + 'resource' => $return['resource'], + 'slug' => $return['slug'], + ]; + unset($return); + $data['status'] = 200; + $data['message'] = 'Success'; + $data['data'] = $arrReturn; + $data['postedData'] = $postDataArr; + } + } + + return $viewModel->setVariables($data); + } +} diff --git a/src/Entity/Menu.php b/src/Entity/Menu.php index 3c61830..514a8c9 100644 --- a/src/Entity/Menu.php +++ b/src/Entity/Menu.php @@ -14,6 +14,7 @@ * @ORM\Entity(repositoryClass=\LRPHPT\MenuTree\Repository\MenuRepository::class) */ #[Gedmo\Tree(type: 'nested')] +#[Gedmo\Loggable()] #[ORM\Table(name: 'menu')] #[ORM\Entity(repositoryClass: \LRPHPT\MenuTree\Repository\MenuRepository::class)] class Menu @@ -53,6 +54,14 @@ class Menu */ #[ORM\Column(name: 'resource', type: Types::STRING, length: 255, nullable:true)] private $resource; + + /** + * @var string|null + * + * @ORM\Column(name="permission", type="string", length=255, nullable=true) + */ + #[ORM\Column(name: 'permission', type: Types::STRING, length: 255, nullable:true)] + private $permission; /** * @var string|null @@ -99,6 +108,8 @@ class Menu * @Gedmo\Slug(fields={"label"}, updatable=true) * @ORM\Column(type="string", length=255) */ + #[Gedmo\Slug(fields:['label'], updateable: true)] + #[ORM\Column(name: 'slug', type: Types::STRING, length: 255)] private $slug; /** diff --git a/src/Module.php b/src/Module.php index 1e3597c..1717c1c 100644 --- a/src/Module.php +++ b/src/Module.php @@ -8,7 +8,6 @@ namespace LRPHPT\MenuTree; class Module{ - public function getConfig() : array{ return include __DIR__ . '/../config/module.config.php'; } diff --git a/src/Repository/MenuRepository.php b/src/Repository/MenuRepository.php index cf7907c..b9b9b22 100644 --- a/src/Repository/MenuRepository.php +++ b/src/Repository/MenuRepository.php @@ -14,10 +14,17 @@ class MenuRepository extends NestedTreeRepository{ protected $bindingRootNode = null; - public function getMenuPages(string $menuRootNodeLabel = 'node'){ + /** + * + * @param string $menuRootNodeSlug + * @return array + * @throws \Exception + */ + public function getMenuPages(string $menuRootNodeSlug = 'node') : array + { $arr = []; try{ - $dummyNode = $this->findOneBy(['slug' => $menuRootNodeLabel]); + $dummyNode = $this->findOneBy(['slug' => $menuRootNodeSlug]); if($dummyNode !== null){ $queryBuilder = $this->childrenQueryBuilder($dummyNode, false, ['root', 'lft']); $arr = $queryBuilder->getQuery()->getArrayResult(); @@ -29,7 +36,129 @@ public function getMenuPages(string $menuRootNodeLabel = 'node'){ return $this->getMyTree($arr); } - public function getMyTree(array $nodes = []) + /** + * + * @param string $menuRootNodeSlug + * @return array + * @throws \Exception + */ + public function getPickleTreeArray(string $menuRootNodeSlug = 'node') : array + { + $arr = []; + try{ + $this->bindingRootNode = $this->findOneBy(['slug' => $menuRootNodeSlug]); + if($this->bindingRootNode !== null){ + $queryBuilder = $this->childrenQueryBuilder($this->bindingRootNode , false, ['root', 'lft']); + $arr = $queryBuilder->getQuery()->setHint(\Doctrine\ORM\Query::HINT_INCLUDE_META_COLUMNS, true)->getArrayResult(); + } + }catch(\Exception $e){ + throw $e; + } + + return $this->createPickleTreeArr($arr); + } + + /** + * + * @param array $submittedData + * @param Menu $dummyParentNode + * @return void + */ + public function insertUpdateDataCollectedViaForm(array $submittedData = [], Menu $dummyParentNode = null) : void{ + $menu = $createdNodes = []; + $newNodes = $submittedData['newNodes']; + $parentNodes = $submittedData['parentNodes']; + $movedNodes = $submittedData['movedNodes']; + + /* Start of node creation loop. */ + if(count($newNodes) > 0){ + foreach($newNodes as $node){ + $menu[$node['id']] = new Menu(); + $menu[$node['id']]->setLabel($node['title']); + $menu[$node['id']]->setRoute($node['route']); + + if($node['parent']['id'] === 0){/* Assign as root node. */ + $menu[$node['id']]->setParent($dummyParentNode); + $createdNodes[$node['id']] = $node['parent']['id']; + $this->removeNodeFromParentArray($node['id'], $parentNodes); + }elseif(is_long($node['parent']['value'])){/* Assign existing parent. */ + $menu[$node['id']]->setParent($this->findOneBy(['id' => $node['parent']['value']])); + $createdNodes[$node['id']] = $node['parent']['id']; + $this->removeNodeFromParentArray($node['id'], $parentNodes); + }else{ + /* If nodes are created via parents first order. + * We'll not need to first create a parent and then set it. */ + if(isset($createdNodes[$node['parent']['id']]) ){ + $menu[$node['id']]->setParent($menu[$node['parent']['id']]); + $createdNodes[$node['id']] = $node['parent']['id']; + } + } + $this->_em->persist($menu[$node['id']]); + } + $this->_em->flush(); + $this->assignTheCorrectValuesForParentAndMoveArray($menu, $parentNodes); + } + + unset($menu, $createdNodes); + if(count($parentNodes)){ + $menu = []; + foreach($parentNodes as $node){ + $menu[$node['id']] = $this->findOneBy(['id' => $node['value']]); + + if($node['parent']['id'] === 0){/* Assign as root node. */ + $menu[$node['id']]->setParent($dummyParentNode); + }elseif(is_long($node['parent']['value'])){/* Assign existing parent. */ + $menu[$node['id']]->setParent($this->findOneBy(['id' => $node['parent']['value']])); + } + $this->_em->persist($menu[$node['id']]); + } + $this->_em->flush(); + unset($menu); + } + + /* Nodes alignment change */ + if(count($movedNodes) > 0){ + foreach($movedNodes as $node){ + $nodeToMove = $this->findOneById($node['value']); + $nodeMethod = explode('_', $node['sibling']); + $nodeAsSibling = $this->findOneById($nodeMethod[2]); + $nodeMethod = $nodeMethod[0]; + switch($nodeMethod){ + case 'movedown': + $this->persistAsNextSiblingOf($nodeToMove, $nodeAsSibling); + break; + case 'moveup': + $this->persistAsPrevSiblingOf($nodeToMove, $nodeAsSibling); + break; + } + } + $this->_em->flush(); + } + } + + protected function assignTheCorrectValuesForParentAndMoveArray(array $arrWithValues, array &$arrToChange, $true = 0){ + if($true && count($arrToChange) > 4){ + $arrToChange['value'] = $arrWithValues[$arrToChange['id']]->getId(); + return; + } + + foreach ($arrToChange as &$value) { + if(isset($value['value'])){ + $value['value'] = $arrWithValues[$value['id']]->getId(); + } + + if(isset($value['parent']) && is_array($value['parent'])){ + $this->assignTheCorrectValuesForParentAndMoveArray($arrWithValues, $value['parent'], 1); + } + } + } + + /** + * + * @param array $nodes + * @return array + */ + protected function getMyTree(array $nodes = []) : array { $config = ['level' => 'lvl']; $nestedTree = []; @@ -65,7 +194,12 @@ public function getMyTree(array $nodes = []) return $nestedTree; } - protected function createPickleTreeArr(array $nodes = []) + /** + * + * @param array $nodes + * @return array + */ + protected function createPickleTreeArr(array $nodes = []) : array { $nestedTree = []; $index = 0; @@ -110,69 +244,35 @@ protected function createPickleTreeArr(array $nodes = []) return $nestedTree; } - public function getPickleTreeArray(string $menuRootNodeLabel = 'node'){ - $arr = []; - try{ - $this->bindingRootNode = $this->findOneBy(['slug' => $menuRootNodeLabel]); - if($this->bindingRootNode !== null){ - $queryBuilder = $this->childrenQueryBuilder($this->bindingRootNode , false, ['root', 'lft']); - $arr = $queryBuilder->getQuery()->setHint(\Doctrine\ORM\Query::HINT_INCLUDE_META_COLUMNS, true)->getArrayResult(); - } - }catch(\Exception $e){ - throw $e; + /** + * + * @param string $nodeKey + * @param array $arrNodeWithParents + * @return void + */ + protected function removeNodeFromParentArray(string $nodeKey, array &$arrNodeWithParents = []):void{ + if(isset($arrNodeWithParents[$nodeKey])){ + unset($arrNodeWithParents[$nodeKey]); } - - return $this->createPickleTreeArr($arr); } - public function insertUpdateDataCollectedViaForm(array $submittedData = [], Menu $dummyParentNode = null){ - $menu = $createdNodes = []; - $newNodes = $submittedData['newNodes']; - $movedNodes = $submittedData['movedNodes']; - - /* Start of node creation loop. */ - if(count($newNodes) > 0){ - foreach($newNodes as $node){ - $menu[$node['id']] = new Menu(); - $menu[$node['id']]->setLabel($node['title']); - $menu[$node['id']]->setRoute($node['route']); - - if($node['parent']['id'] === 0){/* Assign as root node. */ - $menu[$node['id']]->setParent($dummyParentNode); - $createdNodes[$node['id']] = $node['parent']['id']; - }elseif(is_long($node['parent']['value'])){/* Assign existing parent. */ - $menu[$node['id']]->setParent($this->findOneBy(['id' => $node['parent']['value']])); - $createdNodes[$node['id']] = $node['parent']['id']; - }else{ - /* If nodes are created via parents first order. - * We'll not need to first create a parent and then set it. */ - if(isset($createdNodes[$node['parent']['id']]) ){ - $menu[$node['id']]->setParent($menu[$node['parent']['id']]); - $createdNodes[$node['id']] = $node['parent']['id']; - } - } - $this->_em->persist($menu[$node['id']]); - } - $this->_em->flush(); - } + /** + * + * @param array $postedData + * @return false|\LRPHPT\MenuTree\Entity\Menu::class + */ + public function editPostedNode(array $postedData = []){ + try{ + $currentObj = $this->findOneBy(['id' => $postedData['id'], 'slug' => $postedData['slug']]); + $currentObj->setLabel($postedData['title']); + $currentObj->setRoute($postedData['route_name']); + $currentObj->setUri($postedData['uri']); - /* Nodes alignment change */ - if(count($movedNodes) > 0){ - foreach($movedNodes as $node){ - $nodeToMove = $this->findOneById($node['value']); - $nodeMethod = explode('_', $node['sibling']); - $nodeAsSibling = $this->findOneById($nodeMethod[2]); - $nodeMethod = $nodeMethod[0]; - switch($nodeMethod){ - case 'movedown': - $this->persistAsNextSiblingOf($nodeToMove, $nodeAsSibling); - break; - case 'moveup': - $this->persistAsPrevSiblingOf($nodeToMove, $nodeAsSibling); - break; - } - } + $this->_em->persist($currentObj); $this->_em->flush(); + return $currentObj; + } catch (\Exception $ex) { + return false; } } } diff --git a/view/lrphpt/menu-tree/index/menutree.phtml b/view/lrphpt/menu-tree/index/menutree.phtml index de6203d..59793f7 100644 --- a/view/lrphpt/menu-tree/index/menutree.phtml +++ b/view/lrphpt/menu-tree/index/menutree.phtml @@ -1,6 +1,6 @@ headLink()->appendStylesheet($this->serverUrl('/pickletree/pickletree.css')); -$this->inlineScript()->appendFile($this->serverUrl('/pickletree/pickletree.js')); +$this->headLink()->appendStylesheet($this->serverUrl('/pickletree/pickletree.css?v=1.2.1')); +$this->inlineScript()->appendFile($this->serverUrl('/pickletree/pickletree.js?v=1.2.1')); $json = json_encode($treeArray,true); ?>