Advertisement
Guest User

class.categorymodel.php

a guest
Dec 16th, 2011
89
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 42.24 KB | None | 0 0
  1. <?php if (!defined('APPLICATION')) exit();
  2. /*
  3. Copyright 2008, 2009 Vanilla Forums Inc.
  4. This file is part of Garden.
  5. Garden is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
  6. Garden is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  7. You should have received a copy of the GNU General Public License along with Garden.  If not, see <http://www.gnu.org/licenses/>.
  8. Contact Vanilla Forums Inc. at support [at] vanillaforums [dot] com
  9. */
  10. /**
  11.  * Category Model
  12.  *
  13.  * @package Vanilla
  14.  */
  15.  
  16. /**
  17.  * Manages discussion categories.
  18.  *
  19.  * @since 2.0.0
  20.  * @package Vanilla
  21.  */
  22. class CategoryModel extends Gdn_Model {
  23.    const CACHE_KEY = 'Categories';
  24.    
  25.    public $Watching = FALSE;
  26.    public static $Categories = NULL;
  27.  
  28.    /**
  29.     * Class constructor. Defines the related database table name.
  30.     *
  31.     * @since 2.0.0
  32.     * @access public
  33.     */
  34.    public function __construct() {
  35.       parent::__construct('Category');
  36.    }
  37.    
  38.    /**
  39.     *
  40.     *
  41.     * @since 2.0.18
  42.     * @access public
  43.     * @return array Category IDs.
  44.     */
  45.    public static function CategoryWatch() {
  46.       $Categories = self::Categories();
  47.       $AllCount = count($Categories);
  48.      
  49.       $Watch = array();
  50.      
  51.       foreach ($Categories as $CategoryID => $Category) {
  52.          if ($Category['PermsDiscussionsView'] && $Category['Following']) {
  53.             $Watch[] = $CategoryID;
  54.          }
  55.       }
  56.  
  57.       Gdn::PluginManager()->EventArguments['CategoryIDs'] =& $Watch;
  58.       Gdn::PluginManager()->FireEvent('CategoryWatch');
  59.      
  60.       if ($AllCount == count($Watch))
  61.          return TRUE;
  62.  
  63.       return $Watch;
  64.    }
  65.    
  66.    /**
  67.     *
  68.     *
  69.     * @since 2.0.18
  70.     * @access public
  71.     * @param int $ID
  72.     * @return object DataObject
  73.     */
  74.    public static function Categories($ID = FALSE) {
  75.       if (self::$Categories == NULL) {
  76.          // Try and get the categories from the cache.
  77.          $Categories = Gdn::Cache()->Get(self::CACHE_KEY);
  78.          
  79.          if (!$Categories) {
  80.             $Sql = Gdn::SQL();
  81.             $Sql = clone $Sql;
  82.             $Sql->Reset();
  83.             $Session = Gdn::Session();
  84.  
  85.             $Sql->Select('c.*')
  86.                ->Select('lc.DateInserted', '', 'DateLastComment')
  87.                ->From('Category c')
  88.                ->Join('Comment lc', 'c.LastCommentID = lc.CommentID', 'left')
  89.                ->OrderBy('c.TreeLeft');
  90.  
  91.             $Categories = array_merge(array(), $Sql->Get()->ResultArray());
  92.             $Categories = Gdn_DataSet::Index($Categories, 'CategoryID');
  93.             self::CalculateData($Categories);
  94.             Gdn::Cache()->Store(self::CACHE_KEY, $Categories, array(Gdn_Cache::FEATURE_EXPIRY => 600));
  95.          }
  96.          
  97.          self::JoinUserData($Categories, TRUE);
  98.          
  99.          self::$Categories = $Categories;
  100.       }
  101.  
  102.       if ($ID !== FALSE) {
  103.          if (!is_numeric($ID) && $ID) {
  104.             foreach (self::$Categories as $Category) {
  105.                if ($Category['UrlCode'] == $ID)
  106.                   $ID = $Category['CategoryID'];
  107.             }
  108.          }
  109.  
  110.          if (isset(self::$Categories[$ID])) {
  111.             $Result = self::$Categories[$ID];
  112.             return $Result;
  113.          } else {
  114.             return NULL;
  115.          }
  116.       } else {
  117.          $Result = self::$Categories;
  118.          return $Result;
  119.       }
  120.    }
  121.    
  122.    /**
  123.     *
  124.     *
  125.     * @since 2.0.18
  126.     * @access public
  127.     * @param array $Data Dataset.
  128.     * @param string $Column Name of database column.
  129.     * @param array $Options 'Join' key may contain array of columns to join on.
  130.     */
  131.    public static function JoinCategories(&$Data, $Column = 'CategoryID', $Options = array()) {
  132.       $Join = GetValue('Join', $Options, array('Name' => 'Category', 'PermissionCategoryID', 'UrlCode' => 'CategoryUrlCode'));
  133.       foreach ($Data as &$Row) {
  134.          $ID = GetValue($Column, $Row);
  135.          $Category = self::Categories($ID);
  136.          foreach ($Join as $N => $V) {
  137.             if (is_numeric($N))
  138.                $N = $V;
  139.            
  140.             if ($Category)
  141.                $Value = $Category[$N];
  142.             else
  143.                $Value = NULL;
  144.            
  145.             SetValue($V, $Row, $Value);
  146.          }
  147.       }
  148.    }
  149.    
  150.    /**
  151.     *
  152.     *
  153.     * @since 2.0.18
  154.     * @access public
  155.     * @param array $Categories
  156.     * @param bool $AddUserCategory
  157.     */
  158.    public static function JoinUserData(&$Categories, $AddUserCategory = TRUE) {
  159.       if ($AddUserCategory) {
  160.          $SQL = clone Gdn::SQL();
  161.          $SQL->Reset();
  162.          
  163.          if (Gdn::Session()->UserID) {
  164.             $UserData = $SQL->GetWhere('UserCategory', array('UserID' => Gdn::Session()->UserID))->ResultArray();
  165.             $UserData = Gdn_DataSet::Index($UserData, 'CategoryID');
  166.          } else
  167.             $UserData = array();
  168.          
  169.          foreach ($Categories as $ID => $Category) {
  170.             $Row = GetValue($ID, $UserData);
  171.             if ($Row) {
  172.                $Categories[$ID]['UserDateMarkedRead'] = $Row['DateMarkedRead'];
  173.                $Categories[$ID]['Unfollow'] = $Row['Unfollow'];
  174.             } else {
  175.                $Categories[$ID]['UserDateMarkedRead'] = NULL;
  176.                $Categories[$ID]['Unfollow'] = FALSE;
  177.             }
  178.            
  179.             // Calculate the following field.
  180.             $Following = !((bool)GetValue('Archived', $Category) || (bool)GetValue('Unfollow', $Category));
  181.             $Categories[$ID]['Following'] = $Following;
  182.  
  183.             // Calculate the read field.
  184.             if (isset($Category['DateLastComment'])) {
  185.                $DateMarkedRead = GetValue('UserDateMarkedRead', $Category);
  186.                if (!$DateMarkedRead)
  187.                   $DateMarkedRead = GetValue('DateMarkedRead', $Category);
  188.                if ($DateMarkedRead || !GetValue('DateLastComment', $Category))
  189.                   $Categories[$ID]['Read'] = Gdn_Format::ToTimestamp($DateMarkedRead) >= Gdn_Format::ToTimestamp($Category['DateLastComment']);
  190.                else
  191.                   $Categories[$ID]['Read'] = FALSE;
  192.             }
  193.            
  194.          }
  195.       }
  196.      
  197.       // Add permissions.
  198.       $Session = Gdn::Session();
  199.       foreach ($Categories as $CID => $Category) {
  200.          $Categories[$CID]['PermsDiscussionsView'] = $Session->CheckPermission('Vanilla.Discussions.View', TRUE, 'Category', $Category['PermissionCategoryID']);
  201.          $Categories[$CID]['PermsDiscussionsAdd'] = $Session->CheckPermission('Vanilla.Discussions.Add', TRUE, 'Category', $Category['PermissionCategoryID']);
  202.          $Categories[$CID]['PermsDiscussionsEdit'] = $Session->CheckPermission('Vanilla.Discussions.Edit', TRUE, 'Category', $Category['PermissionCategoryID']);
  203.          $Categories[$CID]['PermsCommentsAdd'] = $Session->CheckPermission('Vanilla.Comments.Add', TRUE, 'Category', $Category['PermissionCategoryID']);
  204.       }
  205.      
  206.    }
  207.    
  208.    /**
  209.     * Delete a single category and assign its discussions to another.
  210.     *
  211.     * @since 2.0.0
  212.     * @access public
  213.     *
  214.     * @param object $Category
  215.     * @param int $ReplacementCategoryID Unique ID of category all discussion are being move to.
  216.     */
  217.    public function Delete($Category, $ReplacementCategoryID) {
  218.       // Don't do anything if the required category object & properties are not defined.
  219.       if (
  220.          !is_object($Category)
  221.          || !property_exists($Category, 'CategoryID')
  222.          || !property_exists($Category, 'ParentCategoryID')
  223.          || !property_exists($Category, 'AllowDiscussions')
  224.          || !property_exists($Category, 'Name')
  225.          || $Category->CategoryID <= 0
  226.       ) {
  227.          throw new Exception(T('Invalid category for deletion.'));
  228.       } else {
  229.          // Remove permissions related to category
  230.          $PermissionModel = Gdn::PermissionModel();
  231.          $PermissionModel->Delete(NULL, 'Category', 'CategoryID', $Category->CategoryID);
  232.          
  233.          // If there is a replacement category...
  234.          if ($ReplacementCategoryID > 0) {
  235.             // Update children categories
  236.             $this->SQL
  237.                ->Update('Category')
  238.                ->Set('ParentCategoryID', $ReplacementCategoryID)
  239.                ->Where('ParentCategoryID', $Category->CategoryID)
  240.                ->Put();
  241.  
  242.             // Update permission categories.
  243.             $this->SQL
  244.                ->Update('Category')
  245.                ->Set('PermissionCategoryID', $ReplacementCategoryID)
  246.                ->Where('PermissionCategoryID', $Category->CategoryID)
  247.                ->Where('CategoryID <>', $Category->CategoryID)
  248.                ->Put();
  249.                
  250.             // Update discussions
  251.             $this->SQL
  252.                ->Update('Discussion')
  253.                ->Set('CategoryID', $ReplacementCategoryID)
  254.                ->Where('CategoryID', $Category->CategoryID)
  255.                ->Put();
  256.                
  257.             // Update the discussion count
  258.             $Count = $this->SQL
  259.                ->Select('DiscussionID', 'count', 'DiscussionCount')
  260.                ->From('Discussion')
  261.                ->Where('CategoryID', $ReplacementCategoryID)
  262.                ->Get()
  263.                ->FirstRow()
  264.                ->DiscussionCount;
  265.                
  266.             if (!is_numeric($Count))
  267.                $Count = 0;
  268.                
  269.             $this->SQL
  270.                ->Update('Category')->Set('CountDiscussions', $Count)
  271.                ->Where('CategoryID', $ReplacementCategoryID)
  272.                ->Put();
  273.          } else {
  274.             // Delete comments in this category
  275.             $this->SQL->From('Comment')
  276.                ->Join('Discussion d', 'c.DiscussionID = d.DiscussionID')
  277.                ->Delete('Comment c', array('d.CategoryID' => $Category->CategoryID));
  278.                
  279.             // Delete discussions in this category
  280.             $this->SQL->Delete('Discussion', array('CategoryID' => $Category->CategoryID));
  281.  
  282.             // Make inherited permission local permission
  283.             $this->SQL
  284.                ->Update('Category')
  285.                ->Set('PermissionCategoryID', 0)
  286.                ->Where('PermissionCategoryID', $Category->CategoryID)
  287.                ->Where('CategoryID <>', $Category->CategoryID)
  288.                ->Put();
  289.          }
  290.          
  291.          // Delete the category
  292.          $this->SQL->Delete('Category', array('CategoryID' => $Category->CategoryID));
  293.       }
  294.       // Make sure to reorganize the categories after deletes
  295.       $this->RebuildTree();
  296.    }
  297.      
  298.    /**
  299.     * Get data for a single category selected by Url Code. Disregards permissions.
  300.     *
  301.     * @since 2.0.0
  302.     * @access public
  303.     *
  304.     * @param int $CodeID Unique Url Code of category we're getting data for.
  305.     * @return object SQL results.
  306.     */
  307.    public function GetByCode($Code) {
  308.       return $this->SQL->GetWhere('Category', array('UrlCode' => $Code))->FirstRow();
  309.    }
  310.  
  311.    /**
  312.     * Get data for a single category selected by ID. Disregards permissions.
  313.     *
  314.     * @since 2.0.0
  315.     * @access public
  316.     *
  317.     * @param int $CategoryID Unique ID of category we're getting data for.
  318.     * @return object SQL results.
  319.     */
  320.    public function GetID($CategoryID) {
  321.       return $this->SQL->GetWhere('Category', array('CategoryID' => $CategoryID))->FirstRow();
  322.    }
  323.  
  324.    /**
  325.     * Get list of categories (respecting user permission).
  326.     *
  327.     * @since 2.0.0
  328.     * @access public
  329.     *
  330.     * @param string $OrderFields Ignored.
  331.     * @param string $OrderDirection Ignored.
  332.     * @param int $Limit Ignored.
  333.     * @param int $Offset Ignored.
  334.     * @return Gdn_DataSet SQL results.
  335.     */
  336.    public function Get($OrderFields = '', $OrderDirection = 'asc', $Limit = FALSE, $Offset = FALSE) {
  337.       $this->SQL
  338.          ->Select('c.ParentCategoryID, c.CategoryID, c.TreeLeft, c.TreeRight, c.Depth, c.Name, c.Description, c.CountDiscussions, c.AllowDiscussions, c.UrlCode')
  339.          ->From('Category c')
  340.          ->BeginWhereGroup()
  341.          ->Permission('Vanilla.Discussions.View', 'c', 'PermissionCategoryID', 'Category')
  342.          ->EndWhereGroup()
  343.          ->OrWhere('AllowDiscussions', '0')
  344.          ->OrderBy('TreeLeft', 'asc');
  345.          
  346.          // Note: we are using the Nested Set tree model, so TreeLeft is used for sorting.
  347.          // Ref: http://articles.sitepoint.com/article/hierarchical-data-database/2
  348.          // Ref: http://en.wikipedia.org/wiki/Nested_set_model
  349.          
  350.       $CategoryData = $this->SQL->Get();
  351.       $this->AddCategoryColumns($CategoryData);
  352.       return $CategoryData;
  353.    }
  354.    
  355.    /**
  356.     * Get list of categories (disregarding user permission for admins).
  357.     *
  358.     * @since 2.0.0
  359.     * @access public
  360.     *
  361.     * @param string $OrderFields Ignored.
  362.     * @param string $OrderDirection Ignored.
  363.     * @param int $Limit Ignored.
  364.     * @param int $Offset Ignored.
  365.     * @return object SQL results.
  366.     */
  367.    public function GetAll() {
  368.       $CategoryData = $this->SQL
  369.          ->Select('c.ParentCategoryID, c.CategoryID, c.TreeLeft, c.TreeRight, c.Depth, c.Name, c.Description, c.CountDiscussions, c.CountComments, c.AllowDiscussions, c.UrlCode, c.PermissionCategoryID')
  370.          ->From('Category c')
  371.          ->OrderBy('TreeLeft', 'asc')
  372.          ->Get();
  373.          
  374.       $this->AddCategoryColumns($CategoryData);
  375.       return $CategoryData;
  376.    }
  377.    
  378.    /**
  379.     * Return the number of descendants for a specific category.
  380.     */
  381.    public function GetDescendantCountByCode($Code) {
  382.       $Category = $this->GetByCode($Code);
  383.       if ($Category)
  384.          return round(($Category->TreeRight - $Category->TreeLeft - 1) / 2);
  385.  
  386.       return 0;
  387.    }
  388.  
  389.    /**
  390.     * Get all of the ancestor categories above this one.
  391.     * @param int|string $Category The category ID or url code.
  392.     * @param bool $CheckPermissions Whether or not to only return the categories with view permission.
  393.     * @return array
  394.     */
  395.    public static function GetAncestors($CategoryID, $CheckPermissions = TRUE) {
  396.       $Categories = self::Categories();
  397.       $Result = array();
  398.      
  399.       // Grab the category by ID or url code.
  400.       if (is_numeric($CategoryID)) {
  401.          if (isset($Categories[$CategoryID]))
  402.             $Category = $Categories[$CategoryID];
  403.       } else {
  404.          foreach ($Categories as $ID => $Value) {
  405.             if ($Value['UrlCode'] == $CategoryID) {
  406.                $Category = $Categories[$ID];
  407.                break;
  408.             }
  409.          }
  410.       }
  411.  
  412.       if (!isset($Category))
  413.          return $Result;
  414.  
  415.       // Build up the ancestor array by tracing back through parents.
  416.       $Result[$Category['CategoryID']] = $Category;
  417.       $Max = 20;
  418.       while (isset($Categories[$Category['ParentCategoryID']])) {
  419.          // Check for an infinite loop.
  420.          if ($Max <= 0)
  421.             break;
  422.          $Max--;
  423.          
  424.          if ($CheckPermissions && !$Category['PermsDiscussionsView']) {
  425.             $Category = $Categories[$Category['ParentCategoryID']];
  426.             continue;
  427.          }
  428.          
  429.          if ($Category['CategoryID'] == -1)
  430.             break;
  431.  
  432.          // Return by ID or code.
  433.          if (is_numeric($CategoryID))
  434.             $ID = $Category['CategoryID'];
  435.          else
  436.             $ID = $Category['UrlCode'];
  437.  
  438.          $Result[$ID] = $Category;
  439.  
  440.          $Category = $Categories[$Category['ParentCategoryID']];
  441.       }
  442.       $Result = array_reverse($Result, TRUE); // order for breadcrumbs
  443.       return $Result;
  444.    }
  445.    
  446.    /**
  447.     *
  448.     *
  449.     * @since 2.0.18
  450.     * @acces public
  451.     * @param string $Code Where condition.
  452.     * @return object DataSet
  453.     */
  454.    public function GetDescendantsByCode($Code) {
  455.       Deprecated('CategoryModel::GetDescendantsByCode', 'CategoryModel::GetAncestors');
  456.  
  457.       // SELECT title FROM tree WHERE lft < 4 AND rgt > 5 ORDER BY lft ASC;
  458.       return $this->SQL
  459.          ->Select('c.ParentCategoryID, c.CategoryID, c.TreeLeft, c.TreeRight, c.Depth, c.Name, c.Description, c.CountDiscussions, c.CountComments, c.AllowDiscussions, c.UrlCode')
  460.          ->From('Category c')
  461.          ->Join('Category d', 'c.TreeLeft < d.TreeLeft and c.TreeRight > d.TreeRight')
  462.          ->Where('d.UrlCode', $Code)
  463.          ->OrderBy('c.TreeLeft', 'asc')
  464.          ->Get();
  465.    }
  466.  
  467.    /**
  468.     *
  469.     *
  470.     * @since 2.0.18
  471.     * @acces public
  472.     * @param int $ID
  473.     * @return array
  474.     */
  475.    public static function GetSubtree($ID) {
  476.       $Result = array();
  477.       $Category = self::Categories($ID);
  478.       if ($Category) {
  479.          $Result[$Category['CategoryID']] = $Category;
  480.          $ChildIDs = GetValue('ChildIDs', $Category);
  481.          
  482.          foreach ($ChildIDs as $ChildID) {
  483.             $Result = array_merge($Result, self::GetSubtree($ChildID));
  484.          }
  485.       }
  486.       return $Result;
  487.    }
  488.  
  489.    /**
  490.     * Get full data for a single category or all categories. Respects Permissions.
  491.     *
  492.     * If no CategoryID is provided, it gets all categories.
  493.     *
  494.     * @since 2.0.0
  495.     * @access public
  496.     *
  497.     * @param int $CategoryID Unique ID of category to return.
  498.     * @param string $Permissions Permission to check.
  499.     * @return object SQL results.
  500.     */
  501.    public function GetFull($CategoryID = '', $Permissions = FALSE) {
  502.       // Minimally check for view discussion permission
  503.       if (!$Permissions)
  504.          $Permissions = 'Vanilla.Discussions.View';
  505.  
  506.       // Get the category IDs.
  507.       if ($Permissions == 'Vanilla.Discussions.View') {
  508.          if ($this->Watching)
  509.             $CategoryIDs = self::CategoryWatch();
  510.          else
  511.             $CategoryIDs = DiscussionModel::CategoryPermissions();
  512.          if ($CategoryIDs !== TRUE)
  513.             $this->SQL->WhereIn('c.CategoryID', $CategoryIDs);
  514.       } else {
  515.          $this->SQL->Permission($Permissions, 'c', 'PermissionCategoryID', 'Category');
  516.       }
  517.  
  518.       // Build base query
  519.       $this->SQL
  520.          ->Select('c.*')
  521.          ->Select('co.DateInserted', '', 'DateLastComment')
  522.          ->Select('co.InsertUserID', '', 'LastCommentUserID')
  523.          ->Select('d.Name', '', 'LastDiscussionTitle')
  524.          ->Select('d.CountComments', '', 'LastDiscussionCountComments')
  525.          ->Select('d.InsertUserID', '', 'LastDiscussionUserID')
  526.          ->Select('d.DateInserted', '', 'DateLastDiscussion')
  527.          ->From('Category c')
  528.          ->Join('Comment co', 'c.LastCommentID = co.CommentID', 'left')
  529.          ->Join('Discussion d', 'd.DiscussionID = c.LastDiscussionID', 'left')
  530.          ->Where('c.AllowDiscussions', '1');
  531.  
  532.       $this->FireEvent('AfterGetFullQuery');
  533.      
  534.       if (Gdn::Session()->UserID > 0) {
  535.          $UserID = Gdn::Session()->UserID;
  536.          // Add in user/category stuff.
  537.          $this->SQL
  538.             ->Join('UserCategory uc', "uc.UserID = $UserID and uc.CategoryID = c.CategoryID", 'left')
  539.             ->Select('uc.DateMarkedRead')
  540.             ->Select('uc.Unfollow');
  541.       }
  542.  
  543.       // Single record or full list?
  544.       if (is_numeric($CategoryID) && $CategoryID != 0) {
  545.          return $this->SQL->Where('c.CategoryID', $CategoryID)->Get()->FirstRow();
  546.       } else {
  547.          $CategoryData = $this->SQL->OrderBy('TreeLeft', 'asc')->Get();
  548.          $this->AddCategoryColumns($CategoryData);
  549.          Gdn::UserModel()->JoinUsers($CategoryData, array('LastCommentUserID', 'LastDiscussionUserID'));
  550.          return $CategoryData;
  551.       }
  552.    }
  553.    
  554.    /**
  555.     * Get full data for a single category by its URL slug. Respects permissions.
  556.     *
  557.     * @since 2.0.0
  558.     * @access public
  559.     *
  560.     * @param string $UrlCode Unique category slug from URL.
  561.     * @return object SQL results.
  562.     */
  563.    public function GetFullByUrlCode($UrlCode) {
  564.       $Data = (object)self::Categories($UrlCode);
  565.  
  566.       // Check to see if the user has permission for this category.
  567.       // Get the category IDs.
  568.       $CategoryIDs = DiscussionModel::CategoryPermissions();
  569.       if (is_array($CategoryIDs) && !in_array(GetValue('CategoryID', $Data), $CategoryIDs))
  570.          $Data = FALSE;
  571.       return $Data;
  572.    }
  573.    
  574.    /**
  575.     * Check whether category has any children categories.
  576.     *
  577.     * @since 2.0.0
  578.     * @access public
  579.     *
  580.     * @param string $CategoryID Unique ID for category being checked.
  581.     * @return bool
  582.     */
  583.    public function HasChildren($CategoryID) {
  584.       $ChildData = $this->SQL
  585.          ->Select('CategoryID')
  586.          ->From('Category')
  587.          ->Where('ParentCategoryID', $CategoryID)
  588.          ->Get();
  589.       return $ChildData->NumRows() > 0 ? TRUE : FALSE;
  590.    }
  591.    
  592.    /**
  593.     *
  594.     *  
  595.     * @since 2.0.0
  596.     * @access public
  597.     * @param array $Data
  598.     * @param string $Permission
  599.     * @param string $Column
  600.     */
  601.    public static function JoinModerators($Data, $Permission = 'Vanilla.Comments.Edit', $Column = 'Moderators') {
  602.       $Moderators = Gdn::SQL()
  603.          ->Select('u.UserID, u.Name, u.Photo, u.Email')
  604.          ->Select('p.JunctionID as CategoryID')
  605.          ->From('User u')
  606.          ->Join('UserRole ur', 'ur.UserID = u.UserID')
  607.          ->Join('Permission p', 'ur.RoleID = p.RoleID')
  608.          ->Where('`'.$Permission.'`', 1)
  609.          ->Get()->ResultArray();
  610.  
  611.       $Moderators = Gdn_DataSet::Index($Moderators, 'CategoryID', array('Unique' => FALSE));
  612.  
  613.       foreach ($Data as &$Category) {
  614.          $ID = GetValue('PermissionCategoryID', $Category);
  615.          $Mods = GetValue($ID, $Moderators, array());
  616.          $ModIDs = array();
  617.          $UniqueMods = array();
  618.          foreach ($Mods as $Mod) {
  619.             if (!in_array($Mod['UserID'], $ModIDs)) {
  620.                $ModIDs[] = $Mod['UserID'];
  621.                $UniqueMods[] = $Mod;
  622.             }
  623.            
  624.          }
  625.          SetValue($Column, $Category, $UniqueMods);
  626.       }
  627.    }
  628.    
  629.    /**
  630.     * Rebuilds the category tree. We are using the Nested Set tree model.
  631.     *
  632.     * @ref http://articles.sitepoint.com/article/hierarchical-data-database/2
  633.     * @ref http://en.wikipedia.org/wiki/Nested_set_model
  634.     *  
  635.     * @since 2.0.0
  636.     * @access public
  637.     */
  638.    public function RebuildTree() {
  639.       // Grab all of the categories.
  640.       $Categories = $this->SQL->Get('Category', 'TreeLeft, Sort, Name');
  641.       $Categories = Gdn_DataSet::Index($Categories->ResultArray(), 'CategoryID');
  642.  
  643.       // Make sure the tree has a root.
  644.       if (!isset($Categories[-1])) {
  645.          $RootCat = array('CategoryID' => -1, 'TreeLeft' => 1, 'TreeRight' => 4, 'Depth' => 0, 'InsertUserID' => 1, 'UpdateUserID' => 1, 'DateInserted' => Gdn_Format::ToDateTime(), 'DateUpdated' => Gdn_Format::ToDateTime(), 'Name' => 'Root', 'UrlCode' => '', 'Description' => 'Root of category tree. Users should never see this.', 'PermissionCategoryID' => -1, 'Sort' => 0, 'ParentCategoryID' => NULL);
  646.          $Categories[-1] = $RootCat;
  647.          $this->SQL->Insert('Category', $RootCat);
  648.       }
  649.  
  650.       // Build a tree structure out of the categories.
  651.       $Root = NULL;
  652.       foreach ($Categories as &$Cat) {
  653.          if (!isset($Cat['CategoryID']))
  654.             continue;
  655.          
  656.          // Backup category settings for efficient database saving.
  657.          try {
  658.             $Cat['_TreeLeft'] = $Cat['TreeLeft'];
  659.             $Cat['_TreeRight'] = $Cat['TreeRight'];
  660.             $Cat['_Depth'] = $Cat['Depth'];
  661.             $Cat['_PermissionCategoryID'] = $Cat['PermissionCategoryID'];
  662.             $Cat['_ParentCategoryID'] = $Cat['ParentCategoryID'];
  663.          } catch (Exception $Ex) {
  664.             $Foo = 'Bar';
  665.          }
  666.  
  667.          if ($Cat['CategoryID'] == -1) {
  668.             $Root =& $Cat;
  669.             continue;
  670.          }
  671.  
  672.          $ParentID = $Cat['ParentCategoryID'];
  673.          if (!$ParentID) {
  674.             $ParentID = -1;
  675.             $Cat['ParentCategoryID'] = $ParentID;
  676.          }
  677.          if (!isset($Categories[$ParentID]['Children']))
  678.             $Categories[$ParentID]['Children'] = array();
  679.          $Categories[$ParentID]['Children'][] =& $Cat;
  680.       }
  681.       unset($Cat);
  682.  
  683.       // Set the tree attributes of the tree.
  684.       $this->_SetTree($Root);
  685.       unset($Root);
  686.  
  687.       // Save the tree structure.
  688.       foreach ($Categories as $Cat) {
  689.          if (!isset($Cat['CategoryID']))
  690.             continue;
  691.          if ($Cat['_TreeLeft'] != $Cat['TreeLeft'] || $Cat['_TreeRight'] != $Cat['TreeRight'] || $Cat['_Depth'] != $Cat['Depth'] || $Cat['PermissionCategoryID'] != $Cat['PermissionCategoryID'] || $Cat['_ParentCategoryID'] != $Cat['ParentCategoryID'] || $Cat['Sort'] != $Cat['TreeLeft']) {
  692.             $this->SQL->Put('Category',
  693.                array('TreeLeft' => $Cat['TreeLeft'], 'TreeRight' => $Cat['TreeRight'], 'Depth' => $Cat['Depth'], 'PermissionCategoryID' => $Cat['PermissionCategoryID'], 'ParentCategoryID' => $Cat['ParentCategoryID'], 'Sort' => $Cat['TreeLeft']),
  694.                array('CategoryID' => $Cat['CategoryID']));
  695.          }
  696.       }
  697.       $this->SetCache();
  698.    }
  699.    
  700.    /**
  701.     *
  702.     *
  703.     * @since 2.0.18
  704.     * @access protected
  705.     * @param array $Node
  706.     * @param int $Left
  707.     * @param int $Depth
  708.     */
  709.    protected function _SetTree(&$Node, $Left = 1, $Depth = 0) {
  710.       $Right = $Left + 1;
  711.      
  712.       if (isset($Node['Children'])) {
  713.          foreach ($Node['Children'] as &$Child) {
  714.             $Right = $this->_SetTree($Child, $Right, $Depth + 1);
  715.             $Child['ParentCategoryID'] = $Node['CategoryID'];
  716.             if ($Child['PermissionCategoryID'] != $Child['CategoryID']) {
  717.                $Child['PermissionCategoryID'] = GetValue('PermissionCategoryID', $Node, $Child['CategoryID']);
  718.             }
  719.          }
  720.          unset($Node['Children']);
  721.       }
  722.  
  723.       $Node['TreeLeft'] = $Left;
  724.       $Node['TreeRight'] = $Right;
  725.       $Node['Depth'] = $Depth;
  726.  
  727.       return $Right + 1;
  728.    }
  729.    
  730.    /**
  731.     * Saves the category tree based on a provided tree array. We are using the
  732.     * Nested Set tree model.
  733.     *
  734.     * @ref http://articles.sitepoint.com/article/hierarchical-data-database/2
  735.     * @ref http://en.wikipedia.org/wiki/Nested_set_model
  736.     *
  737.     * @since 2.0.16
  738.     * @access public
  739.     *
  740.     * @param array $TreeArray A fully defined nested set model of the category tree.
  741.     */
  742.    public function SaveTree($TreeArray) {
  743.       /*
  744.         TreeArray comes in the format:
  745.       '0' ...
  746.         'item_id' => "root"
  747.         'parent_id' => "none"
  748.         'depth' => "0"
  749.         'left' => "1"
  750.         'right' => "34"
  751.       '1' ...
  752.         'item_id' => "1"
  753.         'parent_id' => "root"
  754.         'depth' => "1"
  755.         'left' => "2"
  756.         'right' => "3"
  757.       etc...
  758.       */
  759.  
  760.       // Grab all of the categories so that permissions can be properly saved.
  761.       $PermTree = $this->SQL->Select('CategoryID, PermissionCategoryID, TreeLeft, TreeRight, Depth, Sort, ParentCategoryID')->From('Category')->Get();
  762.       $PermTree = $PermTree->Index($PermTree->ResultArray(), 'CategoryID');
  763.  
  764.       // The tree must be walked in order for the permissions to save properly.
  765.       usort($TreeArray, array('CategoryModel', '_TreeSort'));
  766.      
  767.       foreach($TreeArray as $I => $Node) {
  768.          $CategoryID = GetValue('item_id', $Node);
  769.          if ($CategoryID == 'root')
  770.             $CategoryID = -1;
  771.            
  772.          $ParentCategoryID = GetValue('parent_id', $Node);
  773.          if (in_array($ParentCategoryID, array('root', 'none')))
  774.             $ParentCategoryID = -1;
  775.  
  776.          $PermissionCategoryID = GetValueR("$CategoryID.PermissionCategoryID", $PermTree, 0);
  777.          $PermCatChanged = FALSE;
  778.          if ($PermissionCategoryID != $CategoryID) {
  779.             // This category does not have custom permissions so must inherit its parent's permissions.
  780.             $PermissionCategoryID = GetValueR("$ParentCategoryID.PermissionCategoryID", $PermTree, 0);
  781.             if ($CategoryID != -1 && !GetValueR("$ParentCategoryID.Touched", $PermTree)) {
  782.                $Foo = 'Bar';
  783.                throw new Exception("Category $ParentCategoryID not touched before touching $CategoryID.");
  784.             }
  785.             if ($PermTree[$CategoryID]['PermissionCategoryID'] != $PermissionCategoryID)
  786.                $PermCatChanged = TRUE;
  787.             $PermTree[$CategoryID]['PermissionCategoryID'] = $PermissionCategoryID;
  788.          }
  789.          $PermTree[$CategoryID]['Touched'] = TRUE;
  790.  
  791.          // Only update if the tree doesn't match the database.
  792.          $Row = $PermTree[$CategoryID];
  793.          if ($Node['left'] != $Row['TreeLeft'] || $Node['right'] != $Row['TreeRight'] || $Node['depth'] != $Row['Depth'] || $ParentCategoryID != $Row['ParentCategoryID'] || $Node['left'] != $Row['Sort'] || $PermCatChanged) {
  794.            
  795.             $this->SQL->Update(
  796.                'Category',
  797.                array(
  798.                   'TreeLeft' => $Node['left'],
  799.                   'TreeRight' => $Node['right'],
  800.                   'Depth' => $Node['depth'],
  801.                   'Sort' => $Node['left'],
  802.                   'ParentCategoryID' => $ParentCategoryID,
  803.                   'PermissionCategoryID' => $PermissionCategoryID
  804.                ),
  805.                array('CategoryID' => $CategoryID)
  806.             )->Put();
  807.          }
  808.       }
  809.    }
  810.    
  811.    /**
  812.     * Utility method for sorting via usort.
  813.     *
  814.     * @since 2.0.18
  815.     * @access protected
  816.     * @param $A First element to compare.
  817.     * @param $B Second element to compare.
  818.     * @return int -1, 1, 0 (per usort)
  819.     */
  820.    protected function _TreeSort($A, $B) {
  821.       if ($A['left'] > $B['left'])
  822.          return 1;
  823.       elseif ($A['left'] < $B['left'])
  824.          return -1;
  825.       else
  826.          return 0;
  827.    }
  828.    
  829.    /**
  830.     * Saves the category.
  831.     *
  832.     * @since 2.0.0
  833.     * @access public
  834.     *
  835.     * @param array $FormPostValue The values being posted back from the form.
  836.     * @return int ID of the saved category.
  837.     */
  838.    public function Save($FormPostValues) {
  839.       // Define the primary key in this model's table.
  840.       $this->DefineSchema();
  841.      
  842.       // Get data from form
  843.       $CategoryID = ArrayValue('CategoryID', $FormPostValues);
  844.       $NewName = ArrayValue('Name', $FormPostValues, '');
  845.       $UrlCode = ArrayValue('UrlCode', $FormPostValues, '');
  846.       $AllowDiscussions = ArrayValue('AllowDiscussions', $FormPostValues, '');
  847.       $CustomPermissions = (bool)GetValue('CustomPermissions', $FormPostValues);
  848.      
  849.       // Is this a new category?
  850.       $Insert = $CategoryID > 0 ? FALSE : TRUE;
  851.       if ($Insert)
  852.          $this->AddInsertFields($FormPostValues);              
  853.  
  854.       $this->AddUpdateFields($FormPostValues);
  855.       $this->Validation->ApplyRule('UrlCode', 'Required');
  856.       $this->Validation->ApplyRule('UrlCode', 'UrlStringRelaxed');
  857.  
  858.       // Make sure that the UrlCode is unique among categories.
  859.       $this->SQL->Select('CategoryID')
  860.          ->From('Category')
  861.          ->Where('UrlCode', $UrlCode);
  862.  
  863.       if ($CategoryID)
  864.          $this->SQL->Where('CategoryID <>', $CategoryID);
  865.  
  866.       if ($this->SQL->Get()->NumRows())
  867.          $this->Validation->AddValidationResult('UrlCode', 'The specified url code is already in use by another category.');
  868.  
  869.         //  Prep and fire event.
  870.         $this->EventArguments['FormPostValues'] = &$FormPostValues;
  871.         $this->EventArguments['CategoryID'] = $CategoryID;
  872.         $this->FireEvent('BeforeSaveCategory');
  873.      
  874.       // Validate the form posted values
  875.       if ($this->Validate($FormPostValues, $Insert)) {
  876.          $Fields = $this->Validation->SchemaValidationFields();
  877.          $Fields = RemoveKeyFromArray($Fields, 'CategoryID');
  878.          $AllowDiscussions = ArrayValue('AllowDiscussions', $Fields) == '1' ? TRUE : FALSE;
  879.          $Fields['AllowDiscussions'] = $AllowDiscussions ? '1' : '0';
  880.  
  881.          if ($Insert === FALSE) {
  882.             $OldCategory = $this->GetID($CategoryID);
  883.             $AllowDiscussions = $OldCategory->AllowDiscussions; // Force the allowdiscussions property
  884.             $Fields['AllowDiscussions'] = $AllowDiscussions ? '1' : '0';
  885.             $this->Update($Fields, array('CategoryID' => $CategoryID));
  886.             $this->SetCache($CategoryID, $Fields);
  887.          } else {
  888.             $CategoryID = $this->Insert($Fields);
  889.  
  890.             if ($CustomPermissions && $CategoryID) {
  891.                $this->SQL->Put('Category', array('PermissionCategoryID' => $CategoryID), array('CategoryID' => $CategoryID));
  892.             }
  893.  
  894.             $this->RebuildTree(); // Safeguard to make sure that treeleft and treeright cols are added
  895.          }
  896.          
  897.          // Save the permissions
  898.          if ($AllowDiscussions && $CategoryID) {
  899.             // Check to see if this category uses custom permissions.
  900.             if ($CustomPermissions) {
  901.                $PermissionModel = Gdn::PermissionModel();
  902.                $Permissions = $PermissionModel->PivotPermissions(GetValue('Permission', $FormPostValues, array()), array('JunctionID' => $CategoryID));
  903.             $PermissionModel->SaveAll($Permissions, array('JunctionID' => $CategoryID, 'JunctionTable' => 'Category'));
  904.  
  905.                if (!$Insert) {
  906.                   // Figure out my last permission and tree info.
  907.                   $Data = $this->SQL->Select('PermissionCategoryID, TreeLeft, TreeRight')->From('Category')->Where('CategoryID', $CategoryID)->Get()->FirstRow(DATASET_TYPE_ARRAY);
  908.  
  909.                   // Update this category's permission.
  910.                   $this->SQL->Put('Category', array('PermissionCategoryID' => $CategoryID), array('CategoryID' => $CategoryID));
  911.  
  912.                   // Update all of my children that shared my last category permission.
  913.                   $this->SQL->Put('Category',
  914.                      array('PermissionCategoryID' => $CategoryID),
  915.                      array('TreeLeft >' => $Data['TreeLeft'], 'TreeRight <' => $Data['TreeRight'], 'PermissionCategoryID' => $Data['PermissionCategoryID']));
  916.                }
  917.             } elseif (!$Insert) {
  918.                // Figure out my parent's permission.
  919.                $NewPermissionID = $this->SQL
  920.                   ->Select('p.PermissionCategoryID')
  921.                   ->From('Category c')
  922.                   ->Join('Category p', 'c.ParentCategoryID = p.CategoryID')
  923.                   ->Where('c.CategoryID', $CategoryID)
  924.                   ->Get()->Value('PermissionCategoryID', 0);
  925.  
  926.                if ($NewPermissionID != $CategoryID) {
  927.                   // Update all of my children that shared my last permission.
  928.                   $this->SQL->Put('Category',
  929.                      array('PermissionCategoryID' => $NewPermissionID),
  930.                      array('PermissionCategoryID' => $CategoryID));
  931.                }
  932.  
  933.                // Delete my custom permissions.
  934.                $this->SQL->Delete('Permission',
  935.                   array('JunctionTable' => 'Category', 'JunctionColumn' => 'PermissionCategoryID', 'JunctionID' => $CategoryID));
  936.             }
  937.          }
  938.          
  939.          // Force the user permissions to refresh.
  940.          Gdn::UserModel()->ClearPermissions();
  941.          
  942.          // $this->RebuildTree();
  943.       } else {
  944.          $CategoryID = FALSE;
  945.       }
  946.      
  947.       return $CategoryID;
  948.    }
  949.    
  950.    /**
  951.     * Grab the Category IDs of the tree.
  952.     *
  953.     * @since 2.0.18
  954.     * @access public
  955.     * @param int $CategoryID
  956.     * @param mixed $Set
  957.     */
  958.    public function SaveUserTree($CategoryID, $Set) {
  959.       $Categories = $this->GetSubtree($CategoryID);
  960.       foreach ($Categories as $Category) {
  961.          $this->SQL->Replace(
  962.             'UserCategory',
  963.             $Set,
  964.             array('UserID' => Gdn::Session()->UserID, 'CategoryID' => $Category['CategoryID']));
  965.       }
  966.    }
  967.    
  968.    /**
  969.     * Grab the categories from the cache.
  970.     *
  971.     * @since 2.0.18
  972.     * @access public
  973.     * @param int $ID
  974.     * @param array $Data
  975.     */
  976.    public static function SetCache($ID = FALSE, $Data = FALSE) {
  977.       $Categories = Gdn::Cache()->Get(self::CACHE_KEY);
  978.       self::$Categories = NULL;
  979.      
  980.       if (!$Categories)
  981.          return;
  982.      
  983.       if (!$ID) {
  984.          Gdn::Cache()->Remove(self::CACHE_KEY);
  985.          return;
  986.       }
  987.      
  988.       if (!array_key_exists($ID, $Categories)) {
  989.          Gdn::Cache()->Remove(self::CACHE_KEY);
  990.          return;
  991.       }
  992.      
  993.       $Category = $Categories[$ID];
  994.       $Category = array_merge($Category, $Data);
  995.       $Categories[$ID] = $Category;
  996.       Gdn::Cache()->Store(self::CACHE_KEY, $Categories, array(Gdn_Cache::FEATURE_EXPIRY => 600));
  997.    }
  998.    
  999.    public function SetField($ID, $Property, $Value = FALSE) {
  1000.       if (!is_array($Property))
  1001.          $Property = array($Property => $Value);
  1002.      
  1003.       $this->SQL->Put($this->Name, $Property, array('CategoryID' => $ID));
  1004.      
  1005.       // Set the cache.
  1006.       self::SetCache($ID, $Property);
  1007.  
  1008.         return $Property;
  1009.    }
  1010.    
  1011.    /**
  1012.     * If looking at the root node, make sure it exists and that the
  1013.     * nested set columns exist in the table.
  1014.     *
  1015.     * @since 2.0.15
  1016.     * @access public
  1017.     */
  1018.    public function ApplyUpdates() {
  1019.       if (!C('Vanilla.NestedCategoriesUpdate')) {
  1020.          // Add new columns
  1021.          $Construct = Gdn::Database()->Structure();
  1022.          $Construct->Table('Category')
  1023.             ->Column('TreeLeft', 'int', TRUE)
  1024.             ->Column('TreeRight', 'int', TRUE)
  1025.             ->Column('Depth', 'int', TRUE)
  1026.             ->Column('CountComments', 'int', '0')
  1027.             ->Column('LastCommentID', 'int', TRUE)
  1028.             ->Set(0, 0);
  1029.  
  1030.          // Insert the root node
  1031.          if ($this->SQL->GetWhere('Category', array('CategoryID' => -1))->NumRows() == 0)
  1032.             $this->SQL->Insert('Category', array('CategoryID' => -1, 'TreeLeft' => 1, 'TreeRight' => 4, 'Depth' => 0, 'InsertUserID' => 1, 'UpdateUserID' => 1, 'DateInserted' => Gdn_Format::ToDateTime(), 'DateUpdated' => Gdn_Format::ToDateTime(), 'Name' => 'Root', 'UrlCode' => '', 'Description' => 'Root of category tree. Users should never see this.'));
  1033.          
  1034.          // Build up the TreeLeft & TreeRight values.
  1035.          $this->RebuildTree();
  1036.          
  1037.          SaveToConfig('Vanilla.NestedCategoriesUpdate', 1);
  1038.       }
  1039.    }
  1040.    
  1041.     /**
  1042.     * Modifies category data before it is returned.
  1043.     *
  1044.     * Adds CountAllDiscussions column to each category representing the sum of
  1045.     * discussions within this category as well as all subcategories.
  1046.     *
  1047.     * @since 2.0.17
  1048.     * @access public
  1049.     *
  1050.     * @param object $Data SQL result.
  1051.     */
  1052.     public static function AddCategoryColumns($Data) {
  1053.         $Result = &$Data->Result();
  1054.       $Result2 = $Result;
  1055.         foreach ($Result as &$Category) {
  1056.          if (!property_exists($Category, 'CountAllDiscussions'))
  1057.             $Category->CountAllDiscussions = $Category->CountDiscussions;
  1058.            
  1059.          if (!property_exists($Category, 'CountAllComments'))
  1060.             $Category->CountAllComments = $Category->CountComments;
  1061.  
  1062.          // Calculate the following field.
  1063.          $Following = !((bool)GetValue('Archived', $Category) || (bool)GetValue('Unfollow', $Category));
  1064.          $Category->Following = $Following;
  1065.  
  1066.          // Calculate the read field.
  1067.          if (property_exists($Category, 'DateLastComment')) {
  1068.             $DateMarkedRead = GetValue('UserDateMarkedRead', $Category);
  1069.             if (!$DateMarkedRead)
  1070.                $DateMarkedRead = GetValue('DateMarkedRead', $Category);
  1071.             if ($DateMarkedRead || !GetValue('DateLastComment', $Category))
  1072.                $Category->Read = Gdn_Format::ToTimestamp($DateMarkedRead) >= Gdn_Format::ToTimestamp($Category->DateLastComment);
  1073.             else
  1074.                $Category->Read = FALSE;
  1075.          }
  1076.          
  1077.          if (GetValue('LastCommentUserID', $Category) == NULL) {
  1078.             SetValue('LastCommentUserID', $Category, GetValue('LastDiscussionUserID', $Category, NULL));
  1079.             SetValue('DateLastComment', $Category, GetValue('DateLastDiscussion', $Category, NULL));
  1080.          }
  1081.  
  1082.          foreach ($Result2 as $Category2) {
  1083.             if ($Category2->TreeLeft > $Category->TreeLeft && $Category2->TreeRight < $Category->TreeRight) {
  1084.                $Category->CountAllDiscussions += $Category2->CountDiscussions;
  1085.                $Category->CountAllComments += $Category2->CountComments;
  1086.             }
  1087.          }
  1088.         }
  1089.     }
  1090.  
  1091.     /**
  1092.     * Get category subtree ids (respecting user permission).
  1093.     *
  1094.     * @access public
  1095.     *
  1096.     * @param string $CategoryID the root of the subtree.
  1097.     * @return Gdn_DataSet SQL results.
  1098.     */
  1099.    public function GetSubTreeIds($CategoryID) {
  1100.       $mainCat = $this->GetID($CategoryID);
  1101.       if(!$mainCat){
  1102.         //Category not found
  1103.         return array();
  1104.       }
  1105.       elseif ($mainCat->TreeLeft+1 >= $mainCat->TreeRight){
  1106.         //Category is leaf
  1107.         return array($mainCat->CategoryID);
  1108.       }
  1109.       else{
  1110.          $this->SQL
  1111.          ->Select('c.CategoryID')
  1112.          ->From('Category c')
  1113.          ->BeginWhereGroup()
  1114.          ->Where('c.TreeLeft >=', $mainCat->TreeLeft)
  1115.          ->Where('c.TreeRight <=', $mainCat->TreeRight)
  1116.          ->Permission('Vanilla.Discussions.View', 'c', 'PermissionCategoryID', 'Category')
  1117.          ->EndWhereGroup()
  1118.          ->OrWhere('AllowDiscussions', '0')
  1119.          ->OrderBy('TreeLeft', 'asc');
  1120.          $subTreeQuery = $this->SQL->Get();
  1121.          $subTree = $subTreeQuery->ResultArray();
  1122.          for($i = 0; $i < count($subTree); $i++){
  1123.             $subTree[$i] = $subTree[$i]['CategoryID'];
  1124.          }
  1125.          return $subTree;
  1126.       }
  1127.    }
  1128.  
  1129.  
  1130.    /**
  1131.     *
  1132.     *
  1133.     * @since 2.0.18
  1134.     * @access public
  1135.     * @param array $Data Dataset.
  1136.     */
  1137.    protected static function CalculateData(&$Data) {
  1138.         foreach ($Data as &$Category) {
  1139.          $Category['CountAllDiscussions'] = $Category['CountDiscussions'];
  1140.          $Category['CountAllComments'] = $Category['CountComments'];
  1141.          $Category['Url'] = '/categories/'.rawurlencode($Category['UrlCode']);
  1142.          $Category['ChildIDs'] = array();
  1143.         }
  1144.      
  1145.       $Keys = array_reverse(array_keys($Data));
  1146.       foreach ($Keys as $Key) {
  1147.          $Cat = $Data[$Key];
  1148.          $ParentID = $Cat['ParentCategoryID'];
  1149.  
  1150.          if (isset($Data[$ParentID]) && $ParentID != $Key) {
  1151.             $Data[$ParentID]['CountAllDiscussions'] += $Cat['CountAllDiscussions'];
  1152.             $Data[$ParentID]['CountAllComments'] += $Cat['CountAllComments'];
  1153.             $Data[$ParentID]['ChildIDs'][] = $Key;
  1154.          }
  1155.       }
  1156.     }
  1157.    
  1158. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement