From 2.x to 3.0 =============== .. contents:: Contents :local: :depth: 1 PHP 7.0 is now required ----------------------- 5.6 is reaching it's end of life. PHP 7.0 is now required to install and run Elgg. ``$CONFIG`` is removed! ----------------------- Not exactly, however you **must** audit its usage and *should* replace it with ``elgg_get_config()`` and ``elgg_set_config()``, as recommended since Elgg 1.9. The global ``$CONFIG`` is now a proxy for Elgg's configuration container, and modifications **will fail** if you try to alter array properties directly. E.g. ``$CONFIG->cool_fruit[] = 'Pear';``. The silver lining is that failures will emit NOTICEs. Removed views ------------- * ``forms/account/settings``: usersettings extension can now extend the view ``forms/usersettings/save`` * ``forms/admin/site/advanced/system`` * ``resources/file/download`` * ``output/checkboxes``: use ``output/tags`` if you want the same behaviour * ``input/write_access``: mod/pages now uses the **access:collections:write** plugin hook. * ``invitefriends/form`` * ``page/layouts/content``: use ``page/layouts/default`` * ``page/layouts/one_column``: use ``page/layouts/default`` * ``page/layouts/one_sidebar``: use ``page/layouts/default`` * ``page/layouts/two_sidebar``: use ``page/layouts/default`` * ``page/layouts/walled_garden``: use ``page/layouts/default`` * ``page/layouts/walled_garden/cancel_button`` * ``page/layouts/two_column_left_sidebar`` * ``page/layouts/widgets/add_panel`` * ``page/elements/topbar_wrapper``: update your use of ``page/elements/topbar`` to include a check for a logged in user * ``pages/icon`` * ``groups/group_sort_menu``: use ``register, filter:menu:groups/all`` plugin hook * ``groups/my_status`` * ``groups/profile/stats`` * ``subscriptions/form/additions``: extend ``notifications/settings/other`` instead * ``likes/count``: modifications can now be done to the ``likes_count`` menu item * ``likes/css``: likes now uses ``elgg/likes.css`` * ``resources/members/index`` * ``messageboard/css`` * ``notifications/subscriptions/personal`` * ``notifications/subscriptions/collections`` * ``notifications/subscriptions/form`` * ``notifications/subscriptions/jsfuncs`` * ``notifications/subscriptions/forminternals`` * ``notifications/css`` * ``pages/input/parent`` * ``river/item``: use elgg_view_river_item() to render river items * ``river/user/default/profileupdate`` * ``admin.js`` * ``aalborg_theme/homepage.png`` * ``aalborg_theme/css`` * ``resources/avatar/view``: Use entity icon API * ``ajax_loader.gif`` * ``button_background.gif`` * ``button_graduation.png`` * ``elgg_toolbar_logo.gif`` * ``header_shadow.png`` * ``powered_by_elgg_badge_drk_bckgnd.gif`` * ``powered_by_elgg_badge_light_bckgnd.gif`` * ``sidebar_background.gif`` * ``spacer.gif`` * ``toptoolbar_background.gif`` * ``two_sidebar_background.gif`` * ``ajax_loader_bw.gif``: use ``graphics/ajax_loader_bw.gif`` * ``elgg_logo.png``: use ``graphics/elgg_logo.png`` * ``favicon-128.png``: use ``graphics/favicon-128.png`` * ``favicon-16.png``: use ``graphics/favicon-16.png`` * ``favicon-32.png``: use ``graphics/favicon-32.png`` * ``favicon-64.png``: use ``graphics/favicon-64.png`` * ``favicon.ico``: use ``graphics/favicon.ico`` * ``favicon.svg``: use ``graphics/favicon.svg`` * ``friendspicker.png``: use ``graphics/friendspicker.png`` * ``walled_garden.jpg``: use ``graphics/walled_garden.jpg`` * ``core/friends/collection`` * ``core/friends/collections`` * ``core/friends/collectiontabs`` * ``core/friends/tablelist`` * ``core/friends/talbelistcountupdate`` * ``lightbox/elgg-colorbox-theme/colorbox-images/*``` * ``navigation/menu/page``: now uses ``navigation/menu/default`` and a prepare hook * ``navigation/menu/site``: now uses default view * ``page/elements/by_line``: Use ``object/elements/imprint`` * ``forms/admin/site/advanced/security``: the site secret information has been moved to ``forms/admin/security/settings`` * ``river/object/file/create``: check :doc:`/guides/river` * ``river/object/page/create``: check :doc:`/guides/river` * ``river/object/page_top/create``: check :doc:`/guides/river` * ``river/relationship/member``: check :doc:`/guides/river` * ``object/page_top``: use ``object/page`` * ``ajax/discussion/reply/edit``: See :ref:`upgrade-discussion-replies` * ``discussion/replies``: See :ref:`upgrade-discussion-replies` * ``object/discussion_reply``: See :ref:`upgrade-discussion-replies` * ``resources/discussion/reply/edit``: See :ref:`upgrade-discussion-replies` * ``resources/elements/discussion_replies``: See :ref:`upgrade-discussion-replies` * ``river/elements/discussion_replies``: See :ref:`upgrade-discussion-replies` * ``river/object/discussion/create`` * ``river/object/discussion_reply/create``: See :ref:`upgrade-discussion-replies` * ``search/object/discussion_reply/entity``: See :ref:`upgrade-discussion-replies` * ``rss/discussion/replies``: See :ref:`upgrade-discussion-replies` * ``search/header`` * ``search/layout`` in both ``default`` and ``rss`` viewtypes * ``search/no_results`` * ``search/object/comment/entity`` * ``search/css``: Moved to ``search/search.css`` * ``search/startblurb`` * ``bookmarks/bookmarklet.gif`` * ``blog_get_page_content_list`` * ``blog_get_page_content_archive`` * ``blog_get_page_content_edit`` * ``forms/invitefriends/invite``: use ``forms/friends/invite`` * ``resources/invitefriends/invite``: use ``resources/friends/invite`` * ``resources/reportedcontent/add`` * ``resources/reportedcontent/add_form`` * ``resources/site_notifications/view``: Use ``resources/site_notifications/owner`` * ``resources/site_notifications/everyone``: Use ``resources/site_notifications/all`` Removed functions/methods ------------------------- All the functions in ``engine/lib/deprecated-1.9.php`` were removed. See https://github.com/Elgg/Elgg/blob/2.0/engine/lib/deprecated-1.9.php for these functions. Each ``@deprecated`` declaration includes instructions on what to use instead. All the functions in ``engine/lib/deprecated-1.10.php`` were removed. See https://github.com/Elgg/Elgg/blob/2.0/engine/lib/deprecated-1.10.php for these functions. Each ``@deprecated`` declaration includes instructions on what to use instead. * ``elgg_register_library``: require your library files so they are available globally to other plugins * ``elgg_load_library`` * ``activity_profile_menu`` * ``can_write_to_container``: Use ``ElggEntity->canWriteToContainer()`` * ``create_metadata_from_array`` * ``metadata_array_to_values`` * ``datalist_get`` * ``datalist_set`` * ``detect_extender_valuetype`` * ``developers_setup_menu`` * ``elgg_disable_metadata`` * ``elgg_enable_metadata`` * ``elgg_get_class_loader`` * ``elgg_get_metastring_id`` * ``elgg_get_metastring_map`` * ``elgg_register_class`` * ``elgg_register_classes`` * ``elgg_register_viewtype`` * ``elgg_is_registered_viewtype`` * ``file_delete``: Use ``ElggFile->deleteIcon()`` * ``file_get_type_cloud`` * ``file_type_cloud_get_url`` * ``get_default_filestore`` * ``get_site_entity_as_row`` * ``get_group_entity_as_row`` * ``get_missing_language_keys`` * ``get_object_entity_as_row`` * ``get_user_entity_as_row`` * ``update_river_access_by_object`` * ``garbagecollector_orphaned_metastrings`` * ``groups_access_collection_override`` * ``groups_get_group_tool_options``: Use ``elgg()->group_tools->all()`` * ``groups_join_group``: Use ``ElggGroup::join`` * ``groups_prepare_profile_buttons``: Use ``register, menu:title`` hook * ``groups_register_profile_buttons``: Use ``register, menu:title`` hook * ``groups_setup_sidebar_menus`` * ``groups_set_icon_url`` * ``groups_setup_sidebar_menus`` * ``messages_notification_msg`` * ``set_default_filestore`` * ``generate_user_password``: Use ``ElggUser::setPassword`` * ``row_to_elggrelationship`` * ``run_function_once``: Use ``Elgg\Upgrade\Batch`` interface * ``system_messages`` * ``notifications_plugin_pagesetup`` * ``elgg_format_url``: Use elgg_format_element() or the "output/text" view for HTML escaping. * ``get_site_by_url`` * ``elgg_override_permissions``: No longer used as handler for ``permissions_check`` and ``container_permissions_check`` hooks * ``elgg_check_access_overrides`` * ``AttributeLoader`` became obsolete and was removed * ``Application::loadSettings`` * ``ElggEntity::addToSite`` * ``ElggEntity::disableMetadata`` * ``ElggEntity::enableMetadata`` * ``ElggEntity::getSites`` * ``ElggEntity::removeFromSite`` * ``ElggEntity::isFullyLoaded`` * ``ElggEntity::clearAllFiles`` * ``ElggPlugin::getFriendlyName``: Use ``ElggPlugin::getDisplayName()`` * ``ElggPlugin::setID`` * ``ElggPlugin::unsetAllUsersSettings`` * ``ElggFile::setFilestore``: ElggFile objects can no longer use custom filestores. * ``ElggFile::size``: Use ``getSize`` * ``ElggDiskFilestore::makeFileMatrix``: Use ``Elgg\EntityDirLocator`` * ``ElggData::get``: Usually can be replaced by property read * ``ElggData::getClassName``: Use ``get_class()`` * ``ElggData::set``: Usually can be replaced by property write * ``ElggEntity::setURL``: See ``getURL`` for details on the plugin hook * ``ElggMenuBuilder::compareByWeight``: Use ``compareByPriority`` * ``ElggMenuItem::getWeight``: Use ``getPriority`` * ``ElggMenuItem::getContent``: Use ``elgg_view_menu_item()`` * ``ElggMenuItem::setWeight``: Use ``setPriority`` * ``ElggRiverItem::getPostedTime``: Use ``getTimePosted`` * ``ElggSession`` has removed all deprecated methods * ``ElggSite::addEntity`` * ``ElggSite::addObject`` * ``ElggSite::addUser`` * ``ElggSite::getEntities``: Use ``elgg_get_entities()`` * ``ElggSite::getExportableValues``: Use ``toObject`` * ``ElggSite::getMembers``: Use ``elgg_get_entities()`` * ``ElggSite::getObjects``: Use ``elgg_get_entities()`` * ``ElggSite::listMembers``: Use ``elgg_list_entities()`` * ``ElggSite::removeEntity`` * ``ElggSite::removeObject`` * ``ElggSite::removeUser`` * ``ElggSite::isPublicPage``: Logic moved to the router and should not be accessed directly * ``ElggSite::checkWalledGarden``: Logic moved to the router and should not be accessed directly * ``ElggUser::countObjects``: Use ``elgg_get_entities()`` * ``Logger::getClassName``: Use ``get_class()`` * ``Elgg\Application\Database::getTablePrefix``: Read the ``prefix`` property * ``elgg_view_access_collections()`` * ``ElggSession::get_ignore_access``: Use ``getIgnoreAccess`` * ``ElggSession::set_ignore_access``: Use ``setIgnoreAccess`` * ``profile_pagesetup`` * ``pages_can_delete_page``: Use ``$entity->canDelete()`` * ``pages_search_pages`` * ``pages_is_page``: use ``$entity instanceof ElggPage`` * ``discussion_comment_override``: See :ref:`upgrade-discussion-replies` * ``discussion_can_edit_reply``: See :ref:`upgrade-discussion-replies` * ``discussion_reply_menu_setup``: See :ref:`upgrade-discussion-replies` * ``discussion_reply_container_logic_override``: See :ref:`upgrade-discussion-replies` * ``discussion_reply_container_permissions_override``: See :ref:`upgrade-discussion-replies` * ``discussion_update_reply_access_ids``: See :ref:`upgrade-discussion-replies` * ``discussion_search_discussion``: See :ref:`upgrade-discussion-replies` * ``discussion_add_to_river_menu``: See :ref:`upgrade-discussion-replies` * ``discussion_prepare_reply_notification``: See :ref:`upgrade-discussion-replies` * ``discussion_redirect_to_reply``: See :ref:`upgrade-discussion-replies` * ``discussion_ecml_views_hook``: See :ref:`upgrade-discussion-replies` * ``search_get_where_sql`` * ``search_get_ft_min_max`` * ``search_get_order_by_sql`` * ``search_consolidate_substrings`` * ``search_remove_ignored_words`` * ``search_get_highlighted_relevant_substrings`` * ``search_highlight_words`` * ``search_get_search_view`` * ``search_custom_types_tags_hook`` * ``search_tags_hook`` * ``search_users_hook`` * ``search_groups_hook`` * ``search_objects_hook`` * ``members_list_popular`` * ``members_list_newest`` * ``members_list_online`` * ``members_list_alpha`` * ``members_nav_popular`` * ``members_nav_newest`` * ``members_nav_online`` * ``members_nav_alpha`` * ``uservalidationbyemail_generate_code`` All functions around entity subtypes table: * ``add_subtype``: Use ``elgg_set_entity_class`` at runtime * ``update_subtype``: Use ``elgg_set_entity_class`` at runtime * ``remove_subtype`` * ``get_subtype_id`` * ``get_subtype_from_id`` * ``get_subtype_class``: Use ``elgg_get_entity_class`` * ``get_subtype_class_from_id`` All caches have been consolidated into a single API layer. The following functions and methods have been removed: * ``is_memcache_available`` * ``_elgg_get_memcache`` * ``_elgg_invalidate_memcache_for_entity`` * ``ElggMemcache`` * ``ElggFileCache`` * ``ElggStaticVariableCache`` * ``ElggSharedMemoryCache`` * ``Elgg\Cache\Pool`` interface and all extending classes As a result of system log changes: * ``system_log_default_logger``: moved to ``system_log`` plugin * ``system_log_listener``: moved to ``system_log`` plugin * ``system_log``: moved to ``system_log`` plugin * ``get_system_log``: renamed to ``system_log_get_log`` and moved to ``system_log`` plugin * ``get_log_entry``: renamed to ``system_log_get_log_entry`` and moved to ``system_log`` plugin * ``get_object_from_log_entry``: renamed to ``system_log_get_object_from_log_entry`` and moved to ``system_log`` plugin * ``archive_log``: renamed to ``system_log_archive_log`` and moved to ``system_log`` plugin * ``logbrowser_user_hover_menu``: renamed to ``system_log_user_hover_menu`` and moved to ``system_log`` plugin * ``logrotate_archive_cron``: renamed to ``system_log_archive_cron`` and moved to ``system_log`` plugin * ``logrotate_delete_cron``: renamed to ``system_log_delete_cron`` and moved to ``system_log`` plugin * ``logrotate_get_seconds_in_period``: renamed to ``system_log_get_seconds_in_period`` and moved to ``system_log`` plugin * ``log_browser_delete_log``: renamed to ``system_log_browser_delete_log`` and moved to ``system_log`` plugin Deprecated APIs --------------- * ``ban_user``: Use ``ElggUser->ban()`` * ``create_metadata``: Use ``ElggEntity`` setter or ``ElggEntity->setMetadata()`` * ``update_metadata``: Use ``ElggMetadata->save()`` * ``get_metadata_url`` * ``create_annotation``: Use ``ElggEntity->annotate()`` * ``update_metadata``: Use ``ElggAnnotation->save()`` * ``elgg_get_user_validation_status``: Use ``ElggUser->isValidated()`` * ``make_user_admin``: Use ``ElggUser->makeAdmin()`` * ``remove_user_admin``: Use ``ElggUser->removeAdmin()`` * ``unban_user``: Use ``ElggUser->unban()`` * ``elgg_get_entities_from_attributes``: Use ``elgg_get_entities()`` * ``elgg_get_entities_from_metadata``: Use ``elgg_get_entities()`` * ``elgg_get_entities_from_relationship``: Use ``elgg_get_entities()`` * ``elgg_get_entities_from_private_settings``: Use ``elgg_get_entities()`` * ``elgg_get_entities_from_access_id``: Use ``elgg_get_entities()`` * ``elgg_list_entities_from_metadata``: Use ``elgg_list_entities()`` * ``elgg_list_entities_from_relationship``: Use ``elgg_list_entities()`` * ``elgg_list_entities_from_private_settings``: Use ``elgg_list_entities()`` * ``elgg_list_entities_from_access_id``: Use ``elgg_list_entities()`` * ``elgg_list_registered_entities``: Use ``elgg_list_entities()`` * ``elgg_batch_delete_callback`` * ``\Elgg\Project\Paths::sanitize``: Use ``\Elgg\Project\Paths::sanitize()`` * ``elgg_group_gatekeeper``: Use ``elgg_entity_gatekeeper()`` * ``get_entity_dates``: Use ``elgg_get_entity_dates()`` * ``messages_set_url``: Use ``ElggEntity::getURL()`` Removed global vars ------------------- * ``$CURRENT_SYSTEM_VIEWTYPE`` * ``$DEFAULT_FILE_STORE`` * ``$ENTITY_CACHE`` * ``$SESSION``: Use the API provided by ``elgg_get_session()`` * ``$CONFIG->site_id``: Use ``1`` * ``$CONFIG->search_info`` * ``$CONFIG->input``: Use ``set_input`` and ``get_input`` Removed classes/interfaces -------------------------- * ``FilePluginFile``: replace with ``ElggFile`` (or load with ``get_entity()``) * ``Elgg_Notifications_Notification`` * ``Elgg\Database\EntityTable\UserFetchResultException.php`` * ``Elgg\Database\MetastringsTable`` * ``Elgg\Database\SubtypeTable`` * ``Exportable`` and its methods ``export`` and ``getExportableValues``: Use ``toObject`` * ``ExportException`` * ``Importable`` and its method ``import``. * ``ImportException`` * ``ODD`` and all classes beginning with ``ODD*``. * ``XmlElement`` * ``Elgg_Notifications_Event``: Use ``\Elgg\Notifications\Event`` * ``Elgg\Mail\Address``: use ``Elgg\Email\Address`` * ``ElggDiscussionReply``: user ``ElggComment`` see :ref:`upgrade-discussion-replies` Schema changes -------------- The storage engine for the database tables has been changed from MyISAM to InnoDB. You maybe need to optimize your database settings for this change. The ``datalists`` table has been removed. All settings from datalists table have been merged into the ``config`` table. Metastrings in the database have been denormalized for performance purposes. We removed the metastrings table and put all the string values directly in the metadata and annotation tables. You need to update your custom queries to reflect these changes. Also the ``msv`` and ``msn`` table aliases are no longer available. It is best practice not to rely on the table aliases used in core queries. If you need to use custom clauses you should do your own joins. From the "users_entity" table, the ``password`` and ``hash`` columns have been removed. The ``geocode_cache`` table has been removed as it was no longer used. ``subtype`` column in ``entities`` table no longer holds a subtype ID, but a subtype string ``entity_subtypes`` table has been dropped. ``type``, ``subtype`` and ``access_id`` columns in ``river`` table have been dropped. For queries without ``elgg_get_river()`` join the ``entities`` table on ``object_guid`` to check the type and the subtype of the entity. Access column hasn't been in use for some time: queries are built to ensure access to all three entities (subject, object and target). Changes in ``elgg_get_entities``, ``elgg_get_metadata`` and ``elgg_get_annotations`` getter functions ----------------------------------------------------------------------------------------------------- ``elgg_get_entities`` now accepts all options that were previously distributed between ``elgg_get_entities_from_metadata``, ``elgg_get_entities_from_annotations``, ``elgg_get_entities_from_relationship``, ``elgg_get_entities_from_private_settings`` and ``elgg_get_entities_from_access_id``. The latter have been been deprecated. Passing raw MySQL statements to options is deprecated. Plugins are advised to use closures that receive an instance of ``\Elgg\Database\QueryBuilder`` and prepare the statement using database abstraction layer. On one hand this will ensure that all statements are properly sanitized using the database driver, on the other hand it will allow us to transition to testable object-oriented query building. ``wheres`` statements should not use raw SQL strings, instead pass an instance of ``\Elgg\Database\Clauses\WhereClause`` or a closure that returns an instance of ``\Doctrine\DBAL\Query\Expression\CompositeExpression``: .. code-block:: php elgg_get_entities([ 'wheres' => [ function(\Elgg\Database\QueryBuilder $qb, $alias) { $joined_alias = $qb->joinMetadataTable($alias, 'guid', 'status'); return $qb->compare("$joined_alias.name", 'in', ['draft', 'unsaved_draft'], ELGG_VALUE_STRING); } ] ]); ``joins``, ``order_by``, ``group_by``, ``selects`` clauses should not use raw SQL strings. Use closures that receive an instance of ``\Elgg\Database\QueryBuilder`` and return a prepared statement. The ``reverse_order_by`` option has been removed. Plugins should not rely on joined and selected table aliases. Closures passed to the options array will receive a second argument that corresponds to the selected table alias. Plugins must perform their own joins and use joined aliases accordingly. Note that all of the private API around building raw SQL strings has also been removed. If you were relying on them in your plugins, be advised that anything marked as ``@access private`` or ``@internal`` in core can be modified and removed at any time, and we do not guarantee any backward compatibility for those functions. DO NOT USE THEM. If you find yourself needing to use them, open an issue on Github and we will consider adding a public equivalent. Boolean entity properties ------------------------- Storage of metadata, annotation and private setting values has been aligned. **Boolean values are cast to integers when saved**: ``false`` is stored as ``0`` and ``true`` is stored as ``1``. This has breaking implications for private settings, which were previously stored as empty strings for ``false`` values. Plugins should write their own migration scripts to alter DB values from empty strings to ``0`` (for private settings that are expected to store boolean values) to ensure that ``elgg_get_entities()`` can retrieve these values with ``private_setting_name_value_pairs`` containing ``false`` values. This applies to plugin settings, as well as any private settings added to entities. Metadata Changes ---------------- Metadata is no longer access controlled. If your plugin created metadata with restricted access, those restrictions will not be honored. You should use annotations or entities instead, which do provide access control. Do not read or write to the ``access_id`` property on ElggMetadata objects. Metadata is no longer enabled or disabled. You can no longer perform the ``enable`` and ``disable`` API calls on metadata. Metadata no longer has an ``owner_guid``. It is no longer possible to query metadata based on ``owner_guids``. Subsequently, ``ElggMetadata::canEdit()`` will always return ``true`` regardless of the logged in user, unless explicitly overriden by a plugin hook. Permissions and Access ---------------------- User capabilities service will no longer trigger permission check hooks when: - permissions are checked for an admin user - permissions are checked when access is ignored with ``elgg_set_ignore_access()`` This means that plugins can no longer alter permissions in aforementioned cases. ``elgg_check_access_overrides()`` has been removed, as plugins will no longer need to validate access overrides. The translations for the default Elgg access levels have new translation language keys. Multi Site Changes ------------------ Pre 3.0 Elgg has some (partial) support for having multiple sites in the same database. This Multi Site concept has been completely removed in 3.0. Entities no longer have the site_guid attribute. This means there is no longer the ability to have entities on different sites. If you currently have multiple sites in your database, upgrading Elgg to 3.0 will fail. You need to separate the different sites into separate databases/tables. Related to the removal of the Multi Site concept in Elgg, there is no longer a need for entities having a 'member_of_site' relationship with the Site Entity. All functions related to adding/removing this relationship has been removed. All existing relationships will be removed as part of this upgrade. Setting ``ElggSite::$url`` has no effect. Reading the site URL always pulls from the ``$CONFIG->wwwroot`` set in settings.php, or computed by Symphony Request. ``ElggSite::save()`` will fail if it isn't the main site. Entity Subtable Changes ----------------------- The subtable ``sites_entity`` for ``ElggSite`` no longer exists. All attributes have been moved to metadata. The subtable ``groups_entity`` for ``ElggGroup`` no longer exists. All attributes have been moved to metadata. The subtable ``objects_entity`` for ``ElggObject`` no longer exists. All attributes have been moved to metadata. The subtable ``users_entity`` for ``ElggUser`` no longer exists. All attributes have been moved to metadata. If you have custom queries referencing this table you need to update them. If you have function that rely on ``Entity->getOriginalAttributes()`` be advised that this will only return the base attributes of an ``ElggEntity`` and no longer contain the secondary attributes. Friends and Group Access Collection ----------------------------------- The access collections table now has a subtype column. This extra data helps identifying the purpose of the ACL. The user owned access collections are assumed to be used as Friends Collections and now have the 'friends_collection' subtype. The groups access collection information was previously stored in the group_acl metadata. With the introduction of the ACL subtype this information has been moved to the ACL subtype attribute. The ``ACCESS_FRIENDS`` access_id has been migrated to an actual access collection (with the subtype ``friends``). All entities and annotations have been updated to use the new access collection id. The access collection is created when a user is created. When a relationship of the type ``friends`` is created, the related guid will also be added to the access collection. You can no longer save or update entities with the access id ``ACCESS_FRIENDS``. Subtypes no longer have an ID ----------------------------- Entity subtypes have been denormalized. ``entity_subtypes`` table has been removed and ``subtype`` column in entities table simply holds the string representation of the subtype. Consequently, all API around adding/updating entity subtypes and classes have been removed. Plugins can now use ``elgg_set_entity_class()`` and ``elgg_get_entity_class()`` to register a custom entity class at runtime (e.g. in system init handler). All entities now **MUST** have a subtype. By default, the following subtypes are added and reserved: * ``user`` for users * ``group`` for groups * ``site`` for sites Custom class loading -------------------- Elgg no longer provides API functions to register custom classes. If you need custom classes you can use ``PSR-0`` classes in the ``/classes`` folder of your plugin or use composer for autoloading of additional classes. The following class registration related functions have been removed: * ``elgg_get_class_loader`` * ``elgg_register_class`` * ``elgg_register_classes`` Dependency Injection Container ------------------------------ Plugins can now define their services and attach them to Elgg's public DI container by providing definitions in ``elgg-services.php`` in the root of the plugin directory. ``elgg()`` no longer returns an instance of Elgg application, but a DI container instance. Search changes -------------- We have added a search service into core, consequently the ``search`` plugin now only provides a user interface for displaying forms and listing search results. Many of the views in the search plugin have been affected by this change. The FULLTEXT indices have been removed on various tables. The search plugin will now always use a like query when performing a search. See :doc:`Search Service ` and :ref:`Search hooks ` documentation for detailed information about new search capabilities. Form and field related changes ------------------------------ * ``input/password``: by default this field will no longer show a value passed to it, this can be overridden by passing the view var ``always_empty`` and set it to false * ``input/submit``, ``input/reset`` and ``input/button`` are now rendered with a ``