database.rst 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. Database
  2. ########
  3. Persist user-generated content and settings with Elgg's generic storage API.
  4. .. contents:: Contents
  5. :local:
  6. :depth: 2
  7. Entities
  8. ========
  9. Creating an object
  10. ------------------
  11. To create an object in your code, you need to instantiate an
  12. ``ElggObject``. Setting data is simply a matter of adding instance
  13. variables or properties. The built-in properties are:
  14. - **``guid``** The entity's GUID; set automatically
  15. - **``owner_guid``** The owning user's GUID
  16. - **``site_guid``** The owning site's GUID. This is set automatically
  17. when an instance of ``ElggObject`` gets created)
  18. - **``subtype``** A single-word arbitrary string that defines what kind
  19. of object it is, for example ``blog``
  20. - **``access_id``** An integer representing the access level of the
  21. object
  22. - **``title``** The title of the object
  23. - **``description``** The description of the object
  24. The object subtype is a special property. This is an arbitrary string
  25. that describes what the object is. For example, if you were writing a
  26. blog plugin, your subtype string might be *blog*. It's a good idea to
  27. make this unique, so that other plugins don't accidentally try and use
  28. the same subtype. For the purposes of this document, let's assume we're
  29. building a simple forum. Therefore, the subtype will be *forum*:
  30. .. code:: php
  31. $object = new ElggObject();
  32. $object->subtype = "forum";
  33. $object->access_id = 2;
  34. $object->save();
  35. ``access_id`` is another important property. If you don't set this, your
  36. object will be private, and only the creator user will be able to see
  37. it. Elgg defines constants for the special values of ``access_id``:
  38. - **ACCESS_PRIVATE** Only the owner can see it
  39. - **ACCESS_FRIENDS** Only the owner and his/her friends can see it
  40. - **ACCESS_LOGGED_IN** Any logged in user can see it
  41. - **ACCESS_PUBLIC** Even visitors not logged in can see it
  42. Saving the object will automatically populate the ``$object->guid``
  43. property if successful. If you change any more base properties, you can
  44. call ``$object->save()`` again, and it will update the database for you.
  45. You can set metadata on an object just like a standard property. Let's
  46. say we want to set the SKU of a product:
  47. .. code:: php
  48. $object->SKU = 62784;
  49. If you assign an array, all the values will be set for that metadata.
  50. This is how, for example, you set tags.
  51. Metadata cannot be persisted to the database until the entity has been
  52. saved, but for convenience, ElggEntity can cache it internally and save
  53. it when saving the entity.
  54. Loading an object
  55. -----------------
  56. By GUID
  57. ~~~~~~~
  58. .. code:: php
  59. $entity = get_entity($guid);
  60. if (!$entity) {
  61. // The entity does not exist or you're not allowed to access it.
  62. }
  63. But what if you don't know the GUID? There are several options.
  64. By user, subtype or site
  65. ~~~~~~~~~~~~~~~~~~~~~~~~
  66. If you know the user ID you want to get objects for, or the subtype, or
  67. the site, you have several options. The easiest is probably to call the
  68. procedural function ``elgg_get_entities``:
  69. .. code:: php
  70. $entities = elgg_get_entities(array(
  71. 'type' => $entity_type,
  72. 'subtype' => $subtype,
  73. 'owner_guid' => $owner_guid,
  74. ));
  75. This will return an array of ``ElggEntity`` objects that you can iterate
  76. through. ``elgg_get_entities`` paginates by default, with a limit of 10;
  77. and offset 0.
  78. You can leave out ``owner_guid`` to get all objects and leave out subtype
  79. or type to get objects of all types/subtypes.
  80. If you already have an ``ElggUser`` – e.g. ``elgg_get_logged_in_user_entity``,
  81. which always has the current user's object when you're logged in – you can
  82. simply use:
  83. .. code:: php
  84. $objects = $user->getObjects($subtype, $limit, $offset)
  85. But what about getting objects with a particular piece of metadata?
  86. By metadata
  87. ~~~~~~~~~~~
  88. The function ``elgg_get_entities_from_metadata`` allows fetching entities
  89. with metadata in a variety of ways.
  90. By annotation
  91. ~~~~~~~~~~~~~
  92. The function ``elgg_get_entities_from_annotations`` allows fetching entities
  93. with metadata in a variety of ways.
  94. .. note::
  95. As of Elgg 1.10 the default behaviour of `elgg_get_entities_from_annotations` was brought inline with the rest of the `elgg_get_entities*` functions.
  96. Pre Elgg 1.10 the sorting of the entities was based on the latest addition of an annotation (in $options your could add `$options['order_by'] = 'maxtime ASC'` or `$options['order_by'] = 'maxtime DESC'`. As of Elgg 1.10 this was changed to the creation time of the entity, just like the rest of the `elgg_get_entities*` functions.
  97. To get the old behaviour back add the following to your `$options`:
  98. .. code:: php
  99. $options['selects'] = array('MAX(n_table.time_created) AS maxtime');
  100. $options['group_by'] = 'n_table.entity_guid';
  101. $options['order_by'] = 'maxtime ASC'
  102. or
  103. $options['order_by'] = 'maxtime DESC'
  104. Displaying entities
  105. -------------------
  106. In order for entities to be displayed in listing functions you need
  107. to provide a view for the entity in the views system.
  108. To display an entity, create a view EntityType/subtype where EntityType
  109. is one of the following:
  110. object: for entities derived from ElggObject
  111. user: for entities derived from ElggUser
  112. site: for entities derived from ElggSite
  113. group: for entities derived from ElggGroup
  114. A default view for all entities has already been created, this is called
  115. EntityType/default.
  116. .. _guides/database#entity-icons:
  117. Entity Icons
  118. ~~~~~~~~~~~~
  119. Every entity can be assigned an icon which is retrieved using the ``ElggEntity::getIconURL($params)`` method.
  120. This method accepts a ``$params`` argument that can be either a string specifying on of the configured icon sizes,
  121. or an array of parameters, that specify the size and provide additional context for the hook to determine the icon
  122. to serve.
  123. Use ``elgg_get_config('icon_sizes')`` to get all possible values. The following sizes exist by default:
  124. ``'large'``, ``'medium'``, ``'small'``, ``'tiny'``, and ``'topbar'``. The method triggers the
  125. ``entity:icon:url`` :ref:`hook <guides/hooks-list#other>`.
  126. Use ``elgg_view_entity_icon($entity, $size, $vars)`` to render an icon. This will scan the following
  127. locations for a view and include the first match.
  128. #. views/$viewtype/icon/$type/$subtype.php
  129. #. views/$viewtype/icon/$type/default.php
  130. #. views/$viewtype/icon/default.php
  131. Where
  132. $viewtype
  133. Type of view, e.g. ``'default'`` or ``'json'``.
  134. $type
  135. Type of entity, e.g. ``'group'`` or ``'user'``.
  136. $subtype
  137. Entity subtype, e.g. ``'blog'`` or ``'page'``.
  138. By convention entities that have an uploaded avatar or icon will have the ``icontime`` property
  139. assigned. This means that you can use ``$entity->icontime`` to check if an icon exists for the given
  140. entity.
  141. Adding, reading and deleting annotations
  142. ----------------------------------------
  143. Annotations could be used, for example, to track ratings. To annotate an
  144. entity you can use the object's ``annotate()`` method. For example, to
  145. give a blog post a rating of 5, you could use:
  146. .. code:: php
  147. $blog_post->annotate('rating', 5);
  148. .. _view: Views
  149. To retrieve the ratings on the blog post, use
  150. ``$blogpost->getAnnotations('rating')`` and if you want to delete an
  151. annotation, you can operate on the ``ElggAnnotation`` class, eg
  152. ``$annotation->delete()``.
  153. Retrieving a single annotation can be done with ``get_annotation()`` if
  154. you have the annotation's ID. If you delete an ElggEntity of any kind,
  155. all its metadata, annotations, and relationships will be automatically
  156. deleted as well.
  157. Extending ElggEntity
  158. --------------------
  159. If you derive from one of the Elgg core classes, you'll need to tell
  160. Elgg how to properly instantiate the new type of object so that
  161. get\_entity() et al. will return the appropriate PHP class. For example,
  162. if I customize ElggGroup in a class called "Committee", I need to make
  163. Elgg aware of the new mapping. Following is an example class extension:
  164. .. code:: php
  165. // Class source
  166. class Committee extends ElggGroup {
  167. protected function initializeAttributes() {
  168. parent::initializeAttributes();
  169. $this->attributes['subtype'] = 'committee';
  170. }
  171. // more customizations here
  172. }
  173. function committee_init() {
  174. register_entity_type('group', 'committee');
  175. // Tell Elgg that group subtype "committee" should be loaded using the Committee class
  176. // If you ever change the name of the class, use update_subtype() to change it
  177. add_subtype('group', 'committee', 'Committee');
  178. }
  179. register_elgg_event_handler('init', 'system', 'committee_init');
  180. Now if you invoke ``get_entity()`` with the GUID of a committee object,
  181. you'll get back an object of type Committee.
  182. This template was extracted from the definition of ElggFile.
  183. Advanced features
  184. -----------------
  185. Entity URLs
  186. ~~~~~~~~~~~
  187. Entity urls are provided by the ``getURL()`` interface and provide the
  188. Elgg framework with a common way of directing users to the appropriate
  189. display handler for any given object.
  190. For example, a profile page in the case of users.
  191. The url is set using the ``elgg\_register\_entity\_url\_handler()``
  192. function. The function you register must return the appropriate url for
  193. the given type - this itself can be an address set up by a page handler.
  194. .. _getURL(): http://reference.elgg.org/classElggEntity.html#778536251179055d877d3ddb15deeffd
  195. .. _elgg\_register\_entity\_url\_handler(): http://reference.elgg.org/entities_8php.html#f28d3b403f90c91a715b81334eb59893
  196. The default handler is to use the default export interface.
  197. Entity loading performance
  198. ~~~~~~~~~~~~~~~~~~~~~~~~~~
  199. ``elgg_get_entities`` has a couple options that can sometimes be useful to improve performance.
  200. - **preload_owners**: If the entities fetched will be displayed in a list with the owner information, you can set this option to ``true`` to efficiently load the owner users of the fetched entities.
  201. - **preload_containers**: If the entities fetched will be displayed in a list using info from their containers, you can set this option to ``true`` to efficiently load them.
  202. - **distinct**: When Elgg fetches entities using an SQL query, Elgg must be sure that each entity row appears only once in the result set. By default it includes a ``DISTINCT`` modifier on the GUID column to enforce this, but some queries naturally return unique entities. Setting the ``distinct`` option to false will remove this modifier, and rely on the query to enforce its own uniqueness.
  203. The internals of Elgg entity queries is a complex subject and it's recommended to seek help on the Elgg Community site before using the ``distinct`` option.
  204. Pre-1.8 Notes
  205. -------------
  206. update\_subtype(): This function is new in 1.8. In prior versions, you
  207. would need to edit the database by hand if you updated the class name
  208. associated with a given subtype.
  209. elgg\_register\_entity\_url\_handler(): This function is new in 1.8. It
  210. deprecates register\_entity\_url\_handler(), which you should use if
  211. developing for a pre-1.8 version of Elgg.
  212. elgg\_get\_entities\_from\_metadata(): This function is new in 1.8. It
  213. deprecates get\_entities\_from\_metadata(), which you should use if
  214. developing for a pre-1.8 version of Elgg.
  215. Custom database functionality
  216. =============================
  217. It is strongly recommended to use entities wherever possible. However, Elgg
  218. supports custom SQL queries using the database API.
  219. Example: Run SQL script on plugin activation
  220. --------------------------------------------
  221. This example shows how you can populate your database on plugin activation.
  222. my_plugin/activate.php:
  223. .. code:: php
  224. if (!elgg_get_plugin_setting('database_version', 'my_plugin') {
  225. run_sql_script(__DIR__ . '/sql/activate.sql');
  226. elgg_set_plugin_setting('database_version', 1, 'my_plugin');
  227. }
  228. my_plugin/sql/activate.sql:
  229. .. code:: sql
  230. -- Create some table
  231. CREATE TABLE prefix_custom_table(
  232. id INTEGER AUTO_INCREMENT,
  233. name VARCHAR(32),
  234. description VARCHAR(32),
  235. PRIMARY KEY (id)
  236. );
  237. -- Insert initial values for table
  238. INSERT INTO prefix_custom_table (name, description)
  239. VALUES ('Peter', 'Some guy'), ('Lisa', 'Some girl');
  240. Note that Elgg execute statements through PHPs built-in functions and have
  241. limited support for comments. I.e. only single line comments are supported
  242. and must be prefixed by "-- " or "# ". A comment must start at the very beginning
  243. of a line.
  244. Systemlog
  245. =========
  246. .. note::
  247. This section need some attention and will contain outdated information
  248. The default Elgg system log is a simple way of recording what happens within an Elgg system. It's viewable and searchable directly from the administration panel.
  249. System log storage
  250. ------------------
  251. A system log row is stored whenever an event concerning an object whose class implements the :doc:`/design/loggable` interface is triggered. ``ElggEntity`` and ``ElggExtender`` implement :doc:`/design/loggable`, so a system log row is created whenever an event is performed on all objects, users, groups, sites, metadata and annotations.
  252. Common events include:
  253. - create
  254. - update
  255. - delete
  256. - login
  257. Creating your own system log
  258. ----------------------------
  259. There are some reasons why you might want to create your own system log. For example, you might need to store a full copy of entities when they are updated or deleted, for auditing purposes. You might also need to notify an administrator when certain types of events occur.
  260. To do this, you can create a function that listens to all events for all types of object:
  261. .. code:: php
  262. register_elgg_event_handler('all','all','your_function_name');
  263. Your function can then be defined as:
  264. .. code:: php
  265. function your_function_name($object, $event) {
  266. if ($object instanceof Loggable) {
  267. ...
  268. }
  269. }
  270. You can then use the extra methods defined by :doc:`/design/loggable` to extract the information you need.