SubtypeTable.php 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. <?php
  2. namespace Elgg\Database;
  3. /**
  4. * Cache subtypes and related class names.
  5. *
  6. * @global array|null $SUBTYPE_CACHE array once populated from DB, initially null
  7. * @access private
  8. */
  9. global $SUBTYPE_CACHE;
  10. $SUBTYPE_CACHE = null;
  11. /**
  12. * WARNING: API IN FLUX. DO NOT USE DIRECTLY.
  13. *
  14. * @access private
  15. *
  16. * @package Elgg.Core
  17. * @subpackage Database
  18. * @since 1.10.0
  19. */
  20. class SubtypeTable {
  21. /**
  22. * Global Elgg configuration
  23. *
  24. * @var \stdClass
  25. */
  26. private $CONFIG;
  27. /**
  28. * Constructor
  29. */
  30. public function __construct() {
  31. global $CONFIG;
  32. $this->CONFIG = $CONFIG;
  33. }
  34. /**
  35. * Return the id for a given subtype.
  36. *
  37. * \ElggEntity objects have a type and a subtype. Subtypes
  38. * are defined upon creation and cannot be changed.
  39. *
  40. * Plugin authors generally don't need to use this function
  41. * unless writing their own SQL queries. Use {@link \ElggEntity::getSubtype()}
  42. * to return the string subtype.
  43. *
  44. * @internal Subtypes are stored in the entity_subtypes table. There is a foreign
  45. * key in the entities table.
  46. *
  47. * @param string $type Type
  48. * @param string $subtype Subtype
  49. *
  50. * @return int Subtype ID
  51. * @see get_subtype_from_id()
  52. * @access private
  53. */
  54. function getId($type, $subtype) {
  55. global $SUBTYPE_CACHE;
  56. if (!$subtype) {
  57. return false;
  58. }
  59. if ($SUBTYPE_CACHE === null) {
  60. _elgg_populate_subtype_cache();
  61. }
  62. // use the cache before hitting database
  63. $result = _elgg_retrieve_cached_subtype($type, $subtype);
  64. if ($result !== null) {
  65. return $result->id;
  66. }
  67. return false;
  68. }
  69. /**
  70. * Gets the denormalized string for a given subtype ID.
  71. *
  72. * @param int $subtype_id Subtype ID from database
  73. * @return string|false Subtype name, false if subtype not found
  74. * @see get_subtype_id()
  75. * @access private
  76. */
  77. function getSubtype($subtype_id) {
  78. global $SUBTYPE_CACHE;
  79. if (!$subtype_id) {
  80. return '';
  81. }
  82. if ($SUBTYPE_CACHE === null) {
  83. _elgg_populate_subtype_cache();
  84. }
  85. if (isset($SUBTYPE_CACHE[$subtype_id])) {
  86. return $SUBTYPE_CACHE[$subtype_id]->subtype;
  87. }
  88. return false;
  89. }
  90. /**
  91. * Retrieve subtype from the cache.
  92. *
  93. * @param string $type
  94. * @param string $subtype
  95. * @return \stdClass|null
  96. *
  97. * @access private
  98. */
  99. function retrieveFromCache($type, $subtype) {
  100. global $SUBTYPE_CACHE;
  101. if ($SUBTYPE_CACHE === null) {
  102. _elgg_populate_subtype_cache();
  103. }
  104. foreach ($SUBTYPE_CACHE as $obj) {
  105. if ($obj->type === $type && $obj->subtype === $subtype) {
  106. return $obj;
  107. }
  108. }
  109. return null;
  110. }
  111. /**
  112. * Fetch all suptypes from DB to local cache.
  113. *
  114. * @access private
  115. */
  116. function populateCache() {
  117. global $SUBTYPE_CACHE;
  118. $results = _elgg_services()->db->getData("SELECT * FROM {$this->CONFIG->dbprefix}entity_subtypes");
  119. $SUBTYPE_CACHE = array();
  120. foreach ($results as $row) {
  121. $SUBTYPE_CACHE[$row->id] = $row;
  122. }
  123. }
  124. /**
  125. * Return the class name for a registered type and subtype.
  126. *
  127. * Entities can be registered to always be loaded as a certain class
  128. * with add_subtype() or update_subtype(). This function returns the class
  129. * name if found and null if not.
  130. *
  131. * @param string $type The type
  132. * @param string $subtype The subtype
  133. *
  134. * @return string|null a class name or null
  135. * @see get_subtype_from_id()
  136. * @see get_subtype_class_from_id()
  137. * @access private
  138. */
  139. function getClass($type, $subtype) {
  140. global $SUBTYPE_CACHE;
  141. if ($SUBTYPE_CACHE === null) {
  142. _elgg_populate_subtype_cache();
  143. }
  144. // use the cache before going to the database
  145. $obj = _elgg_retrieve_cached_subtype($type, $subtype);
  146. if ($obj) {
  147. return $obj->class;
  148. }
  149. return null;
  150. }
  151. /**
  152. * Returns the class name for a subtype id.
  153. *
  154. * @param int $subtype_id The subtype id
  155. *
  156. * @return string|null
  157. * @see get_subtype_class()
  158. * @see get_subtype_from_id()
  159. * @access private
  160. */
  161. function getClassFromId($subtype_id) {
  162. global $SUBTYPE_CACHE;
  163. if (!$subtype_id) {
  164. return null;
  165. }
  166. if ($SUBTYPE_CACHE === null) {
  167. _elgg_populate_subtype_cache();
  168. }
  169. if (isset($SUBTYPE_CACHE[$subtype_id])) {
  170. return $SUBTYPE_CACHE[$subtype_id]->class;
  171. }
  172. return null;
  173. }
  174. /**
  175. * Register \ElggEntities with a certain type and subtype to be loaded as a specific class.
  176. *
  177. * By default entities are loaded as one of the 4 parent objects: site, user, object, or group.
  178. * If you subclass any of these you can register the classname with add_subtype() so
  179. * it will be loaded as that class automatically when retrieved from the database with
  180. * {@link get_entity()}.
  181. *
  182. * @warning This function cannot be used to change the class for a type-subtype pair.
  183. * Use update_subtype() for that.
  184. *
  185. * @param string $type The type you're subtyping (site, user, object, or group)
  186. * @param string $subtype The subtype
  187. * @param string $class Optional class name for the object
  188. *
  189. * @return int
  190. * @see update_subtype()
  191. * @see remove_subtype()
  192. * @see get_entity()
  193. */
  194. function add($type, $subtype, $class = "") {
  195. global $SUBTYPE_CACHE;
  196. if (!$subtype) {
  197. return 0;
  198. }
  199. $id = get_subtype_id($type, $subtype);
  200. if (!$id) {
  201. // In cache we store non-SQL-escaped strings because that's what's returned by query
  202. $cache_obj = (object) array(
  203. 'type' => $type,
  204. 'subtype' => $subtype,
  205. 'class' => $class,
  206. );
  207. $type = sanitise_string($type);
  208. $subtype = sanitise_string($subtype);
  209. $class = sanitise_string($class);
  210. $id = _elgg_services()->db->insertData("INSERT INTO {$this->CONFIG->dbprefix}entity_subtypes"
  211. . " (type, subtype, class) VALUES ('$type', '$subtype', '$class')");
  212. // add entry to cache
  213. $cache_obj->id = $id;
  214. $SUBTYPE_CACHE[$id] = $cache_obj;
  215. }
  216. return $id;
  217. }
  218. /**
  219. * Removes a registered \ElggEntity type, subtype, and classname.
  220. *
  221. * @warning You do not want to use this function. If you want to unregister
  222. * a class for a subtype, use update_subtype(). Using this function will
  223. * permanently orphan all the objects created with the specified subtype.
  224. *
  225. * @param string $type Type
  226. * @param string $subtype Subtype
  227. *
  228. * @return bool
  229. * @see add_subtype()
  230. * @see update_subtype()
  231. */
  232. function remove($type, $subtype) {
  233. global $SUBTYPE_CACHE;
  234. $type = sanitise_string($type);
  235. $subtype = sanitise_string($subtype);
  236. $success = _elgg_services()->db->deleteData("DELETE FROM {$this->CONFIG->dbprefix}entity_subtypes"
  237. . " WHERE type = '$type' AND subtype = '$subtype'");
  238. if ($success) {
  239. // invalidate the cache
  240. $SUBTYPE_CACHE = null;
  241. }
  242. return (bool) $success;
  243. }
  244. /**
  245. * Update a registered \ElggEntity type, subtype, and class name
  246. *
  247. * @param string $type Type
  248. * @param string $subtype Subtype
  249. * @param string $class Class name to use when loading this entity
  250. *
  251. * @return bool
  252. */
  253. function update($type, $subtype, $class = '') {
  254. global $SUBTYPE_CACHE;
  255. $id = get_subtype_id($type, $subtype);
  256. if (!$id) {
  257. return false;
  258. }
  259. if ($SUBTYPE_CACHE === null) {
  260. _elgg_populate_subtype_cache();
  261. }
  262. $unescaped_class = $class;
  263. $type = sanitise_string($type);
  264. $subtype = sanitise_string($subtype);
  265. $class = sanitise_string($class);
  266. $success = _elgg_services()->db->updateData("UPDATE {$this->CONFIG->dbprefix}entity_subtypes
  267. SET type = '$type', subtype = '$subtype', class = '$class'
  268. WHERE id = $id
  269. ");
  270. if ($success && isset($SUBTYPE_CACHE[$id])) {
  271. $SUBTYPE_CACHE[$id]->class = $unescaped_class;
  272. }
  273. return $success;
  274. }
  275. }