</package>
```
-There is an [entire chapter][package_package-xml] on the package system that explains what the code above
+There is an [entire chapter](package_package-xml.md) on the package system that explains what the code above
does and how you can adjust it to fit your needs. For now we'll keep it as it is.
## The PHP Class
This documentation explains the basic API functionality and the creation of own packages. It is expected that you are somewhat experienced with [PHP](https://en.wikipedia.org/wiki/PHP), [Object-oriented programming](https://en.wikipedia.org/wiki/Object-oriented_programming) and [MySQL](https://en.wikipedia.org/wiki/MySQL).
-Head over to the [quick start tutorial][getting-started_quick-start] to learn more.
+Head over to the [quick start tutorial](getting-started_quick-start.md) to learn more.
## About WoltLab Suite 5.3
## The History of the Legacy API
-The WoltLab Suite 3.0 [introduced a new API][javascript_new-api_writing-a-module] based on AMD-Modules
+The WoltLab Suite 3.0 [introduced a new API](javascript_new-api_writing-a-module.md) based on AMD-Modules
with ES5-JavaScript that was designed with high performance and visible dependencies
-in mind. This was a fundamental change in comparison to [the legacy API][javascript_legacy-api]
+in mind. This was a fundamental change in comparison to [the legacy API](javascript_legacy-api.md)
that was build many years before while jQuery was still a thing and we had to deal
with ancient browsers such as Internet Explorer 9 that felt short in both CSS and
JavaScript capabilities.
### The Accelerated Guest View ("Tiny Builds")
-{% include callout.html content="You can learn more on the [Accelerated Guest View][migration_wsc-30_javascript] in the migration docs." type="info" %}
+{% include callout.html content="You can learn more on the [Accelerated Guest View](migration_wsc-30_javascript.md) in the migration docs." type="info" %}
The "Accelerated Guest View" was introduced in WoltLab Suite 3.1 and aims to
decrease page size and to improve responsiveness by enabling a read-only mode
### `elInnerError(element: Element, errorMessage?: string, isHtml?: boolean): Element | null``
Unified function to display and remove inline error messages for input elements,
-please read the [section in the migration docs](migration_wsc-30_javascript.html#helper-function-for-inline-error-messages)
+please read the [section in the migration docs](migration_wsc-30_javascript.md#helper-function-for-inline-error-messages)
to learn more about this function.
## String Extensions
The legacy JavaScript API is the original code that was part of the 2.x series
of WoltLab Suite, formerly known as WoltLab Community Framework. It has been
-superseded for the most part by the [ES5/AMD-modules API][javascript_new-api_writing-a-module]
+superseded for the most part by the [ES5/AMD-modules API](javascript_new-api_writing-a-module.md)
introduced with WoltLab Suite 3.0.
Some parts still exist to this day for backwards-compatibility and because some
_Defaults to `""`._
-Shows a [confirmation dialog][javascript_new-api_ui] using the configured message
+Shows a [confirmation dialog](javascript_new-api_ui.md) using the configured message
before closing the dialog. The dialog will not be closed if the dialog is
rejected by the user.
## Helper Functions
-There is large set of [helper functions][javascript_helper-functions] that assist
+There is large set of [helper functions](javascript_helper-functions.md) that assist
you when working with the DOM tree and its elements. These functions are globally
available and do not require explicit module imports.
The default location for modules is `js/` in the Core's app dir,
but every app and plugin can register their own lookup path by providing the path
-using a [template-listener][package_pip_template-listener] on `requirePaths@headIncludeJavaScript`.
+using a [template-listener](package_pip_template-listener.md) on `requirePaths@headIncludeJavaScript`.
For this example we'll assume the file is placed at `js/WoltLabSuite/Core/Ui/Foo.js`,
the module name is therefore `WoltLabSuite/Core/Ui/Foo`, it is automatically
| Alias | Full Path |
|---|---|
-| [Ajax][javascript_new-api_ajax] | WoltLabSuite/Core/Ajax |
+| [Ajax](javascript_new-api_ajax.md) | WoltLabSuite/Core/Ajax |
| AjaxJsonp | WoltLabSuite/Core/Ajax/Jsonp |
| AjaxRequest | WoltLabSuite/Core/Ajax/Request |
| CallbackList | WoltLabSuite/Core/CallbackList |
| ColorUtil | WoltLabSuite/Core/ColorUtil |
-| [Core][javascript_new-api_core] | WoltLabSuite/Core/Core |
+| [Core](javascript_new-api_core.md) | WoltLabSuite/Core/Core |
| DateUtil | WoltLabSuite/Core/Date/Util |
| Devtools | WoltLabSuite/Core/Devtools |
-| [Dictionary][javascript_new-api_data-structures] | WoltLabSuite/Core/Dictionary |
-| [Dom/ChangeListener][javascript_new-api_dom] | WoltLabSuite/Core/Dom/Change/Listener |
+| [Dictionary](javascript_new-api_data-structures.md) | WoltLabSuite/Core/Dictionary |
+| [Dom/ChangeListener](javascript_new-api_dom.md) | WoltLabSuite/Core/Dom/Change/Listener |
| Dom/Traverse | WoltLabSuite/Core/Dom/Traverse |
-| [Dom/Util][javascript_new-api_dom] | WoltLabSuite/Core/Dom/Util |
-| [Environment][javascript_new-api_browser] | WoltLabSuite/Core/Environment |
-| [EventHandler][javascript_new-api_events] | WoltLabSuite/Core/Event/Handler |
-| [EventKey][javascript_new-api_events] | WoltLabSuite/Core/Event/Key |
-| [Language][javascript_new-api_core] | WoltLabSuite/Core/Language |
-| [List][javascript_new-api_data-structures] | WoltLabSuite/Core/List |
-| [ObjectMap][javascript_new-api_data-structures] | WoltLabSuite/Core/ObjectMap |
+| [Dom/Util](javascript_new-api_dom.md) | WoltLabSuite/Core/Dom/Util |
+| [Environment](javascript_new-api_browser.md) | WoltLabSuite/Core/Environment |
+| [EventHandler](javascript_new-api_events.md) | WoltLabSuite/Core/Event/Handler |
+| [EventKey](javascript_new-api_events.md) | WoltLabSuite/Core/Event/Key |
+| [Language](javascript_new-api_core.md) | WoltLabSuite/Core/Language |
+| [List](javascript_new-api_data-structures.md) | WoltLabSuite/Core/List |
+| [ObjectMap](javascript_new-api_data-structures.md) | WoltLabSuite/Core/ObjectMap |
| Permission | WoltLabSuite/Core/Permission |
-| [StringUtil][javascript_new-api_core] | WoltLabSuite/Core/StringUtil |
-| [Ui/Alignment][javascript_new-api_ui] | WoltLabSuite/Core/Ui/Alignment |
-| [Ui/CloseOverlay][javascript_new-api_ui] | WoltLabSuite/Core/Ui/CloseOverlay |
-| [Ui/Confirmation][javascript_new-api_ui] | WoltLabSuite/Core/Ui/Confirmation |
-| [Ui/Dialog][javascript_new-api_dialogs] | WoltLabSuite/Core/Ui/Dialog |
-| [Ui/Notification][javascript_new-api_ui] | WoltLabSuite/Core/Ui/Notification |
+| [StringUtil](javascript_new-api_core.md) | WoltLabSuite/Core/StringUtil |
+| [Ui/Alignment](javascript_new-api_ui.md) | WoltLabSuite/Core/Ui/Alignment |
+| [Ui/CloseOverlay](javascript_new-api_ui.md) | WoltLabSuite/Core/Ui/CloseOverlay |
+| [Ui/Confirmation](javascript_new-api_ui.md) | WoltLabSuite/Core/Ui/Confirmation |
+| [Ui/Dialog](javascript_new-api_dialogs.md) | WoltLabSuite/Core/Ui/Dialog |
+| [Ui/Notification](javascript_new-api_ui.md) | WoltLabSuite/Core/Ui/Notification |
| Ui/ReusableDropdown | WoltLabSuite/Core/Ui/Dropdown/Reusable |
-| [Ui/Screen][javascript_new-api_browser] | WoltLabSuite/Core/Ui/Screen |
+| [Ui/Screen](javascript_new-api_browser.md) | WoltLabSuite/Core/Ui/Screen |
| Ui/Scroll | WoltLabSuite/Core/Ui/Scroll |
| Ui/SimpleDropdown | WoltLabSuite/Core/Ui/Dropdown/Simple |
| Ui/TabMenu | WoltLabSuite/Core/Ui/TabMenu |
The LESS compiler has been in use since WoltLab Community Framework 2.0, but was replaced with a SCSS compiler in WoltLab Suite 3.0. This change was motivated by SCSS becoming the de facto standard for CSS pre-processing and some really annoying shortcomings in the old LESS compiler.
-The entire CSS has been rewritten from scratch, please read the [docs on CSS][view_css] to learn what has changed.
+The entire CSS has been rewritten from scratch, please read the [docs on CSS](view_css.md) to learn what has changed.
## box.xml
-The [box][package_pip_box] PIP has been added.
+The [box](package_pip_box.md) PIP has been added.
## cronjob.xml
## menu.xml
-The [menu][package_pip_menu] PIP has been added.
+The [menu](package_pip_menu.md) PIP has been added.
## menuItem.xml
-The [menuItem][package_pip_menu-item] PIP has been added.
+The [menuItem](package_pip_menu-item.md) PIP has been added.
## objectType.xml
## page.xml
-The [page][package_pip_page] PIP has been added.
+The [page](package_pip_page.md) PIP has been added.
## pageMenu.xml
## Pages and Forms
-The property `$activeMenuItem` has been deprecated for the front end and is no longer evaluated at runtime. Recognition of the active item is entirely based around the invoked controller class name and its definition in the page table. You need to properly [register your pages](package_pip_page.html) for this feature to work.
+The property `$activeMenuItem` has been deprecated for the front end and is no longer evaluated at runtime. Recognition of the active item is entirely based around the invoked controller class name and its definition in the page table. You need to properly [register your pages](package_pip_page.md) for this feature to work.
## Search
## New Package Installation Plugin for Media Providers
-Please refer to the documentation of the [`mediaProvider.xml`][package_pip_media-provider] to learn more.
+Please refer to the documentation of the [`mediaProvider.xml`](package_pip_media-provider.md) to learn more.
## Limited Forward-Compatibility for Plugins
-Please refer to the documentation of the [`<compatibility>`](package_package-xml.html#compatibility) tag in the `package.xml`.
+Please refer to the documentation of the [`<compatibility>`](package_package-xml.md#compatibility) tag in the `package.xml`.
## Example: Two Text Form Fields
-As the first example, the pre-WoltLab Suite Core 5.2 versions of the forms to add and edit persons from the [first part of the tutorial series](tutorial_tutorial-series_part-1-base-structure.html) will be updated to the new form builder API.
+As the first example, the pre-WoltLab Suite Core 5.2 versions of the forms to add and edit persons from the [first part of the tutorial series](tutorial_tutorial-series_part-1-base-structure.md) will be updated to the new form builder API.
This form is the perfect first examples as it is very simple with only two text fields whose only restriction is that they have to be filled out and that their values may not be longer than 255 characters each.
As a reminder, here are the two relevant PHP files and the relevant template file:
### Recent Activity
-To adjust entries in the Recent Activity, only three small steps are necessary. First we pass the concrete reaction to the language variable, so that we can use the reaction object there. To do this, we add the following variable to the text of the `\wcf\system\user\activity\event\IUserActivityEvent` object: `$event->reactionType`. Typically we name the variable `reactionType`. In the second step, we mark the event as compatible. Therefore we set the parameter `supportsReactions` in the [`objectType.xml`](package_pip_object-type) to `1`. So for example the entry looks like this:
+To adjust entries in the Recent Activity, only three small steps are necessary. First we pass the concrete reaction to the language variable, so that we can use the reaction object there. To do this, we add the following variable to the text of the `\wcf\system\user\activity\event\IUserActivityEvent` object: `$event->reactionType`. Typically we name the variable `reactionType`. In the second step, we mark the event as compatible. Therefore we set the parameter `supportsReactions` in the [`objectType.xml`](package_pip_object-type.md) to `1`. So for example the entry looks like this:
```xml
<type>
```
### Comments
-If comments send notifications, they must also be updated. The language variables are changed in the same way as described in the section [Notifications / Language](migration_wsc-31_like.html#Language-Variables). After that comment must be marked as compatible. Therefore we set the parameter `supportsReactions` in the [`objectType.xml`](package_pip_object-type) to `1`. So for example the entry looks like this:
+If comments send notifications, they must also be updated. The language variables are changed in the same way as described in the section [Notifications / Language](migration_wsc-31_like.md#Language-Variables). After that comment must be marked as compatible. Therefore we set the parameter `supportsReactions` in the [`objectType.xml`](package_pip_object-type.md) to `1`. So for example the entry looks like this:
```xml
<type>
## Form Builder
WoltLab Suite Core 5.2 introduces a new, simpler and quicker way of creating forms:
-[form builder](php_api_form_builder.html).
-You can find examples of how to migrate existing forms to form builder [here](migration_wsc-31_form-builder.html).
+[form builder](php_api_form_builder.md).
+You can find examples of how to migrate existing forms to form builder [here](migration_wsc-31_form-builder.md).
In the near future, to ensure backwards compatibility within WoltLab packages, we will only use form builder for new forms or for major rewrites of existing forms that would break backwards compatibility anyway.
## Like System
-WoltLab Suite Core 5.2 replaced the like system with the reaction system. You can find the migration guide [here](migration_wsc-31_like.html).
+WoltLab Suite Core 5.2 replaced the like system with the reaction system. You can find the migration guide [here](migration_wsc-31_like.md).
## User Content Providers
### PHP Class
-First, we create the PHP class that provides our interface to provide the data. The class must implement interface `wcf\system\user\content\provider\IUserContentProvider` in any case. Mostly we process data which is based on [`wcf\data\DatabaseObject`](php_database-objects.html). In this case, the WoltLab Suite provides an abstract class `wcf\system\user\content\provider\AbstractDatabaseUserContentProvider` that can be used to automatically generates the standardized classes to generate the list and deletes objects via the DatabaseObjectAction. For example, if we would create a content provider for comments, the class would look like this:
+First, we create the PHP class that provides our interface to provide the data. The class must implement interface `wcf\system\user\content\provider\IUserContentProvider` in any case. Mostly we process data which is based on [`wcf\data\DatabaseObject`](php_database-objects.md). In this case, the WoltLab Suite provides an abstract class `wcf\system\user\content\provider\AbstractDatabaseUserContentProvider` that can be used to automatically generates the standardized classes to generate the list and deletes objects via the DatabaseObjectAction. For example, if we would create a content provider for comments, the class would look like this:
```php
<?php
## PHP Database API
WoltLab Suite 5.2 introduces a new way to update the database scheme:
-[database PHP API](package_database-php-api.html).
\ No newline at end of file
+[database PHP API](package_database-php-api.md).
\ No newline at end of file
If you need to specify additional HTML attributes for the anchor tag you can use the new [`StringUtil::getAnchorTagAttributes(string, bool): string`](https://github.com/WoltLab/WCF/blob/af245d7b9bdb411a344f79c0a038350c1f103e70/wcfsetup/install/files/lib/util/StringUtil.class.php#L691-L699) method to generate the anchor attributes that are dependent on the target URL.
Specifically the attributes returned are the `class="externalURL"` attribute, the `rel="…"` attribute and the `target="…"` attribute.
-Within the template the [`{anchorAttributes}`](view_template-plugins.html#53-anchorattributes) template plugin is newly available.
+Within the template the [`{anchorAttributes}`](view_template-plugins.md#53-anchorattributes) template plugin is newly available.
## Resource Management When Scaling Images
## Template Plugins
-The [`{anchor}`](view_template-plugins.html#53-anchor), [`{plural}`](view_template-plugins.html#53-plural), and [`{user}`](view_template-plugins.html#53-user) template plugins have been added.
+The [`{anchor}`](view_template-plugins.md#53-anchor), [`{plural}`](view_template-plugins.md#53-plural), and [`{user}`](view_template-plugins.md#53-user) template plugins have been added.
## Notification Language Items
No breaking changes are expected for simple uses.
A detailed [Guzzle migration guide](https://github.com/guzzle/guzzle/blob/master/UPGRADING.md#60-to-70) can be found in the Guzzle documentation.
-The explicit `sink` that was recommended in the [migration guide for WSC 5.2](migration_wsc-52_libraries.html#guzzle) can now be removed, as [the Guzzle issue #2735](https://github.com/guzzle/guzzle/issues/2735) was fixed in Guzzle 7.
+The explicit `sink` that was recommended in the [migration guide for WSC 5.2](migration_wsc-52_libraries.md#guzzle) can now be removed, as [the Guzzle issue #2735](https://github.com/guzzle/guzzle/issues/2735) was fixed in Guzzle 7.
## Emogrifier / CSS Inliner
{% include callout.html content="Available since WoltLab Suite 5.2." type="info" %}
-While the [sql](package_pip_sql.html) package installation plugin supports adding and removing tables, columns, and indices, it is not able to handle cases where the added table, column, or index already exist.
-We have added a new PHP-based API to manipulate the database scheme which can be used in combination with the [script](package_pip_script.html) package installation plugin that skips parts that already exist:
+While the [sql](package_pip_sql.md) package installation plugin supports adding and removing tables, columns, and indices, it is not able to handle cases where the added table, column, or index already exist.
+We have added a new PHP-based API to manipulate the database scheme which can be used in combination with the [script](package_pip_script.md) package installation plugin that skips parts that already exist:
```php
$tables = [
<instruction type="objectTypeDefinition" />
```
-There is a [list of all default PIPs](package_pip.html) available.
+There is a [list of all default PIPs](package_pip.md) available.
{% include callout.html content="Both the `type`-attribute and the element value are case-sensitive. Windows does not care if the file is called `objecttypedefinition.xml` but was referenced as `objectTypeDefinition.xml`, but both Linux and Mac systems will be unable to find the file." type="warning" %}
| Name | Description |
|------|-------------|
-| [aclOption][package_pip_acl-option] | Customizable permissions for individual objects |
-| [acpMenu][package_pip_acp-menu] | Admin panel menu categories and items |
-| [acpSearchProvider][package_pip_acp-search-provider] | Data provider for the admin panel search |
-| [acpTemplate][package_pip_acp-template] | Admin panel templates |
-| [bbcode][package_pip_bbcode] | BBCodes for rich message formatting |
-| [box][package_pip_box] | Boxes that can be placed anywhere on a page |
-| [clipboardAction][package_pip_clipboard_action] | Perform bulk operations on marked objects |
-| [coreObject][package_pip_core-object] | Access Singletons from within the template |
-| [cronjob][package_pip_cronjob] | Periodically execute code with customizable intervals |
-| [eventListener][package_pip_event-listener] | Register listeners for the event system |
-| [file][package_pip_file] | Deploy any type of files with the exception of templates |
-| [language][package_pip_language] | Language items |
-| [mediaProvider][package_pip_media-provider] | Detect and convert links to media providers |
-| [menu][package_pip_menu] | Side-wide and custom per-page menus |
-| [menuItem][package_pip_menu-item] | Menu items for menus created through the menu PIP |
-| [objectType][package_pip_object-type] | Flexible type registry based on definitions |
-| [objectTypeDefinition][package_pip_object-type-definition] | Groups objects and classes by functionality |
-| [option][package_pip_option] | Side-wide configuration options |
-| [page][package_pip_page] | Register page controllers and text-based pages |
-| [pip][package_pip_pip] | Package Installation Plugins |
-| [script][package_pip_script] | Execute arbitrary PHP code during installation, update and uninstallation |
-| [smiley][package_pip_smiley] | Smileys |
-| [sql][package_pip_sql] | Execute SQL instructions using a MySQL-flavored syntax (also see [database PHP API](package_database-php-api.html)) |
-| [style][package_pip_style] | Style |
-| [template][package_pip_template] | Frontend templates |
-| [templateListener][package_pip_template-listener] | Embed template code into templates without altering the original |
-| [userGroupOption][package_pip_user-group-option] | Permissions for user groups |
-| [userMenu][package_pip_user-menu] | User menu categories and items |
-| [userNotificationEvent][package_pip_user-notification-event] | Events of the user notification system |
-| [userOption][package_pip_user-option] | User settings |
-| [userProfileMenu][package_pip_user-profile-menu] | User profile tabs |
+| [aclOption](package_pip_acl-option.md) | Customizable permissions for individual objects |
+| [acpMenu](package_pip_acp-menu.md) | Admin panel menu categories and items |
+| [acpSearchProvider](package_pip_acp-search-provider.md) | Data provider for the admin panel search |
+| [acpTemplate](package_pip_acp-template.md) | Admin panel templates |
+| [bbcode](package_pip_bbcode.md) | BBCodes for rich message formatting |
+| [box](package_pip_box.md) | Boxes that can be placed anywhere on a page |
+| [clipboardAction](package_pip_clipboard_action.md) | Perform bulk operations on marked objects |
+| [coreObject](package_pip_core-object.md) | Access Singletons from within the template |
+| [cronjob](package_pip_cronjob.md) | Periodically execute code with customizable intervals |
+| [eventListener](package_pip_event-listener.md) | Register listeners for the event system |
+| [file](package_pip_file.md) | Deploy any type of files with the exception of templates |
+| [language](package_pip_language.md) | Language items |
+| [mediaProvider](package_pip_media-provider.md) | Detect and convert links to media providers |
+| [menu](package_pip_menu.md) | Side-wide and custom per-page menus |
+| [menuItem](package_pip_menu-item.md) | Menu items for menus created through the menu PIP |
+| [objectType](package_pip_object-type.md) | Flexible type registry based on definitions |
+| [objectTypeDefinition](package_pip_object-type-definition.md) | Groups objects and classes by functionality |
+| [option](package_pip_option.md) | Side-wide configuration options |
+| [page](package_pip_page.md) | Register page controllers and text-based pages |
+| [pip](package_pip_pip.md) | Package Installation Plugins |
+| [script](package_pip_script.md) | Execute arbitrary PHP code during installation, update and uninstallation |
+| [smiley](package_pip_smiley.md) | Smileys |
+| [sql](package_pip_sql.md) | Execute SQL instructions using a MySQL-flavored syntax (also see [database PHP API.md)(package_database-php-api.md)) |
+| [style](package_pip_style.md) | Style |
+| [template](package_pip_template.md) | Frontend templates |
+| [templateListener](package_pip_template-listener.md) | Embed template code into templates without altering the original |
+| [userGroupOption](package_pip_user-group-option.md) | Permissions for user groups |
+| [userMenu](package_pip_user-menu.md) | User menu categories and items |
+| [userNotificationEvent](package_pip_user-notification-event.md) | Events of the user notification system |
+| [userOption](package_pip_user-option.md) | User settings |
+| [userProfileMenu](package_pip_user-profile-menu.md) | User profile tabs |
### `<objectType>`
-Required for boxes with `boxType = system`, must be registered through [the objectType PIP](package_pip_object-type.html) for the definition `com.woltlab.wcf.boxController`.
+Required for boxes with `boxType = system`, must be registered through [the objectType PIP](package_pip_object-type.md) for the definition `com.woltlab.wcf.boxController`.
### `<position>`
---
Registers event listeners.
-An explanation of events and event listeners can be found [here](php_api_events.html).
+An explanation of events and event listeners can be found [here](php_api_events.md).
## Components
{% include callout.html content="You cannot overwrite files provided by other packages." type="warning" %}
-The `application` attribute behaves like it does for [acp templates](package_pip_acp-template.html#application).
+The `application` attribute behaves like it does for [acp templates](package_pip_acp-template.md#application).
## Archive
### `<menu>`
-The target menu that the item should be added to, requires the internal identifier set by creating a menu through the [menu.xml][package_pip_menu].
+The target menu that the item should be added to, requires the internal identifier set by creating a menu through the [menu.xml](package_pip_menu.md).
### `<title>`
### `<page>`
-The page that the link should point to, requires the internal identifier set by creating a page through the [page.xml][package_pip_page].
+The page that the link should point to, requires the internal identifier set by creating a page through the [page.xml](package_pip_page.md).
## Example
### `<box>`
-The following elements of the [box PIP](package_pip_box.html) are supported, please refer to the documentation to learn more about them:
+The following elements of the [box PIP](package_pip_box.md) are supported, please refer to the documentation to learn more about them:
* `<position>`
* `<showHeader>`
---
Registers an object type definition.
-An object type definition is a blueprint for a certain behaviour that is particularized by [objectTypes](package_pip_object-type.html).
+An object type definition is a blueprint for a certain behaviour that is particularized by [objectTypes](package_pip_object-type.md).
As an example: Tags can be attached to different types of content (such as forum posts or gallery images).
The bulk of the work is implemented in a generalized fashion, with all the tags stored in a single database table.
Certain things, such as permission checking, need to be particularized for the specific type of content, though.
<span class="label label-info">Optional</span>
-The name of the PHP interface [objectTypes](package_pip_object-type.html) have to implement.
+The name of the PHP interface [objectTypes](package_pip_object-type.md) have to implement.
## Example
---
Registers an object type.
-Read about object types in the [objectTypeDefinition](package_pip_object-type-definition.html) PIP.
+Read about object types in the [objectTypeDefinition](package_pip_object-type-definition.md) PIP.
## Components
### `<definitionname>`
-The `<name>` of the [objectTypeDefinition](package_pip_object-type-definition.html).
+The `<name>` of the [objectTypeDefinition](package_pip_object-type-definition.md).
### `<classname>`
Execute arbitrary PHP code during installation, update and uninstallation of the package.
-{% include callout.html content="You must install the PHP script through the [file package installation plugin](package_pip_file.html)." type="warning" %}
+{% include callout.html content="You must install the PHP script through the [file package installation plugin](package_pip_file.md)." type="warning" %}
{% include callout.html content="The installation will attempt to delete the script after successful execution." type="warning" %}
### `application`
The `application` attribute must have the same value as the `application` attribute of the `file` package installation plugin instruction so that the correct file in the intended application directory is executed.
-For further information about the `application` attribute, refer to its documentation on the [acpTemplate package installation plugin page](package_pip_acp-template.html#application).
+For further information about the `application` attribute, refer to its documentation on the [acpTemplate package installation plugin page](package_pip_acp-template.md#application).
## Expected value
### Naming convention
-The PHP script is deployed by using the [file package installation plugin](package_pip_file.html).
+The PHP script is deployed by using the [file package installation plugin](package_pip_file.md).
To prevent it from colliding with other install script (remember: You cannot overwrite files created by another plugin), we highly recommend to make use of these naming conventions:
- Installation: `install_<package>_<version>.php` (example: `install_com.woltlab.wbb_5.0.0.php`)
### `<path(2x)?>`
-{% include important.html content="The files must be installed using the [file](package_pip_file.html) PIP." %}
+{% include important.html content="The files must be installed using the [file](package_pip_file.md) PIP." %}
File path relative to the root of WoltLab Suite Core.
`path2x` is optional and being used for High-DPI screens.
### Triggers
WoltLab Suite Core does not support trigger since MySQL does not support execution of triggers if the event was fired by a cascading foreign key action.
-If you really need triggers, you should consider adding them by custom SQL queries using a [script](package_pip_script.html).
+If you really need triggers, you should consider adding them by custom SQL queries using a [script](package_pip_script.md).
## Example
---
Registers template listeners.
-Template listeners supplement [event listeners](package_pip_event-listener.html), which modify server side behaviour, by adding additional template code to display additional elements.
+Template listeners supplement [event listeners](package_pip_event-listener.md), which modify server side behaviour, by adding additional template code to display additional elements.
The added template code behaves as if it was part of the original template (i.e. it has access to all local variables).
## Components
{% include callout.html content="You cannot overwrite templates provided by other packages." type="warning" %}
-This package installation plugin behaves exactly like the [acpTemplate package installation plugin](package_pip_acp-template.html) except for installing frontend templates instead of backend/acp templates.
+This package installation plugin behaves exactly like the [acpTemplate package installation plugin](package_pip_acp-template.md) except for installing frontend templates instead of backend/acp templates.
---
Registers new user group options (“permissions”).
-The behaviour of this package installation plugin closely follows the [option](package_pip_option.html) PIP.
+The behaviour of this package installation plugin closely follows the [option](package_pip_option.md) PIP.
## Category Components
---
Registers new user options (profile fields / user settings).
-The behaviour of this package installation plugin closely follows the [option](package_pip_option.html) PIP.
+The behaviour of this package installation plugin closely follows the [option](package_pip_option.md) PIP.
## Category Components
WoltLab Suite offers two distinct types of caches:
-1. [Persistent caches](php_api_caches_persistent-caches.html) created by cache builders whose data can be stored using different cache sources.
-2. [Runtime caches](php_api_caches_runtime-caches.html) store objects for the duration of a single request.
+1. [Persistent caches](php_api_caches_persistent-caches.md) created by cache builders whose data can be stored using different cache sources.
+2. [Runtime caches](php_api_caches_runtime-caches.md) store objects for the duration of a single request.
## Understanding Caching
decision if you should use a cache or not. When in doubt, you should opt to not
use them, because they also come at a hidden cost that cannot be expressed through
simple SQL query counts. If you haven't already, it is recommended that you read
-the [introduction article on caching][php_api_caches] first, it provides a bit
+the [introduction article on caching](php_api_caches.md) first, it provides a bit
of background on caches and examples that should help you in your decision.
## `AbstractCacheBuilder`
{% include callout.html content="The execution of cronjobs is not guaranteed but requires someone to access the page with JavaScript enabled." type="warning" %}
-This page focuses on the technical aspects of cronjobs, [the cronjob package installation plugin page](package_pip_cronjob.html) covers how you can actually register a cronjob.
+This page focuses on the technical aspects of cronjobs, [the cronjob package installation plugin page](package_pip_cronjob.md) covers how you can actually register a cronjob.
## Example
Every cronjob needs to implement the `wcf\system\cronjob\ICronjob` interface which requires the `execute(Cronjob $cronjob)` method to be implemented.
This method is called by [wcf\system\cronjob\CronjobScheduler](https://github.com/WoltLab/WCF/blob/master/wcfsetup/install/files/lib/system/cronjob/CronjobScheduler.class.php) when executing the cronjobs.
-In practice, however, you should extend the `AbstractCronjob` class and also call the `AbstractCronjob::execute()` method as it fires an event which makes cronjobs extendable by plugins (see [event documentation](php_event.html)).
+In practice, however, you should extend the `AbstractCronjob` class and also call the `AbstractCronjob::execute()` method as it fires an event which makes cronjobs extendable by plugins (see [event documentation](php_api_events.md)).
## Executing Cronjobs Through CLI
WoltLab Suite's event system allows manipulation of program flows and data without having to change any of the original source code.
At many locations throughout the PHP code of WoltLab Suite Core and mainly through inheritance also in the applications and plugins, so called *events* are fired which trigger registered *event listeners* that get access to the object firing the event (or at least the class name if the event has been fired in a static method).
-This page focuses on the technical aspects of events and event listeners, [the eventListener package installation plugin page](package_pip_event-listener.html) covers how you can actually register an event listener.
-A comprehensive list of all available events is provided [here](php_api_event_list.html).
+This page focuses on the technical aspects of events and event listeners, [the eventListener package installation plugin page](package_pip_event-listener.md) covers how you can actually register an event listener.
+A comprehensive list of all available events is provided [here](php_api_event_list.md).
## Introductory Example
One common reason to use event listeners is to add an additional field to a pre-existing form (in combination with template listeners, which we will not cover here).
We will assume that users are able to do both, create and edit the objects via this form.
-The points in the program flow of [AbstractForm](php_pages.html#abstractform) that are relevant here are:
+The points in the program flow of [AbstractForm](php_pages.md#abstractform) that are relevant here are:
- adding object (after the form has been submitted):
1. reading the value of the field
During edits, this current value is the actual value that should be shown.
- `validate()` also needs to be called in both cases as the input data always has to be validated.
-Lastly, the following XML file has to be used to register the event listeners (you can find more information about how to register event listeners on [the eventListener package installation plugin page](package_pip_event-listener.html)):
+Lastly, the following XML file has to be used to register the event listeners (you can find more information about how to register event listeners on [the eventListener package installation plugin page](package_pip_event-listener.md)):
```xml
<?xml version="1.0" encoding="UTF-8"?>
By default, `ItemListFormField::SAVE_VALUE_TYPE_CSV` is used.
-If `ItemListFormField::SAVE_VALUE_TYPE_ARRAY` is used as save value type, `ItemListFormField` objects register a [custom form field data processor](php_api_form_builder-validation_data.html#customformfielddataprocessor) to add the relevant array into the `$parameters` array directly using the object property as the array key.
+If `ItemListFormField::SAVE_VALUE_TYPE_ARRAY` is used as save value type, `ItemListFormField` objects register a [custom form field data processor](php_api_form_builder-validation_data.md#customformfielddataprocessor) to add the relevant array into the `$parameters` array directly using the object property as the array key.
### `MultilineTextFormField`
Additionally, the class provides the methods `categoryName($categoryName)` and `getCategoryName()` that allow setting a specific name or filter for the acl option categories whose acl options are shown.
A category name of `null` signals that no category filter is used.
-`AclFormField` objects register a [custom form field data processor](php_api_form_builder-validation_data.html#customformfielddataprocessor) to add the relevant ACL object type id into the `$parameters` array directly using `{$objectProperty}_aclObjectTypeID` as the array key.
+`AclFormField` objects register a [custom form field data processor](php_api_form_builder-validation_data.md#customformfielddataprocessor) to add the relevant ACL object type id into the `$parameters` array directly using `{$objectProperty}_aclObjectTypeID` as the array key.
The relevant database object action method is expected, based on the given ACL object type id, to save the ACL option values appropriately.
`SimpleAclFormField` is used for setting up simple acl values (one `yes`/`no` option per user and user group) for specific objects.
-`SimpleAclFormField` objects register a [custom form field data processor](php_api_form_builder-validation_data.html#customformfielddataprocessor) to add the relevant simple ACL data array into the `$parameters` array directly using the object property as the array key.
+`SimpleAclFormField` objects register a [custom form field data processor](php_api_form_builder-validation_data.md#customformfielddataprocessor) to add the relevant simple ACL data array into the `$parameters` array directly using the object property as the array key.
### `SingleMediaSelectionFormField`
Arrays passed to `TagFormField::values()` can contain tag names as strings and `Tag` objects.
The default label of instances of this class is `wcf.tagging.tags` and their default description is `wcf.tagging.tags.description`.
-`TagFormField` objects register a [custom form field data processor](php_api_form_builder-validation_data.html#customformfielddataprocessor) to add the array with entered tag names into the `$parameters` array directly using the object property as the array key.
+`TagFormField` objects register a [custom form field data processor](php_api_form_builder-validation_data.md#customformfielddataprocessor) to add the array with entered tag names into the `$parameters` array directly using the object property as the array key.
### `UploadFormField`
`UploadFormField` is a form field that allows uploading files by the user.
-`UploadFormField` objects register a [custom form field data processor](php_api_form_builder-validation_data.html#customformfielddataprocessor) to add the array of `wcf\system\file\upload\UploadFile\UploadFile` into the `$parameters` array directly using the object property as the array key. Also it registers the removed files as an array of `wcf\system\file\upload\UploadFile\UploadFile` into the `$parameters` array directly using the object property with the suffix `_removedFiles` as the array key.
+`UploadFormField` objects register a [custom form field data processor](php_api_form_builder-validation_data.md#customformfielddataprocessor) to add the array of `wcf\system\file\upload\UploadFile\UploadFile` into the `$parameters` array directly using the object property as the array key. Also it registers the removed files as an array of `wcf\system\file\upload\UploadFile\UploadFile` into the `$parameters` array directly using the object property with the suffix `_removedFiles` as the array key.
The field supports additional settings:
- `imageOnly($imageOnly = true)` and `isImageOnly()` can be used to ensure that the uploaded files are only images.
{% include callout.html content="It is not sufficient to simply signal attachment support via these methods for attachments to work. These methods are relevant internally to signal the Javascript code that the editor supports attachments. Actual attachment support is provided by `WysiwygAttachmentFormField`." type="warning" %}
- `supportMentions($supportMentions)` and `supportsMentions()` can be used to set and check if the form field supports mentions of other users.
-`WysiwygFormField` objects register a [custom form field data processor](php_api_form_builder-validation_data.html#customformfielddataprocessor) to add the relevant simple ACL data array into the `$parameters` array directly using the object property as the array key.
+`WysiwygFormField` objects register a [custom form field data processor](php_api_form_builder-validation_data.md#customformfielddataprocessor) to add the relevant simple ACL data array into the `$parameters` array directly using the object property as the array key.
### `TWysiwygFormNode`
By default, a form node has no CSS classes.
- `addDependency(IFormFieldDependency $dependency)`, `removeDependency($dependencyId)`, `getDependencies()`, and `hasDependency($dependencyId)` add, remove, get, and check for dependencies of this form node on other form fields.
`checkDependencies()` checks if **all** of the node’s dependencies are met and returns a boolean value reflecting the check’s result.
- The [form builder dependency documentation](php_api_form_builder-dependencies.html) provides more detailed information about dependencies and how they work.
+ The [form builder dependency documentation](php_api_form_builder-dependencies.md) provides more detailed information about dependencies and how they work.
By default, a form node has no dependencies.
- `attribute($name, $value = null)`, `removeAttribute($name)`, `getAttribute($name)`, `getAttributes()`, `hasAttribute($name)` add, remove, get, and check for attributes of the HTML element represting the form node.
The attributes are added to the same element that the CSS classes are added to.
`IFormField` requires the following additional methods:
-- `addValidationError(IFormFieldValidationError $error)` and `getValidationErrors()` can be used to get and set validation errors of the form field (see [form validation](php_api_form_builder-validation_data.html#form-validation)).
-- `addValidator(IFormFieldValidator $validator)`, `getValidators()`, `removeValidator($validatorId)`, and `hasValidator($validatorId)` can be used to get, set, remove, and check for validators for the form field (see [form validation](php_api_form_builder-validation_data.html#form-validation)).
+- `addValidationError(IFormFieldValidationError $error)` and `getValidationErrors()` can be used to get and set validation errors of the form field (see [form validation](php_api_form_builder-validation_data.md#form-validation)).
+- `addValidator(IFormFieldValidator $validator)`, `getValidators()`, `removeValidator($validatorId)`, and `hasValidator($validatorId)` can be used to get, set, remove, and check for validators for the form field (see [form validation](php_api_form_builder-validation_data.md#form-validation)).
- `getFieldHtml()` returns the field's HTML output without the surrounding `dl` structure.
- `objectProperty($objectProperty)` and `getObjectProperty()` can be used to get and set the object property that the field represents.
When setting the object property is set to an empty string, the previously set object property is unset.
`AbstractFormField` provides default implementations of many of the listed methods above and should be extended instead of implementing `IFormField` directly.
-An overview of the form fields provided by default can be found [here](php_api_form_builder-form_fields.html).
+An overview of the form fields provided by default can be found [here](php_api_form_builder-form_fields.md).
### Form Field Interfaces and Traits
- `hasI18nValues()` and `hasPlainValue()` check if the current value is a multilingual or monolingual value.
`TI18nFormField` provides a default implementation of these eight methods and additional default implementations of some of the `IFormField` methods.
-If multilingual input is enabled for a specific form field, classes using `TI18nFormField` register a [custom form field data processor](php_api_form_builder-validation_data.html#customformfielddataprocessor) to add the array with multilingual input into the `$parameters` array directly using `{$objectProperty}_i18n` as the array key.
+If multilingual input is enabled for a specific form field, classes using `TI18nFormField` register a [custom form field data processor](php_api_form_builder-validation_data.md#customformfielddataprocessor) to add the array with multilingual input into the `$parameters` array directly using `{$objectProperty}_i18n` as the array key.
If multilingual input is enabled but only a monolingual value is entered, the custom form field data processor does nothing and the form field’s value is added by the `DefaultFormDataProcessor` into the `data` sub-array of the `$parameters` array.
{% include callout.html content="`TI18nFormField` already provides a default implementation of `IFormField::validate()`." type="info" %}
By default, there is no maximum number of values.
`IMultipleFormField::NO_MAXIMUM_MULTIPLES` is returned if no maximum number of values has been set and it can also be used to unset a previously set maximum number of values.
-`TMultipleFormField` provides a default implementation of these six methods and classes using `TMultipleFormField` register a [custom form field data processor](php_api_form_builder-validation_data.html#customformfielddataprocessor) to add the `HtmlInputProcessor` object with the text into the `$parameters` array directly using `{$objectProperty}_htmlInputProcessor` as the array key.
+`TMultipleFormField` provides a default implementation of these six methods and classes using `TMultipleFormField` register a [custom form field data processor](php_api_form_builder-validation_data.md#customformfielddataprocessor) to add the `HtmlInputProcessor` object with the text into the `$parameters` array directly using `{$objectProperty}_htmlInputProcessor` as the array key.
{% include callout.html content="The implementing class has to validate the values against the minimum and maximum number of values manually." type="warning" %}
{% include callout.html content="Form builder is only available since WoltLab Suite Core 5.2." type="info" %}
-{% include callout.html content="The [migration guide for WoltLab Suite Core 5.2](migration_wsc-31_form-builder.html) provides some examples of how to migrate existing forms to form builder that can also help in understanding form builder if the old way of creating forms is familiar." type="info" %}
+{% include callout.html content="The [migration guide for WoltLab Suite Core 5.2](migration_wsc-31_form-builder.md) provides some examples of how to migrate existing forms to form builder that can also help in understanding form builder if the old way of creating forms is familiar." type="info" %}
## Advantages of Form Builder
Form builder consists of several components that are presented on the following pages:
-1. [Structure of form builder](php_api_form_builder-structure.html)
-1. [Form validation and form data](php_api_form_builder-validation_data.html)
-1. [Form node dependencies](php_api_form_builder-dependencies.html)
+1. [Structure of form builder](php_api_form_builder-structure.md)
+1. [Form validation and form data](php_api_form_builder-validation_data.md)
+1. [Form node dependencies](php_api_form_builder-dependencies.md)
{% include callout.html content="In general, form builder provides default implementation of interfaces by providing either abstract classes or traits.
It is expected that the interfaces are always implemented using these abstract classes and traits!
# Package Installation Plugins
-A package installation plugin (PIP) defines the behavior to handle a specific [instruction](package_package-xml.html#instruction) during package installation, update or uninstallation.
+A package installation plugin (PIP) defines the behavior to handle a specific [instruction](package_package-xml.md#instruction) during package installation, update or uninstallation.
## `AbstractPackageInstallationPlugin`
```php
<?php
return [
- 'environment' => $data['elements']['environment'],
- 'eventName' => $data['elements']['eventname'],
- 'name' => $data['attributes']['name']
+ 'environment' => $data['elements']['environment'.md],
+ 'eventName' => $data['elements']['eventname'.md],
+ 'name' => $data['attributes']['name'.md]
];
```
foreach ($items as $item) {
$statement->execute([
$this->installation->getPackageID(),
- $item['elements']['environment'],
- $item['elements']['eventname'],
- $item['attributes']['name'],
- $item['elements']['templatename']
+ $item['elements']['environment'.md],
+ $item['elements']['eventname'.md],
+ $item['attributes']['name'.md],
+ $item['elements']['templatename'.md]
]);
}
```
## `userNotificationEvent.xml`
-Each event that you fire in your package needs to be registered using the [user notification event package installation plugin](package_pip_user-notification-event.html).
+Each event that you fire in your package needs to be registered using the [user notification event package installation plugin](package_pip_user-notification-event.md).
An example file might look like this:
```xml
By checking the value of `count($this->getAuthors())`, we check if the notification is stacked, thus if the event has been triggered for multiple users so that different languages items are used.
If your notification event does not support stacking, this distinction is not necessary.
- The `prepare()` method is called for each user notification before all user notifications are rendered.
- This allows to tell runtime caches to prepare to load objects later on (see [Runtime Caches](php_api_caches_runtime-caches.html)).
+ This allows to tell runtime caches to prepare to load objects later on (see [Runtime Caches](php_api_caches_runtime-caches.md)).
## Firing Events
{% include callout.html content="The following code style conventions are used by us for our own packages. While you do not have to follow every rule, you are encouraged to do so." type="info" %}
-For information about how to document your code, please refer to the [documentation page](php_code-style_documentation.html).
+For information about how to document your code, please refer to the [documentation page](php_code-style_documentation.md).
## General Code Style
# Database Access
-[Database Objects][php_database-objects] provide a convenient and object-oriented approach to work with the database, but there can be use-cases that require raw access including writing methods for model classes. This section assumes that you have either used [prepared statements](https://en.wikipedia.org/wiki/Prepared_statement) before or at least understand how it works.
+[Database Objects](php_database-objects.md) provide a convenient and object-oriented approach to work with the database, but there can be use-cases that require raw access including writing methods for model classes. This section assumes that you have either used [prepared statements.md)(https://en.wikipedia.org/wiki/Prepared_statement) before or at least understand how it works.
## The PreparedStatement Object
We will start this tutorial series by creating a base structure for the package and then continue by adding further features step by step using different APIs.
Note that in the context of this example, not every added feature might make perfect sense but the goal of this tutorial is not to create a useful package but to introduce you to WoltLab Suite.
-- [Part 1: Base Structure](tutorial_tutorial-series_part-1-base-structure.html)
-- [Part 2: Event Listeners and Template Listeners](tutorial_tutorial-series_part-2-event-listeners-and-template-listeners.html)
-- [Part 3: Person Page and Comments](tutorial_tutorial-series_part-3-person-page-and-comments.html)
+- [Part 1: Base Structure](tutorial_tutorial-series_part-1-base-structure.md)
+- [Part 2: Event Listeners and Template Listeners](tutorial_tutorial-series_part-2-event-listeners-and-template-listeners.md)
+- [Part 3: Person Page and Comments](tutorial_tutorial-series_part-3-person-page-and-comments.md)
We will use the following package installation plugins:
-- [acpTemplate package installation plugin](package_pip_acp-template.html),
-- [acpMenu package installation plugin](package_pip_acp-menu.html),
-- [file package installation plugin](package_pip_file.html),
-- [language package installation plugin](package_pip_language.html),
-- [menuItem package installation plugin](package_pip_menu-item.html),
-- [page package installation plugin](package_pip_page.html),
-- [sql package installation plugin](package_pip_sql.html),
-- [template package installation plugin](package_pip_template.html),
-- [userGroupOption package installation plugin](package_pip_user-group-option.html),
+- [acpTemplate package installation plugin](package_pip_acp-template.md),
+- [acpMenu package installation plugin](package_pip_acp-menu.md),
+- [file package installation plugin](package_pip_file.md),
+- [language package installation plugin](package_pip_language.md),
+- [menuItem package installation plugin](package_pip_menu-item.md),
+- [page package installation plugin](package_pip_page.md),
+- [sql package installation plugin](package_pip_sql.md),
+- [template package installation plugin](package_pip_template.md),
+- [userGroupOption package installation plugin](package_pip_user-group-option.md),
-use [database objects](php_database-objects.html), create [pages](php_pages.html) and use [templates](view_templates.html).
+use [database objects](php_database-objects.md), create [pages](php_pages.md) and use [templates](view_templates.md).
## Package Structure
This implementation of `AbstractDatabaseObjectAction` is very basic and only sets the `$permissionsDelete` and `$requireACP` properties.
This is done so that later on, when implementing the people list for the ACP, we can delete people simply via AJAX.
`$permissionsDelete` has to be set to the permission needed in order to delete a person.
-We will later use the [userGroupOption package installation plugin](package_pip_user-group-option.html) to create the `admin.content.canManagePeople` permission.
+We will later use the [userGroupOption package installation plugin](package_pip_user-group-option.md) to create the `admin.content.canManagePeople` permission.
`$requireACP` restricts deletion of people to the ACP.
#### `PersonEditor`
### `page.xml`
-First, let us register the page with the system because every front end page or form needs to be explicitly registered using the [page package installation plugin](package_pip_page.html):
+First, let us register the page with the system because every front end page or form needs to be explicitly registered using the [page package installation plugin](package_pip_page.md):
{% highlight xml %}
{% include tutorial/tutorial-series/part-1/page.xml %}
{% endhighlight %}
-For more information about what each of the elements means, please refer to the [page package installation plugin page](package_pip_page.html).
+For more information about what each of the elements means, please refer to the [page package installation plugin page](package_pip_page.md).
### `menuItem.xml`
-Next, we register the menu item using the [menuItem package installation plugin](package_pip_menuItem.html):
+Next, we register the menu item using the [menuItem package installation plugin](package_pip_menu-item.md):
{% highlight xml %}
{% include tutorial/tutorial-series/part-1/menuItem.xml %}
## `userGroupOption.xml`
-We have already used the `admin.content.canManagePeople` permissions several times, now we need to install it using the [userGroupOption package installation plugin](package_pip_user-group-option.html):
+We have already used the `admin.content.canManagePeople` permissions several times, now we need to install it using the [userGroupOption package installation plugin](package_pip_user-group-option.md):
{% highlight xml %}
{% include tutorial/tutorial-series/part-1/userGroupOption.xml %}
## `package.xml`
Lastly, we need to create the `package.xml` file.
-For more information about this kind of file, please refer to [the `package.xml` page](package_package-xml.html).
+For more information about this kind of file, please refer to [the `package.xml` page](package_package-xml.md).
{% highlight xml %}
{% include tutorial/tutorial-series/part-1/package.xml %}
parent: tutorial_tutorial-series
---
-In the [first part](tutorial_tutorial-series_part-1-base-structure.html) of this tutorial series, we have created the base structure of our people management package.
+In the [first part](tutorial_tutorial-series_part-1-base-structure.md) of this tutorial series, we have created the base structure of our people management package.
In further parts, we will use the package of the first part as a basis to directly add new features.
In order to explain how event listeners and template works, however, we will not directly adding a new feature to the package by altering it in this part, but we will assume that somebody else created the package and that we want to extend it the “correct” way by creating a plugin.
We will use the following package installation plugins:
-- [acpTemplate package installation plugin](package_pip_acp-template.html),
-- [eventListener package installation plugin](package_pip_event-listener.html),
-- [file package installation plugin](package_pip_file.html),
-- [language package installation plugin](package_pip_language.html),
-- [sql package installation plugin](package_pip_sql.html),
-- [template package installation plugin](package_pip_template.html),
-- [templateListener package installation plugin](package_pip_template-listener.html).
+- [acpTemplate package installation plugin](package_pip_acp-template.md),
+- [eventListener package installation plugin](package_pip_event-listener.md),
+- [file package installation plugin](package_pip_file.md),
+- [language package installation plugin](package_pip_language.md),
+- [sql package installation plugin](package_pip_sql.md),
+- [template package installation plugin](package_pip_template.md),
+- [templateListener package installation plugin](package_pip_template-listener.md).
-For more information about the event system, please refer to the [dedicated page on events](php_api_events.html).
+For more information about the event system, please refer to the [dedicated page on events](php_api_events.md).
## Package Structure
## Extending Person Model (`install.sql`)
The existing model of a person only contains the person’s first name and their last name (in additional to the id used to identify created people).
-To add the birthday to the model, we need to create an additional database table column using the [sql package installation plugin](package_pip_sql.html):
+To add the birthday to the model, we need to create an additional database table column using the [sql package installation plugin](package_pip_sql.md):
{% highlight sql %}
{% include tutorial/tutorial-series/part-2/install.sql %}
{% endhighlight %}
-If we have a [Person object](tutorial_tutorial-series_part-1-base-structure.html#person), this new property can be accessed the same way as the `personID` property, the `firstName` property, or the `lastName` property from the base package: `$person->birthday`.
+If we have a [Person object](tutorial_tutorial-series_part-1-base-structure.md#person), this new property can be accessed the same way as the `personID` property, the `firstName` property, or the `lastName` property from the base package: `$person->birthday`.
## Setting Birthday in ACP
{% include tutorial/tutorial-series/part-2/language/en.xml %}
{% endhighlight %}
-The template listener needs to be registered using the [templateListener package installation plugin](package_pip_template-listener.html).
+The template listener needs to be registered using the [templateListener package installation plugin](package_pip_template-listener.md).
The corresponding complete `templateListener.xml` file is included [below](#templatelistenerxml).
The template code alone is not sufficient because the `birthday` field is, at the moment, neither read, nor processed, nor saved by any PHP code.
## Package Functionality
-In addition to the existing functions from [part 1](tutorial_tutorial-series_part-1-base-structure.html), the package will provide the following possibilities/functions after this part of the tutorial:
+In addition to the existing functions from [part 1](tutorial_tutorial-series_part-1-base-structure.md), the package will provide the following possibilities/functions after this part of the tutorial:
- Details page for each person linked in the front end person list
- Comment on people on their respective page (can be disabled per person)
## Used Components
-In addition to the components used in [part 1](tutorial_tutorial-series_part-1-base-structure.html), we will use the [objectType package installation plugin](package_pip_object-type.html), use the [comment API](php_api_comments.html), create a [runtime cache](php_api_caches_runtime-caches.html), and create a page handler.
+In addition to the components used in [part 1](tutorial_tutorial-series_part-1-base-structure.md), we will use the [objectType package installation plugin](package_pip_object-type.md), use the [comment API](php_api_comments.md), create a [runtime cache](php_api_caches_runtime-caches.md), and create a page handler.
## Package Structure
-The complete package will have the following file structure (including the files from [part 1](tutorial_tutorial-series_part-1-base-structure.html)):
+The complete package will have the following file structure (including the files from [part 1](tutorial_tutorial-series_part-1-base-structure.md)):
```
├── acpMenu.xml
## Runtime Cache
-To reduce the number of database queries when different APIs require person objects, we implement a [runtime cache](php_api_caches_runtime-caches.html) for people:
+To reduce the number of database queries when different APIs require person objects, we implement a [runtime cache](php_api_caches_runtime-caches.md) for people:
{% highlight php %}
{% include tutorial/tutorial-series/part-3/files/lib/system/cache/runtime/PersonRuntimeCache.class.php %}
{% endhighlight %}
- First, the system is told the names of the permissions via the `$permission*` properties.
- More information about comment permissions can be found [here](php_api_comments.html#user-group-options).
+ More information about comment permissions can be found [here](php_api_comments.md#user-group-options).
- The `getLink()` method returns the link to the person with the passed comment id.
As in `isAccessible()`, `PersonRuntimeCache` is used to potentially save database queries.
- The `isAccessible()` method checks if the active user can access the relevant person.
including but not limited to dynamic phrases using template scripting and the
built-in support for right-to-left languages.
-Phrases are deployed using the [language][package_pip_language] package
-installation plugin, please also read the [naming conventions for language items](view_languages_naming-conventions.html).
+Phrases are deployed using the [language](package_pip_language.md) package
+installation plugin, please also read the [naming conventions for language items](view_languages_naming-conventions.md).
## Special Phrases
This page contains general rules for naming language items and for their values.
API-specific rules are listed on the relevant API page:
-- [Comments](php_api_comments.html#language-items)
+- [Comments](php_api_comments.md#language-items)
## Forms
## `event`
-`event` provides extension points in templates that [template listeners](package_pip_template-listener.html) can use.
+`event` provides extension points in templates that [template listeners](package_pip_template-listener.md) can use.
```smarty
{event name='foo'}
## <span class="label label-info">5.3+</span> `plural`
`plural` allows to easily select the correct plural form of a phrase based on a given `value`.
-The pluralization logic follows the [Unicode Language Plural Rules](https://unicode-org.github.io/cldr-staging/charts/37/supplemental/language_plural_rules.html) for cardinal numbers.
+The pluralization logic follows the [Unicode Language Plural Rules](https://unicode-org.github.io/cldr-staging/charts/37/supplemental/language_plural_rules.md) for cardinal numbers.
The `#` placeholder within the resulting phrase is replaced by the `value`.
It is automatically formatted using `StringUtil::formatNumeric`.
## Installing Templates
Templates and ACP templates are installed by two different package installation plugins:
-the [template PIP](package_pip_template.html) and the [ACP template PIP](package_pip_acp-template.html).
+the [template PIP](package_pip_template.md) and the [ACP template PIP](package_pip_acp-template.md).
More information about installing templates can be found on those pages.
### Forms
-{% include callout.html content="For new forms, use the new [form builder API](php_api_form_builder.html) introduced with WoltLab Suite 5.2." type="info" %}
+{% include callout.html content="For new forms, use the new [form builder API](php_api_form_builder.md) introduced with WoltLab Suite 5.2." type="info" %}
```smarty
<form method="post" action="{link controller='FooBar'}{/link}">
### Template Plugins
-An overview of all available template plugins can be found [here](view_template-plugins.html).
+An overview of all available template plugins can be found [here](view_template-plugins.md).