Преглед изворни кода

Ticket #2518 - Point №2. Comments' structure are generated before displaying process. It doesn't use statically saved connections between comment and its children.

AntonLV пре 6 година
родитељ
комит
05dcf04de6
4 измењених фајлова са 213 додато и 16 уклоњено
  1. 97 4
      inc/classes/BxDolCmts.php
  2. 51 0
      inc/classes/BxDolCmtsQuery.php
  3. 4 1
      inc/js/classes/BxDolCmts.js
  4. 61 11
      template/scripts/BxBaseCmts.php

+ 97 - 4
inc/classes/BxDolCmts.php

@@ -173,6 +173,7 @@ class BxDolCmts extends BxDolFactory implements iBxDolReplaceable, iBxDolContent
     protected $_sSystem = 'profile'; ///< current comment system name
     protected $_aSystem = array (); ///< current comments system array
     protected $_iId = 0; ///< obect id to be commented
+    protected $_iAuthorId = 0; ///< currently logged in user who browse, post, etc.
 
     protected $_aT = array (); ///< an array of lang keys
     protected $_aMarkers = array ();
@@ -209,9 +210,10 @@ class BxDolCmts extends BxDolFactory implements iBxDolReplaceable, iBxDolContent
 
         $this->_sSystem = $sSystem;
         $this->_aSystem = $this->_aSystems[$sSystem];
-
         $this->_aSystem['is_browse_filter'] = (int)$this->_bBrowseFilter;
 
+        $this->_iAuthorId = $this->_getAuthorId();
+
         $this->_iDpMaxLevel = (int)$this->_aSystem['number_of_levels'];
         $this->_sDisplayType = $this->_iDpMaxLevel == 0 ? BX_CMT_DISPLAY_FLAT : BX_CMT_DISPLAY_THREADED;
         $this->_sDpSessionKey = 'bx_' . $this->_sSystem . '_dp_';
@@ -1033,7 +1035,21 @@ class BxDolCmts extends BxDolFactory implements iBxDolReplaceable, iBxDolContent
         $this->_getParams($aBp, $aDp);
 
         $aDp['dynamic_mode'] = true;
-        return $this->getComments($aBp, $aDp);
+
+        //--- Beg: Using pregenerated structure
+        if(isset($aDp['structure']) && $aDp['structure'] === true) {
+            $iCmtId = isset($aBp['parent_id']) ? (int)$aBp['parent_id'] : 0;
+
+            $mixedStructure = $this->getCommentStructure($iCmtId, $aBp, $aDp);
+            if($mixedStructure === false || empty($mixedStructure[$iCmtId]['items'])) 
+                return '';
+
+            $aDp['structure'] = $mixedStructure[$iCmtId]['items'];
+            return $this->getCommentsByStructure($aBp, $aDp);
+        }
+        //--- End: Using pregenerated structure
+        else
+            return $this->getComments($aBp, $aDp);
     }
 
     public function actionSubmitPostForm()
@@ -1509,6 +1525,13 @@ class BxDolCmts extends BxDolFactory implements iBxDolReplaceable, iBxDolContent
         if(bx_get('CmtDisplay') !== false) 
             $aDp['type'] = bx_process_input($_REQUEST['CmtDisplay'], BX_DATA_TEXT);
 
+        if(bx_get('CmtDisplayStructure') !== false) {
+            $aDp['structure'] = bx_process_input($_REQUEST['CmtDisplayStructure'], BX_DATA_INT) == 1;
+
+            if($aDp['structure'] && bx_get('CmtParent') !== false)
+                $aBp['parent_id'] = bx_process_input(bx_get('CmtParent'), BX_DATA_INT);
+        }
+
         $aDp['blink'] = isset($aDp['blink']) ? $aDp['blink'] : '';
         if(bx_get('CmtBlink') !== false) 
             $aDp['blink'] = bx_process_input($_REQUEST['CmtBlink'], BX_DATA_TEXT);
@@ -1562,6 +1585,28 @@ class BxDolCmts extends BxDolFactory implements iBxDolReplaceable, iBxDolContent
         return $s;
     }
 
+    protected function _prepareStructureBp($sDType, &$aBp)
+    {
+        $aBp['type'] = !empty($aBp['type']) ? $aBp['type'] : $this->_sBrowseType;
+        $aBp['filter'] = !empty($aBp['filter']) ? $aBp['filter'] : $this->_sBrowseFilter;
+        $aBp['parent_id'] = isset($aBp['parent_id']) ? $aBp['parent_id'] : 0;
+        $aBp['start'] = isset($aBp['start']) ? $aBp['start'] : -1;
+        $aBp['per_view'] = isset($aBp['per_view']) ? $aBp['per_view'] : -1;
+        $aBp['order']['by'] = isset($aBp['order_by']) ? $aBp['order_by'] : $this->_aOrder['by'];
+        $aBp['order']['way'] = isset($aBp['order_way']) ? $aBp['order_way'] : $this->_aOrder['way'];
+
+        if($aBp['per_view'] == -1)
+            switch($sDType) {
+                case BX_CMT_DISPLAY_FLAT:
+                    $aBp['per_view'] = $this->getPerView(0);
+                    break;
+
+                case BX_CMT_DISPLAY_THREADED:
+                    $aBp['per_view'] = $this->getPerView($aBp['parent_id']);
+                    break;
+            }
+    }
+
     protected function _prepareParams(&$aBp, &$aDp)
     {
         $aBp['type'] = !empty($aBp['type']) ? $aBp['type'] : $this->_sBrowseType;
@@ -1587,7 +1632,13 @@ class BxDolCmts extends BxDolFactory implements iBxDolReplaceable, iBxDolContent
                 break;
 
             case BX_CMT_DISPLAY_THREADED:
-                $aBp['per_view'] = $aBp['per_view'] != -1 ? $aBp['per_view'] : $this->getPerView($aBp['vparent_id']);
+                $iParent = 0;
+                if(isset($aBp['vparent_id']))
+                    $iParent = $aBp['vparent_id'];
+                else if(isset($aBp['parent_id']))
+                    $iParent = $aBp['parent_id'];
+
+                $aBp['per_view'] = $aBp['per_view'] != -1 ? $aBp['per_view'] : $this->getPerView($iParent);
                 break;
         }
 
@@ -1600,7 +1651,9 @@ class BxDolCmts extends BxDolFactory implements iBxDolReplaceable, iBxDolContent
                 break;
         }
 
-        $aBp['count'] = $this->getCommentsCount($this->_iId, $aBp['vparent_id'], $aBp['filter']);
+        if(!isset($aBp['count']))
+            $aBp['count'] = $this->getCommentsCount($this->_iId, $aBp['vparent_id'], $aBp['filter']);
+
         if($aBp['start'] != -1)
             return;
 
@@ -1742,6 +1795,46 @@ class BxDolCmts extends BxDolFactory implements iBxDolReplaceable, iBxDolContent
     {
     	return '_cmt_txt_do';
     }
+    
+    public function _getStructure($mixedItem, $aBp, &$iLevel, &$aStructure)
+    {
+        $bItem = !empty($mixedItem) && is_array($mixedItem);
+
+        if($bItem) {
+            $iI = $mixedItem['cmt_id'];
+            $aStructure[$iI] = array(
+                'id' => $mixedItem['cmt_id'], 
+                'order' => isset($mixedItem['cmt_order']) ? $mixedItem['cmt_order'] : 0, 
+                'items' => array(),
+            );
+        }
+
+        if(!$bItem || (int)$mixedItem['cmt_replies'] > 0) {
+            $aItems = $this->_oQuery->getStructure($this->_iId, $this->_iAuthorId, $bItem ? $mixedItem['cmt_id'] : 0, $aBp['filter'], $aBp['order']);
+            if(!empty($aItems)) {
+                if($bItem && $iLevel < (int)$this->_aSystem['number_of_levels']) {
+                    $iPassLevel = $iLevel + 1;
+                    $aPassStructure = &$aStructure[$iI]['items'];
+                }
+                else {
+                    $iPassLevel = $iLevel;
+                    $aPassStructure = &$aStructure;
+                }
+
+                foreach($aItems as $aItem)
+                    $this->_getStructure($aItem, $aBp, $iPassLevel, $aPassStructure);
+
+                //--- Sort subitems
+                $iWay = isset($aBp['order']['way']) && $aBp['order']['way'] == 'desc' ? -1 : 1;
+                uasort($aPassStructure, function($aItem1, $aItem2) use ($iWay) {
+                    if($aItem1['order'] == $aItem2['order'])
+                        return 0;
+
+                    return $iWay * ($aItem1['order'] < $aItem2['order'] ? -1 : 1);
+                });
+            }
+        }
+    }
 }
 
 /** @} */

+ 51 - 0
inc/classes/BxDolCmtsQuery.php

@@ -107,6 +107,57 @@ class BxDolCmtsQuery extends BxDolDb
         return (int)$this->getOne($sQuery, $aBindings);
     }
 
+    function getStructure($iObjectId, $iAuthorId = 0, $iParentId = 0, $sFilter = '', $aOrder = array())
+    {
+        $sSelectClause = $sJoinClause = $sWhereClause = "";
+
+    	$aBindings = array(
+            'cmt_object_id' => $iObjectId,
+            'system_id' => $this->_oMain->getSystemId()
+    	);
+
+        if((int)$iParentId >= 0) {
+            $aBindings['cmt_parent_id'] = $iParentId;
+
+            $sWhereClause .= " AND `tc`.`cmt_parent_id` = :cmt_parent_id";
+        }
+
+        if(in_array($sFilter, array(BX_CMT_FILTER_FRIENDS, BX_CMT_FILTER_SUBSCRIPTIONS))) {
+            $sConnection = $this->_oMain->getConnectionObject($sFilter);
+            $aQueryParts = BxDolConnection::getObjectInstance($sConnection)->getConnectedContentAsSQLParts($this->_sTable, 'cmt_author_id', $iAuthorId);
+            $sJoinClause .= ' ' . $aQueryParts['join'];
+        }
+
+        if(isset($aOrder['by']) && isset($aOrder['way']))
+            switch($aOrder['by']) {
+                case BX_CMT_ORDER_BY_DATE:
+                    $sSelectClause .= ", `tc`.`cmt_time` AS `cmt_order`";
+                    break;
+
+                case BX_CMT_ORDER_BY_POPULAR:
+                    $aOrderFields = array();
+                    if($this->_oMain->getVoteObject(0) !== false)
+                        $aOrderFields[] = "`ti`.`votes`";
+                    if($this->_oMain->getScoreObject(0) !== false)
+                        $aOrderFields[] = "`ti`.`score`";
+                    
+                    if(!empty($aOrderFields))
+                        $sSelectClause .= ", (" . implode(' + ', $aOrderFields) . ") AS `cmt_order`";
+                    else
+                        $sSelectClause .= ", `tc`.`id` AS `cmt_order`";
+                    break;
+            }
+
+        $sQuery = "SELECT
+                `tc`.`cmt_id`, 
+                `tc`.`cmt_replies`, 
+                `tc`.`cmt_time` $sSelectClause
+            FROM `{$this->_sTable}` AS `tc`
+            LEFT JOIN `{$this->_sTableIds}` AS `ti` ON `tc`.`cmt_id` = `ti`.`cmt_id` AND `ti`.`system_id` = :system_id $sJoinClause
+            WHERE `tc`.`cmt_object_id` = :cmt_object_id" . $sWhereClause;
+        return $this->getAll($sQuery, $aBindings);
+    }
+
     function getComments ($iId, $iCmtVParentId = 0, $iAuthorId = 0, $sFilter = '', $aOrder = array(), $iStart = 0, $iCount = -1)
     {
     	$aBindings = array(

+ 4 - 1
inc/js/classes/BxDolCmts.js

@@ -18,6 +18,8 @@ function BxDolCmts (options) {
     this._iMinPostForm = undefined == options.iMinPostForm ? 0 : options.iMinPostForm;
     this._sPostFormPosition = undefined == options.sPostFormPosition ? 'top' : options.sPostFormPosition;
     this._sDisplayType = undefined == options.sDisplayType ? 'threaded' : options.sDisplayType;
+    this._iDisplayStructure = undefined == options.iDisplayStructure ? 0 : options.iDisplayStructure;
+
     this._sBrowseType = undefined == options.sBrowseType ? 'tail' : options.sBrowseType;
     this._sBrowseFilter = undefined == options.sBrowseFilter ? 'all' : options.sBrowseFilter;
 
@@ -289,7 +291,8 @@ BxDolCmts.prototype.cmtLoad = function(oLink, iCmtParentId, iStart, iPerView)
 		CmtPerView: iPerView,
 		CmtBrowse: this._sBrowseType,
 		CmtFilter: this._sBrowseFilter,
-		CmtDisplay: this._sDisplayType
+		CmtDisplay: this._sDisplayType,
+                CmtDisplayStructure: this._iDisplayStructure
 	}, function(sListId, sContent) {
 		if(bButton)
 			$this._loadingInButton(oLink, false);

+ 61 - 11
template/scripts/BxBaseCmts.php

@@ -106,6 +106,7 @@ class BxBaseCmts extends BxDolCmts
             'sPostFormPosition' => $this->_aSystem['post_form_position'],
             'sBrowseType' => $this->_sBrowseType,
             'sDisplayType' => $this->_sDisplayType,
+            'iDisplayStructure' => isset($aDp['structure']) && !empty($aDp['structure']) ? 1 : 0,
             'iMinPostForm' => $bMinPostForm ? 1 : 0,
             'sStylePrefix' => $this->_sStylePrefix,
         );
@@ -164,10 +165,10 @@ class BxBaseCmts extends BxDolCmts
 
         $aCmts = $this->getCommentsArray($aBp['vparent_id'], $aBp['filter'], $aBp['order'], $aBp['start'], $aBp['per_view']);
         if(empty($aCmts) || !is_array($aCmts)) {
-        	if((int)$aBp['parent_id'] == 0 && !isLogged())	{
-        		$oPermalink = BxDolPermalinks::getInstance();
-        		return MsgBox(_t('_cmt_msg_login_required', $oPermalink->permalink('page.php?i=login'), $oPermalink->permalink('page.php?i=create-account')));
-        	}
+            if((int)$aBp['parent_id'] == 0 && !isLogged()) {
+                $oPermalink = BxDolPermalinks::getInstance();
+                return MsgBox(_t('_cmt_msg_login_required', $oPermalink->permalink('page.php?i=login'), $oPermalink->permalink('page.php?i=create-account')));
+            }
 
             return isset($aDp['show_empty']) && $aDp['show_empty'] === true ? $this->_getEmpty($aDp) : '';
         }
@@ -180,6 +181,23 @@ class BxBaseCmts extends BxDolCmts
         return $sCmts;
     }
 
+    public function getCommentsByStructure($aBp = array(), $aDp = array())
+    {
+        if(empty($aDp['structure']))
+            return isset($aDp['show_empty']) && $aDp['show_empty'] === true ? $this->_getEmpty($aDp) : '';
+
+        $aBp['count'] = count($aDp['structure']);
+        $this->_prepareParams($aBp, $aDp);
+        $aDp['structure'] = array_slice($aDp['structure'], $aBp['start'], $aBp['per_view'], true);
+
+        $sCmts = '';
+        foreach($aDp['structure'] as $iCmtId => $aCmt)
+            $sCmts .= $this->getComment($iCmtId, $aBp, $aDp);
+
+        $sCmts = $this->_getMoreLink($sCmts, $aBp, $aDp);
+        return $sCmts;
+    }    
+
     /**
      * get comment view block with initializations
      */
@@ -191,6 +209,13 @@ class BxBaseCmts extends BxDolCmts
 
         $aBp = array_merge(array('type' => $this->_sBrowseType), $aBp);
         $aDp = array_merge(array('type' => BX_CMT_DISPLAY_THREADED), $aDp);
+
+        //--- Beg: Using pregenerated structure
+        $mixedStructure = $this->getCommentStructure((int)$iCmtId, $aBp, $aDp);
+        if($mixedStructure !== false)
+            $aDp['structure'] = $mixedStructure;
+        //--- End: Using pregenerated structure
+
         $sComment = $this->getComment($iCmtId, $aBp, $aDp);
         if (!$sComment)
             return '';
@@ -203,7 +228,7 @@ class BxBaseCmts extends BxDolCmts
             'script' => $this->getJsScript($aBp, $aDp)
         ));
     }
-
+    
     /**
      * get one just posted comment
      *
@@ -268,9 +293,17 @@ class BxBaseCmts extends BxDolCmts
         }
 
         $sReplies = '';
-        if((int)$aCmt['cmt_replies'] > 0 && !empty($aDp) && $aDp['type'] == BX_CMT_DISPLAY_THREADED) {
-        	$aDp['show_empty'] = false;
-            $sReplies = $this->getComments(array('parent_id' => $aCmt['cmt_id'], 'vparent_id' => $aCmt['cmt_id'], 'type' => $aBp['type']), $aDp);
+        if(!empty($aDp)) {
+            $aDp['show_empty'] = false;
+
+            if(!empty($aDp['structure'][$aCmt['cmt_id']]) && is_array($aDp['structure'][$aCmt['cmt_id']])) {
+                if(!empty($aDp['structure'][$aCmt['cmt_id']]['items'])) {
+                    $aDp['structure'] = $aDp['structure'][$aCmt['cmt_id']]['items'];
+                    $sReplies = $this->getCommentsByStructure(array('parent_id' => $aCmt['cmt_id'], 'type' => $aBp['type']), $aDp);
+                }
+            } 
+            else if((int)$aCmt['cmt_replies'] > 0 && $aDp['type'] == BX_CMT_DISPLAY_THREADED)
+                $sReplies = $this->getComments(array('parent_id' => $aCmt['cmt_id'], 'vparent_id' => $aCmt['cmt_id'], 'type' => $aBp['type']), $aDp);
         }
 
         $aTmplVarsMeta = array();
@@ -310,6 +343,22 @@ class BxBaseCmts extends BxDolCmts
         ), $this->_getTmplVarsAuthor($aCmt)));
     }
 
+    public function getCommentStructure($iCmtId, $aBp = array(), $aDp = array())
+    {
+        $aRoot = $this->getCommentRow((int)$iCmtId);
+
+        $aBps = $aBp;
+        if(!empty($aRoot))
+            $aBps['parent_id'] = $aRoot['cmt_id'];
+        $this->_prepareStructureBp($aDp['type'], $aBps);
+
+        $iLevel = 0;
+        $aStructure = array();
+        $this->_getStructure($aRoot, $aBps, $iLevel, $aStructure);
+
+        return !empty($aStructure) && is_array($aStructure) ? $aStructure : false;
+    }
+
     function getCommentSearch($iCmtId, &$sAddon)
     {
         $aBp = array();
@@ -1024,7 +1073,8 @@ class BxBaseCmts extends BxDolCmts
                 break;
         }
 
-        $bRoot = (int)$aBp['vparent_id'] <= 0;
+        $sParentKey = isset($aBp['vparent_id']) ? 'vparent_id' : 'parent_id';
+        $bRoot = (int)$aBp[$sParentKey] <= 0;
 
         $sMore = $this->_oTemplate->parseHtmlByName('comment_more.html', array(
             'js_object' => $this->_sJsObjName,
@@ -1033,10 +1083,10 @@ class BxBaseCmts extends BxDolCmts
                 'condition' => $bRoot,
                 'content' => array()
             ),
-            'parent_id' => $aBp['vparent_id'],
+            'parent_id' => $aBp[$sParentKey],
             'start' => $iStart,
             'per_view' => $iPerView,
-            'title' => _t('_cmt_load_more_' . ($aBp['vparent_id'] == 0 ? 'comments' : 'replies') . '_' . $aBp['type'])
+            'title' => _t('_cmt_load_more_' . ($aBp[$sParentKey] == 0 ? 'comments' : 'replies') . '_' . $aBp['type'])
         ));
 
         switch($aBp['type']) {