OXID eShop CE  4.10.1
 All Classes Namespaces Files Functions Variables Pages
oxnavigationtree.php
Go to the documentation of this file.
1 <?php
2 
7 {
8 
12  protected $_oDom = null;
13 
17  protected $_oInitialDom = null;
18 
24  protected $_sDynIncludeUrl = null;
25 
31  protected $_aSupportedExpathXmlEncodings = array('utf-8', 'utf-16', 'iso-8859-1', 'us-ascii');
32 
40  protected function _cleanEmptyParents($oDom, $sParentXPath, $sChildXPath)
41  {
42  $oXPath = new DomXPath($oDom);
43  $oNodeList = $oXPath->query($sParentXPath);
44 
45  foreach ($oNodeList as $oNode) {
46  $sId = $oNode->getAttribute('id');
47  $oChildList = $oXPath->query("{$sParentXPath}[@id='$sId']/$sChildXPath");
48  if (!$oChildList->length) {
49  $oNode->parentNode->removeChild($oNode);
50  }
51  }
52  }
53 
59  protected function _addLinks($oDom)
60  {
61  $sURL = 'index.php?'; // session parameters will be included later (after cache processor)
62  $oXPath = new DomXPath($oDom);
63 
64  // building
65  $oNodeList = $oXPath->query("//SUBMENU[@cl]");
66  foreach ($oNodeList as $oNode) {
67  // fetching class
68  $sCl = $oNode->getAttribute('cl');
69  $sCl = $sCl ? "cl=$sCl" : '';
70 
71  // fetching params
72  $sParam = $oNode->getAttribute('clparam');
73  $sParam = $sParam ? "&$sParam" : '';
74 
75  // setting link
76  $oNode->setAttribute('link', "{$sURL}{$sCl}{$sParam}");
77  }
78  }
79 
86  protected function _loadFromFile($sMenuFile, $oDom)
87  {
88  $blMerge = false;
89  $oDomFile = new DomDocument();
90  $oDomFile->preserveWhiteSpace = false;
91  if (!@$oDomFile->load($sMenuFile)) {
92  $blMerge = true;
93  } elseif (is_readable($sMenuFile) && ($sXml = @file_get_contents($sMenuFile))) {
94 
95  // looking for non supported character encoding
96  if (getStr()->preg_match("/encoding\=(.*)\?>/", $sXml, $aMatches) !== 0) {
97  if (isset($aMatches[1])) {
98  $sCurrEncoding = trim($aMatches[1], "\"");
99  if (!in_array(strtolower($sCurrEncoding), $this->_aSupportedExpathXmlEncodings)) {
100  $sXml = str_replace($aMatches[1], "\"UTF-8\"", $sXml);
101  $sXml = iconv($sCurrEncoding, "UTF-8", $sXml);
102  }
103  }
104  }
105 
106  // load XML as string
107  if (@$oDomFile->loadXml($sXml)) {
108  $blMerge = true;
109  }
110  }
111 
112  if ($blMerge) {
113  $this->_merge($oDomFile, $oDom);
114  }
115  }
116 
124  protected function _addDynLinks($oDom)
125  {
126  $myConfig = $this->getConfig();
127  $myUtilsFile = oxRegistry::get("oxUtilsFile");
128 
129  $sURL = 'index.php?'; // session parameters will be included later (after cache processor)
130 
131  $oXPath = new DomXPath($oDom);
132  $oNodeList = $oXPath->query("//OXMENU[@type='dyn']/MAINMENU/SUBMENU");
133 
134  foreach ($oNodeList as $oNode) {
135 
136  // fetching class
137  $sCl = $oNode->getAttribute('cl');
138  $sCl = "cl=dynscreen&menu=$sCl";
139 
140  // fetching params
141  $sParam = $oNode->getAttribute('clparam');
142  $sParam = $sParam ? "&$sParam" : '';
143 
144  // setting list node if its is not set yet
145  if (!$oNode->getAttribute('list')) {
146  $oNode->setAttribute('list', 'dynscreen_list');
147  $oNode->setAttribute('listparam', 'menu=' . $oNode->getAttribute('cl'));
148  }
149 
150  // setting link
151  $oNode->setAttribute('link', "{$sURL}{$sCl}{$sParam}");
152 
153  // setting id
154  $oNode->parentNode->setAttribute('id', 'dyn_menu');
155 
156  // setting id to its parent
157 
158  // fetching class
159  $sFile = $oNode->getAttribute('cl');
160 
161  // always display the "about" tab no matter what licence
162 
163  if ($myUtilsFile->checkFile("{$this->_sDynIncludeUrl}pages/{$sFile}_about.php")) {
164  $oTabElem = new DOMElement('TAB');
165  $oNode->appendChild($oTabElem);
166  $oTabElem->setAttribute('external', 'true');
167  $oTabElem->setAttribute('location', "{$this->_sDynIncludeUrl}pages/{$sFile}_about.php");
168  $oTabElem->setAttribute('id', 'dyn_about');
169  }
170 
171  // checking for technics page
172  if ($myUtilsFile->checkFile("{$this->_sDynIncludeUrl}pages/{$sFile}_technics.php")) {
173  $oTabElem = new DOMElement('TAB');
174  $oNode->appendChild($oTabElem);
175  $oTabElem->setAttribute('external', 'true');
176  $oTabElem->setAttribute('location', "{$this->_sDynIncludeUrl}pages/{$sFile}_technics.php");
177  $oTabElem->setAttribute('id', 'dyn_interface');
178  }
179 
180  // checking for setup page
181  if (file_exists($myConfig->getConfigParam('sShopDir') . "/application/controllers/admin/{$sFile}.php")) {
182  $oTabElem = new DOMElement('TAB');
183  $oNode->appendChild($oTabElem);
184  $oTabElem->setAttribute('id', 'dyn_interface');
185  $oTabElem->setAttribute('cl', $sFile);
186  }
187  }
188  }
189 
195  protected function _sessionizeLocalUrls($oDom)
196  {
197  $sURL = $this->_getAdminUrl();
198  $oXPath = new DomXPath($oDom);
199  $oStr = getStr();
200  foreach (array('url', 'link') as $sAttrType) {
201  foreach ($oXPath->query("//OXMENU//*[@$sAttrType]") as $oNode) {
202  $sLocalUrl = $oNode->getAttribute($sAttrType);
203  if (strpos($sLocalUrl, 'index.php?') === 0) {
204  $sLocalUrl = $oStr->preg_replace('#^index.php\?#', $sURL, $sLocalUrl);
205  $oNode->setAttribute($sAttrType, $sLocalUrl);
206  }
207  }
208  }
209  }
210 
216  protected function _checkRights($oDom)
217  {
218  $oXPath = new DomXPath($oDom);
219  $oNodeList = $oXPath->query('//*[@rights or @norights]');
220 
221  foreach ($oNodeList as $oNode) {
222  // only allowed modules/user rights or so
223  if (($sReq = $oNode->getAttribute('rights'))) {
224  $aPerm = explode(',', $sReq);
225  foreach ($aPerm as $sPerm) {
226  if ($sPerm && !$this->_hasRights($sPerm)) {
227  $oNode->parentNode->removeChild($oNode);
228  }
229  }
230  // not allowed modules/user rights or so
231  } elseif (($sNoReq = $oNode->getAttribute('norights'))) {
232  $aPerm = explode(',', $sNoReq);
233  foreach ($aPerm as $sPerm) {
234  if ($sPerm && $this->_hasRights($sPerm)) {
235  $oNode->parentNode->removeChild($oNode);
236  }
237  }
238  }
239  }
240  }
241 
247  protected function _checkGroups($oDom)
248  {
249  $oXPath = new DomXPath($oDom);
250  $oNodeList = $oXPath->query("//*[@nogroup or @group]");
251 
252  foreach ($oNodeList as $oNode) {
253  // allowed only for groups
254  if (($sReq = $oNode->getAttribute('group'))) {
255  $aPerm = explode(',', $sReq);
256  foreach ($aPerm as $sPerm) {
257  if ($sPerm && !$this->_hasGroup($sPerm)) {
258  $oNode->parentNode->removeChild($oNode);
259  }
260  }
261  // not allowed for groups
262  } elseif (($sNoReq = $oNode->getAttribute('nogroup'))) {
263  $aPerm = explode(',', $sNoReq);
264  foreach ($aPerm as $sPerm) {
265  if ($sPerm && $this->_hasGroup($sPerm)) {
266  $oNode->parentNode->removeChild($oNode);
267  }
268  }
269  }
270  }
271  }
272 
280  protected function _checkDemoShopDenials($oDom)
281  {
282  if (!$this->getConfig()->isDemoShop()) {
283  // nothing to check for non demo shop
284  return;
285  }
286 
287  $oXPath = new DomXPath($oDom);
288  $oNodeList = $oXPath->query("//*[@disableForDemoShop]");
289  foreach ($oNodeList as $oNode) {
290  if ($oNode->getAttribute('disableForDemoShop')) {
291  $oNode->parentNode->removeChild($oNode);
292  }
293  }
294  }
295 
303  protected function removeInvisibleMenuNodes($oDom)
304  {
305  $oXPath = new DomXPath($oDom);
306  $oNodeList = $oXPath->query("//*[@visible]");
307  foreach ($oNodeList as $oNode) {
308  if (!$oNode->getAttribute('visible')) {
309  $oNode->parentNode->removeChild($oNode);
310  }
311  }
312  }
313 
320  protected function _copyAttributes($oDomElemTo, $oDomElemFrom)
321  {
322  foreach ($oDomElemFrom->attributes as $oAttr) {
323  $oDomElemTo->setAttribute($oAttr->nodeName, $oAttr->nodeValue);
324  }
325  }
326 
336  protected function _mergeNodes($oDomElemTo, $oDomElemFrom, $oXPathTo, $oDomDocTo, $sQueryStart)
337  {
338  foreach ($oDomElemFrom->childNodes as $oFromNode) {
339  if ($oFromNode->nodeType === XML_ELEMENT_NODE) {
340 
341  $sFromAttrName = $oFromNode->getAttribute('id');
342  $sFromNodeName = $oFromNode->tagName;
343 
344  // find current item
345  $sQuery = "{$sQueryStart}/{$sFromNodeName}[@id='{$sFromAttrName}']";
346  $oCurNode = $oXPathTo->query($sQuery);
347 
348  // if not found - append
349  if ($oCurNode->length == 0) {
350  $oDomElemTo->appendChild($oDomDocTo->importNode($oFromNode, true));
351  } else {
352 
353  $oCurNode = $oCurNode->item(0);
354 
355  // if found copy all attributes and check childnodes
356  $this->_copyAttributes($oCurNode, $oFromNode);
357 
358  if ($oFromNode->childNodes->length) {
359  $this->_mergeNodes($oCurNode, $oFromNode, $oXPathTo, $oDomDocTo, $sQuery);
360  }
361  }
362  }
363  }
364  }
365 
372  protected function _merge($oDomNew, $oDom)
373  {
374  $oXPath = new DOMXPath($oDom);
375  $this->_mergeNodes($oDom->documentElement, $oDomNew->documentElement, $oXPath, $oDom, '/OX');
376  }
377 
387  public function getTabs($sId, $iAct, $blSetActive = true)
388  {
389  $oXPath = new DOMXPath($this->getDomXml());
390  //$oNodeList = $oXPath->query( "//SUBMENU[@cl='$sId' or @list='$sId']/TAB | //SUBMENU/../TAB[@cl='$sId']" );
391  $oNodeList = $oXPath->query("//SUBMENU[@cl='$sId']/TAB | //SUBMENU[@list='$sId']/TAB | //SUBMENU/../TAB[@cl='$sId']");
392 
393  $iAct = ($iAct > $oNodeList->length) ? ($oNodeList->length - 1) : $iAct;
394 
395  if ($blSetActive) {
396  foreach ($oNodeList as $iPos => $oNode) {
397  if ($iPos == $iAct) {
398  // marking active node
399  $oNode->setAttribute('active', 1);
400  }
401  }
402  }
403 
404  return $oNodeList;
405  }
406 
415  public function getActiveTab($sId, $iAct)
416  {
417  $sTab = null;
418  $oNodeList = $this->getTabs($sId, $iAct, false);
419  $iAct = ($iAct > $oNodeList->length) ? ($oNodeList->length - 1) : $iAct;
420  if ($oNodeList->length && ($oNode = $oNodeList->item($iAct))) {
421  $sTab = $oNode->getAttribute('cl');
422  }
423 
424  return $sTab;
425  }
426 
434  public function getBtn($sClass)
435  {
436  $oButtons = null;
437  $oXPath = new DOMXPath($this->getDomXml());
438  $oNodeList = $oXPath->query("//TAB[@cl='$sClass']/../BTN");
439  if ($oNodeList->length) {
440  $oButtons = new stdClass();
441  foreach ($oNodeList as $oNode) {
442  $sBtnID = $oNode->getAttribute('id');
443  $oButtons->$sBtnID = 1;
444  }
445  }
446 
447  return $oButtons;
448  }
449 
455  protected function _getMenuFiles()
456  {
457  $myConfig = $this->getConfig();
458  $myOxUtlis = oxRegistry::getUtils();
459 
460  $sFullAdminDir = getShopBasePath() . 'application/views/admin';
461  $sMenuFile = "/menu.xml";
462 
463  $sTmpDir = $myConfig->getConfigParam('sCompileDir');
464  $sDynLang = $this->_getDynMenuLang();
465  $sLocalDynPath = "{$sTmpDir}{$sDynLang}_dynscreen.xml";
466 
467 
468  // including std file
469  if (file_exists($sFullAdminDir . $sMenuFile)) {
470  $aFilesToLoad[] = $sFullAdminDir . $sMenuFile;
471  }
472 
473  // including custom file
474  if (file_exists("$sFullAdminDir/user.xml")) {
475  $aFilesToLoad[] = "$sFullAdminDir/user.xml";
476  }
477 
478  // including module menu files
479  $sPath = getShopBasePath();
480  $oModulelist = oxNew('oxmodulelist');
481  $aActiveModuleInfo = $oModulelist->getActiveModuleInfo();
482  if (is_array($aActiveModuleInfo)) {
483  foreach ($aActiveModuleInfo as $sModulePath) {
484  $sFullPath = $sPath . "modules/" . $sModulePath;
485  // missing file/folder?
486  if (is_dir($sFullPath)) {
487  // including menu file
488  $sMenuFile = $sFullPath . "/menu.xml";
489  if (file_exists($sMenuFile) && is_readable($sMenuFile)) {
490  $aFilesToLoad[] = $sMenuFile;
491  }
492  }
493  }
494  }
495 
496  $blLoadDynContents = $myConfig->getConfigParam('blLoadDynContents');
497  $sShopCountry = $myConfig->getConfigParam('sShopCountry');
498 
499  // including dyn menu file
500  $sDynPath = null;
501 
502  if ($blLoadDynContents) {
503  if ($sShopCountry) {
504  $sRemoteDynUrl = $this->_getDynMenuUrl($sDynLang, $blLoadDynContents);
505 
506  // loading remote file from server only once
507  $blLoadRemote = oxRegistry::getSession()->getVariable("loadedremotexml");
508 
509  // very basic check if its valid xml file
510  if ((!isset($blLoadRemote) || $blLoadRemote) && ($sDynPath = $myOxUtlis->getRemoteCachePath($sRemoteDynUrl, $sLocalDynPath))) {
511  $sDynPath = $this->_checkDynFile($sDynPath);
512  }
513 
514  // caching last load state
515  oxRegistry::getSession()->setVariable("loadedremotexml", $sDynPath ? true : false);
516  }
517  } else {
518  if ($sShopCountry) {
519  //non international country
520  }
521  }
522 
523  // loading dynpages
524  if ($sDynPath) {
525  $aFilesToLoad[] = $sDynPath;
526  }
527 
528  return $aFilesToLoad;
529  }
530 
540  protected function _checkDynFile($sDynFilePath)
541  {
542  $sDynFile = null;
543  if (file_exists($sDynFilePath)) {
544  $sLine = null;
545  if (($rHandle = @fopen($sDynFilePath, 'r'))) {
546  $sLine = stream_get_line($rHandle, 100, "?>");
547  fclose($rHandle);
548 
549  // checking xml file header
550  if ($sLine && stripos($sLine, '<?xml') !== false) {
551  $sDynFile = $sDynFilePath;
552  }
553  }
554 
555  // cleanup ..
556  if (!$sDynFile) {
557  @unlink($sDynFilePath);
558  }
559  }
560 
561  return $sDynFile;
562  }
563 
575  protected function _processCachedFile($sCacheContents)
576  {
577 
578  return $sCacheContents;
579  }
580 
586  protected function _getInitialDom()
587  {
588  if ($this->_oInitialDom === null) {
589  $myOxUtlis = oxRegistry::getUtils();
590 
591  if (is_array($aFilesToLoad = $this->_getMenuFiles())) {
592 
593  // now checking if xml files are newer than cached file
594  $blReload = false;
595  $sDynLang = $this->_getDynMenuLang();
596 
597  $sShopId = $this->getConfig()->getActiveShop()->getShopId();
598  $sCacheName = 'menu_' . $sDynLang . $sShopId . '_xml';
599  $sCacheFile = $myOxUtlis->getCacheFilePath($sCacheName);
600  $sCacheContents = $myOxUtlis->fromFileCache($sCacheName);
601  if ($sCacheContents && file_exists($sCacheFile) && ($iCacheModTime = filemtime($sCacheFile))) {
602  foreach ($aFilesToLoad as $sDynPath) {
603  if ($iCacheModTime < filemtime($sDynPath)) {
604  $blReload = true;
605  }
606  }
607  } else {
608  $blReload = true;
609  }
610 
611  $this->_oInitialDom = new DOMDocument();
612  if ($blReload) {
613  // fully reloading and building pathes
614  $this->_oInitialDom->appendChild(new DOMElement('OX'));
615 
616  foreach ($aFilesToLoad as $sDynPath) {
617  $this->_loadFromFile($sDynPath, $this->_oInitialDom);
618  }
619 
620  // adds links to menu items
621  $this->_addLinks($this->_oInitialDom);
622 
623  // @deprecated since v5.3 (2016-05-20); Dynpages will be removed.
624  // adds links to dynamic parts
625  $this->_addDynLinks($this->_oInitialDom);
626  // END deprecated
627 
628  // writing to cache
629  $myOxUtlis->toFileCache($sCacheName, $this->_oInitialDom->saveXML());
630  } else {
631  $sCacheContents = $this->_processCachedFile($sCacheContents);
632  // loading from cached file
633  $this->_oInitialDom->preserveWhiteSpace = false;
634  $this->_oInitialDom->loadXML($sCacheContents);
635  }
636 
637  // add session params
638  $this->_sessionizeLocalUrls($this->_oInitialDom);
639  }
640  }
641 
642  return $this->_oInitialDom;
643  }
644 
650  public function getDomXml()
651  {
652  if ($this->_oDom === null) {
653  $this->_oDom = clone $this->_getInitialDom();
654 
655  // removes items denied by user group
656  $this->_checkGroups($this->_oDom);
657 
658  // removes items denied by user rights
659  $this->_checkRights($this->_oDom);
660 
661  // check config params
662  $this->_checkDemoShopDenials($this->_oDom);
663 
664  // removes items marked as not visible
665  $this->removeInvisibleMenuNodes($this->_oDom);
666 
667 
668  $this->_cleanEmptyParents($this->_oDom, '//SUBMENU[@id][@list]', 'TAB');
669  $this->_cleanEmptyParents($this->_oDom, '//MAINMENU[@id]', 'SUBMENU');
670  }
671 
672  return $this->_oDom;
673  }
674 
682  public function getListNodes($aNodes)
683  {
684  $oXPath = new DOMXPath($this->getDomXml());
685  $oNodeList = $oXPath->query("//SUBMENU[@cl='" . implode("' or @cl='", $aNodes) . "']");
686 
687  return ($oNodeList->length) ? $oNodeList : null;
688  }
689 
695  public function markNodeActive($sNodeId)
696  {
697  $oXPath = new DOMXPath($this->getDomXml());
698  $oNodeList = $oXPath->query("//*[@cl='{$sNodeId}' or @list='{$sNodeId}']");
699 
700  if ($oNodeList->length) {
701  foreach ($oNodeList as $oNode) {
702  // special case for external resources
703  $oNode->setAttribute('active', 1);
704  $oNode->parentNode->setAttribute('active', 1);
705  }
706  }
707 
708  }
709 
717  public function getListUrl($sId)
718  {
719  $sUrl = null;
720  $oXPath = new DOMXPath($this->getDomXml());
721  $oNodeList = $oXPath->query("//SUBMENU[@cl='{$sId}']");
722  if ($oNodeList->length && ($oNode = $oNodeList->item(0))) {
723  $sCl = $oNode->getAttribute('list');
724  $sCl = $sCl ? "cl=$sCl" : '';
725 
726  $sParams = $oNode->getAttribute('listparam');
727  $sParams = $sParams ? "&$sParams" : '';
728 
729  $sUrl = "{$sCl}{$sParams}";
730  }
731 
732  return $sUrl;
733  }
734 
743  public function getEditUrl($sId, $iActTab)
744  {
745  $sUrl = null;
746  $oXPath = new DOMXPath($this->getDomXml());
747  $oNodeList = $oXPath->query("//SUBMENU[@cl='{$sId}']/TAB");
748 
749  $iActTab = ($iActTab > $oNodeList->length) ? ($oNodeList->length - 1) : $iActTab;
750  if ($oNodeList->length && ($oActTab = $oNodeList->item($iActTab))) {
751  // special case for external resources
752  if ($oActTab->getAttribute('external')) {
753  $sUrl = $oActTab->getAttribute('location');
754  } else {
755  $sCl = $oActTab->getAttribute('cl');
756  $sCl = $sCl ? "cl={$sCl}" : '';
757 
758  $sParams = $oActTab->getAttribute('clparam');
759  $sParams = $sParams ? "&{$sParams}" : '';
760 
761  $sUrl = "{$sCl}{$sParams}";
762  }
763  }
764 
765  return $sUrl;
766  }
767 
773  protected function _getAdminUrl()
774  {
775  $myConfig = $this->getConfig();
776 
777  if (($sAdminSslUrl = $myConfig->getConfigParam('sAdminSSLURL'))) {
778  $sURL = trim($sAdminSslUrl, '/');
779  } else {
780  $sURL = trim($myConfig->getConfigParam('sShopURL'), '/') . '/admin';
781  }
782 
783  return oxRegistry::get("oxUtilsUrl")->processUrl("{$sURL}/index.php", false);
784  }
785 
793  protected function _hasRights($sRights)
794  {
795  return $this->getUser()->oxuser__oxrights->value == $sRights;
796  }
797 
805  protected function _hasGroup($sGroupId)
806  {
807  return $this->getUser()->inGroup($sGroupId);
808  }
809 
817  public function getClassId($sClassName)
818  {
819  $sClassId = null;
820 
821  $oXPath = new DOMXPath($this->_getInitialDom());
822  $oNodeList = $oXPath->query("//*[@cl='{$sClassName}' or @list='{$sClassName}']");
823  if ($oNodeList->length && ($oFirstItem = $oNodeList->item(0))) {
824  $sClassId = $oFirstItem->getAttribute('id');
825  }
826 
827  return $sClassId;
828  }
829 
830 
841  protected function _getDynMenuUrl($iLang, $blLoadDynContents)
842  {
843  if (!$blLoadDynContents) {
844  // getting dyn info from oxid server is off, so getting local menu path
845  $sFullAdminDir = getShopBasePath() . 'application/views/admin';
846  $sUrl = $sFullAdminDir . "/dynscreen_local.xml";
847  } else {
848  $oAdminView = oxNew('oxadminview');
849  $this->_sDynIncludeUrl = $oAdminView->getServiceUrl($iLang);
850  $sUrl .= $this->_sDynIncludeUrl . "menue/dynscreen.xml";
851  }
852 
853  return $sUrl;
854  }
855 
863  protected function _getDynMenuLang()
864  {
865  $myConfig = $this->getConfig();
866  $oLang = oxRegistry::getLang();
867 
868  $iDynLang = $myConfig->getConfigParam('iDynInterfaceLanguage');
869  $iDynLang = isset($iDynLang) ? $iDynLang : ($oLang->getTplLanguage());
870 
871  $aLanguages = $oLang->getLanguageArray();
872  $sLangAbr = $aLanguages[$iDynLang]->abbr;
873 
874  return $sLangAbr;
875  }
876 }