1<?php 2/** 3 * Joomla! Content Management System 4 * 5 * @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All rights reserved. 6 * @license GNU General Public License version 2 or later; see LICENSE.txt 7 */ 8 9namespace Joomla\CMS\Table; 10 11defined('JPATH_PLATFORM') or die; 12 13/** 14 * Table class supporting modified pre-order tree traversal behavior. 15 * 16 * @since 1.7.0 17 */ 18class Asset extends Nested 19{ 20 /** 21 * The primary key of the asset. 22 * 23 * @var integer 24 * @since 1.7.0 25 */ 26 public $id = null; 27 28 /** 29 * The unique name of the asset. 30 * 31 * @var string 32 * @since 1.7.0 33 */ 34 public $name = null; 35 36 /** 37 * The human readable title of the asset. 38 * 39 * @var string 40 * @since 1.7.0 41 */ 42 public $title = null; 43 44 /** 45 * The rules for the asset stored in a JSON string 46 * 47 * @var string 48 * @since 1.7.0 49 */ 50 public $rules = null; 51 52 /** 53 * Constructor 54 * 55 * @param \JDatabaseDriver $db Database driver object. 56 * 57 * @since 1.7.0 58 */ 59 public function __construct($db) 60 { 61 parent::__construct('#__assets', 'id', $db); 62 } 63 64 /** 65 * Method to load an asset by its name. 66 * 67 * @param string $name The name of the asset. 68 * 69 * @return integer 70 * 71 * @since 1.7.0 72 */ 73 public function loadByName($name) 74 { 75 return $this->load(array('name' => $name)); 76 } 77 78 /** 79 * Assert that the nested set data is valid. 80 * 81 * @return boolean True if the instance is sane and able to be stored in the database. 82 * 83 * @since 1.7.0 84 */ 85 public function check() 86 { 87 $this->parent_id = (int) $this->parent_id; 88 89 if (empty($this->rules)) 90 { 91 $this->rules = '{}'; 92 } 93 94 // Nested does not allow parent_id = 0, override this. 95 if ($this->parent_id > 0) 96 { 97 // Get the \JDatabaseQuery object 98 $query = $this->_db->getQuery(true) 99 ->select('1') 100 ->from($this->_db->quoteName($this->_tbl)) 101 ->where($this->_db->quoteName('id') . ' = ' . $this->parent_id); 102 103 if ($this->_db->setQuery($query, 0, 1)->loadResult()) 104 { 105 return true; 106 } 107 108 $this->setError(\JText::_('JLIB_DATABASE_ERROR_INVALID_PARENT_ID')); 109 110 return false; 111 } 112 113 return true; 114 } 115 116 /** 117 * Method to recursively rebuild the whole nested set tree. 118 * 119 * @param integer $parentId The root of the tree to rebuild. 120 * @param integer $leftId The left id to start with in building the tree. 121 * @param integer $level The level to assign to the current nodes. 122 * @param string $path The path to the current nodes. 123 * 124 * @return integer 1 + value of root rgt on success, false on failure 125 * 126 * @since 3.5 127 * @throws \RuntimeException on database error. 128 */ 129 public function rebuild($parentId = null, $leftId = 0, $level = 0, $path = null) 130 { 131 // If no parent is provided, try to find it. 132 if ($parentId === null) 133 { 134 // Get the root item. 135 $parentId = $this->getRootId(); 136 137 if ($parentId === false) 138 { 139 return false; 140 } 141 } 142 143 $query = $this->_db->getQuery(true); 144 145 // Build the structure of the recursive query. 146 if (!isset($this->_cache['rebuild.sql'])) 147 { 148 $query->clear() 149 ->select($this->_tbl_key) 150 ->from($this->_tbl) 151 ->where('parent_id = %d'); 152 153 // If the table has an ordering field, use that for ordering. 154 if (property_exists($this, 'ordering')) 155 { 156 $query->order('parent_id, ordering, lft'); 157 } 158 else 159 { 160 $query->order('parent_id, lft'); 161 } 162 163 $this->_cache['rebuild.sql'] = (string) $query; 164 } 165 166 // Make a shortcut to database object. 167 168 // Assemble the query to find all children of this node. 169 $this->_db->setQuery(sprintf($this->_cache['rebuild.sql'], (int) $parentId)); 170 171 $children = $this->_db->loadObjectList(); 172 173 // The right value of this node is the left value + 1 174 $rightId = $leftId + 1; 175 176 // Execute this function recursively over all children 177 foreach ($children as $node) 178 { 179 /* 180 * $rightId is the current right value, which is incremented on recursion return. 181 * Increment the level for the children. 182 * Add this item's alias to the path (but avoid a leading /) 183 */ 184 $rightId = $this->rebuild($node->{$this->_tbl_key}, $rightId, $level + 1); 185 186 // If there is an update failure, return false to break out of the recursion. 187 if ($rightId === false) 188 { 189 return false; 190 } 191 } 192 193 // We've got the left value, and now that we've processed 194 // the children of this node we also know the right value. 195 $query->clear() 196 ->update($this->_tbl) 197 ->set('lft = ' . (int) $leftId) 198 ->set('rgt = ' . (int) $rightId) 199 ->set('level = ' . (int) $level) 200 ->where($this->_tbl_key . ' = ' . (int) $parentId); 201 $this->_db->setQuery($query)->execute(); 202 203 // Return the right value of this node + 1. 204 return $rightId + 1; 205 } 206} 207