#### Placeholder Positions
---8<-- "image.html file="boxPlaceholders.png" alt="Visual illustration of placeholder positions""
+![Visual illustration of placeholder positions](../../assets/boxPlaceholders.png)
### `<showHeader>`
- [acpTemplate package installation plugin](../../package/pip/acp-template.md),
- [acpMenu package installation plugin](../../package/pip/acp-menu.md),
+- [database package installation plugin](../../package/pip/database.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),
│ ├── personAdd.tpl
│ └── personList.tpl
├── files
+│ ├── acp
+│ │ └── database
+│ │ └── install_com.woltlab.wcf.people.php
│ └── lib
│ ├── acp
│ │ ├── form
│ │ └── PersonListPage.class.php
│ ├── data
│ │ └── person
-│ │ ├── PersonAction.class.php
│ │ ├── Person.class.php
+│ │ ├── PersonAction.class.php
│ │ ├── PersonEditor.class.php
│ │ └── PersonList.class.php
│ └── page
│ └── PersonListPage.class.php
-├── install.sql
├── language
│ ├── de.xml
│ └── en.xml
1. `firstName` contains the first name of the person,
1. `lastName` contains the last name of the person.
-The first file for our package is the `install.sql` file used to create such a database table during package installation:
+The first file for our package is the `install_com.woltlab.wcf.people.php` file used to create such a database table during package installation:
```sql
---8<-- "tutorial/tutorial-series/part-1/install.sql"
+--8<-- "tutorial/tutorial-series/part-1/files/acp/database/install_com.woltlab.wcf.people.php"
```
### Database Object
1. Now comes the main part of the page, the list of the people, which will only be displayed if any people exist.
Otherwise, an info box is displayed using the generic `wcf.global.noItems` language item.
The `$objects` template variable is automatically assigned by `wcf\page\MultipleLinkPage` and contains the `PersonList` object used to read the people from database.
-
The table itself consists of a `thead` and a `tbody` element and is extendable with more columns using the template events `columnHeads` and `columns`.
In general, every table should provide these events.
The default structure of a table is used here so that the first column of the content rows contains icons to edit and to delete the row (and provides another standard event `rowButtons`) and that the second column contains the ID of the person.
The table can be sorted by clicking on the head of each column.
The used variables `$sortField` and `$sortOrder` are automatically assigned to the template by `SortablePage`.
1. The `.contentFooter` element is only shown if people exist as it basically repeats the `.contentHeaderNavigation` and `.paginationTop` element.
-1. The JavaScript code here fulfills two duties:
- Handling clicks on the delete icons and forwarding the requests via AJAX to the `PersonAction` class, and setting up some code that triggers if all people shown on the current page are deleted via JavaScript to either reload the page or show the `wcf.global.noItems` info box.
+1. The delete button for each person shown in the `.columnIcon` element relies on the global [`WoltLabSuite/Core/Ui/Object/Action`](../../migration/wsc53/javascript.md#wcfactiondelete-and-wcfactiontoggle) module which only requires the `jsObjectActionContainer` CSS class in combination with the `data-object-action-class-name` attribute for the `table` element, the `jsObjectActionObject` CSS class for each person's `tr` element in combination with the `data-object-id` attribute, and lastly the delete button itself, which is created with the [`objectAction` template plugin](../../view/template-plugins.md#view/template-plugins/#54-objectaction).
+1. The [`.jsReloadPageWhenEmpty` CSS class](../../migration/wsc53/javascript.md#wcftableemptytablehandler) on the `tbody` element ensures that once all persons on the page have been deleted, the page is reloaded.
1. Lastly, the `footer` template is included that terminates the page.
You also have to include this template for every page!
--8<-- "tutorial/tutorial-series/part-1/files/lib/acp/form/PersonAddForm.class.php"
```
-The properties here consist of two types:
-the “housekeeping” properties `$activeMenuItem` and `$neededPermissions`, which fulfill the same roles as for `PersonListPage`, and the “data” properties `$firstName` and `$lastName`, which will contain the data entered by the user of the person to be created.
+The properties here consist of three types:
+the “housekeeping” properties `$activeMenuItem` and `$neededPermissions`, which fulfill the same roles as for `PersonListPage`, and the [`$objectEditLinkController` property](../../migration/wsc52/php.md#addform), which is used to generate a link to edit the newly created person after submitting the form, and finally `$formAction` and `$objectActionClass` required by the [PHP form builder API](../../php/api/form_builder/overview.md) used to generate the form.
-Now, let's go through each method in execution order:
+Because of using form builder, we only have to set up the two form fields for entering the first and last name, respectively:
-1. `readFormParameters()` is called after the form has been submitted and reads the entered first and last name and sanitizes the values by calling `StringUtil::trim()`.
-1. `validate()` is called after the form has been submitted and is used to validate the input data.
- In case of invalid data, the method is expected to throw a `UserInputException`.
- Here, the validation for first and last name is the same and quite basic:
- We check that any name has been entered and that it is not longer than the database table column permits.
-1. `save()` is called after the form has been submitted and the entered data has been validated and it creates the new person via `PersonAction`.
- Please note that we do not just pass the first and last name to the action object but merge them with the `$this->additionalFields` array which can be used by event listeners of plugins to add additional data.
- After creating the object, the `saved()` method is called which fires an event for plugins and the data properties are cleared so that the input fields on the page are empty so that another new person can be created.
- Lastly, a `success` variable is assigned to the template which will show a message that the person has been successfully created.
-1. `assignVariables()` assigns the values of the “data” properties to the template and additionally assigns an `action` variable.
- This `action` variable will be used in the template to distinguish between adding a new person and editing an existing person so that which minimal adjustments, we can use the template for both cases.
+1. Each field is a simple single-line text field, thus we use [`TextFormField`](../../php/api/form_builder/form_fields.md#textformfield).
+1. The parameter of the `create()` method expects the id of the field/name of the database object property, which is `firstName` and `lastName`, respectively, here.
+1. The language item of the label shown in the ouput above the input field is set via the `label()` method.
+1. As both fields have to be filled out, `required()` is called, and the maximum length is set via `maximumLength()`.
+1. Lastly, to make it easier to fill out the form more quickly, the first field is auto-focused by calling `autoFocus()`.
#### `personAdd.tpl`
We will now only concentrate on the new parts compared to `personList.tpl`:
1. We use the `$action` variable to distinguish between the languages items used for adding a person and for creating a person.
-1. Including the `formError` template automatically shows an error message if the validation failed.
-1. The `.success` element is shown after successful saving the data and, again, shows different a text depending on the executed action.
-1. The main part is the `form` element which has a common structure you will find in many forms in WoltLab Suite Core.
- The notable parts here are:
- - The `action` attribute of the `form` element is set depending on which controller will handle the request.
- In the link for the edit controller, we can now simply pass the edited `Person` object directly as the `Person` class implements the `IRouteController` interface.
- - The field that caused the validation error can be accessed via `$errorField`.
- - The type of the validation error can be accessed via `$errorType`.
- For an empty input field, we show the generic `wcf.global.form.error.empty` language item.
- In all other cases, we use the error type to determine the object- and property-specific language item to show.
- The approach used here allows plugins to easily add further validation error messages by simply using a different error type and providing the associated language item.
- - Input fields can be grouped into different `.section` elements.
- At the end of each `.section` element, there should be an template event whose name ends with `Fields`.
- The first part of the event name should reflect the type of fields in the particular `.section` element.
- Here, the input fields are just general “data” fields so that the event is called `dataFields`.
- - After the last `.section` element, fire a `section` event so that plugins can add further sections.
- - Lastly, the `.formSubmit` shows the submit button and `{csrfToken}` contains a CSRF token that is automatically validated after the form is submitted.
+1. Because of form builder, we only have to call `{@$form->getHtml()}` to generate all relevant output for the form.
### Person Edit Form
In general, edit forms extend the associated add form so that the code to read and to validate the input data is simply inherited.
-After setting a different active menu item, we declare two new properties for the edited person:
-the id of the person passed in the URL is stored in `$personID` and based on this ID, a `Person` object is created that is stored in the `$person` property.
-
-Now let use go through the different methods in chronological order again:
+After setting a different active menu item, we have to change the value of `$formAction` because this form, in contrast to `PersonAddForm`, does not create but update existing persons.
-1. `readParameters()` reads the passed ID of the edited person and creates a `Person` object based on this ID.
- If the ID is invalid, `$this->person->personID` is `null` and an `IllegalLinkException` is thrown.
-1. `readData()` only executes additional code in the case if `$_POST` is empty, thus only for the initial request before the form has been submitted.
- The data properties of `PersonAddForm` are populated with the data of the edited person so that this data is shown in the form for the initial request.
-1. `save()` handles saving the changed data.
-
- !!! warning "Do not call `parent::save()` because that would cause `PersonAddForm::save()` to be executed and thus a new person would to be created! In order for the `save` event to be fired, call `AbstractForm::save()` instead!"
-
- The only differences compared to `PersonAddForm::save()` are that we pass the edited object to the `PersonAction` constructor, execute the `update` action instead of the `create` action and do not clear the input fields after saving the changes.
-1. In `assignVariables()`, we assign the edited `Person` object to the template, which is required to create the link in the form’s action property.
- Furthermore, we assign the template variable `$action` `edit` as value.
-
- !!! info "After calling `parent::assignVariables()`, the template variable `$action` actually has the value `add` so that here, we are overwriting this already assigned value."
+As we rely on form builder, the only thing necessary in this controller is to read and validate the edit object, i.e. the edited person, which is done in `readParameters()`.
## Frontend
```
As this is a package for WoltLab Suite Core 3, we need to require it using `<requiredpackage>`.
-We require the latest version (when writing this tutorial) `3.0.0 RC 4`.
-Additionally, we disallow installation of the package in the next major version `3.1` by excluding the `3.1.0 Alpha 1` version.
-This ensures that if changes from WoltLab Suite Core 3.0 to 3.1 require changing some parts of the package, it will not break the instance in which the package is installed.
+We require the latest version (when writing this tutorial) `5.4.0 Alpha 1`.
+Additionally, we disallow installation of the package in the next major version `6.0` by excluding the `6.0.0 Alpha 1` version.
The most important part are to installation instructions.
First, we install the ACP templates, files and templates, create the database table and import the language item.
# Part 2: Event Listeners and Template Listeners
+!!! warning "This part of the tutorial series is currently outdated while the tutorial series is updated."
+
In the [first part](part_1.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.
-# Tutorial Series Part 3: Person Page and Comments
+# Part 3: Person Page and Comments
+
+!!! warning "This part of the tutorial series is currently outdated while the tutorial series is updated."
In this part of our tutorial series, we will add a new front end page to our package that is dedicated to each person and shows their personal details.
To make good use of this new page and introduce a new API of WoltLab Suite, we will add the opportunity for users to comment on the person using WoltLab Suite’s reusable comment functionality.
<?xml version="1.0" encoding="UTF-8"?>
-<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/tornado/acpMenu.xsd">
+<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/5.4/acpMenu.xsd">
<import>
<acpmenuitem name="wcf.acp.menu.link.person">
<parent>wcf.acp.menu.link.content</parent>
</nav>
</header>
-{include file='formNotice'}
-
-<form method="post" action="{if $action == 'add'}{link controller='PersonAdd'}{/link}{else}{link controller='PersonEdit' object=$person}{/link}{/if}">
- <div class="section">
- <dl{if $errorField == 'firstName'} class="formError"{/if}>
- <dt><label for="firstName">{lang}wcf.person.firstName{/lang}</label></dt>
- <dd>
- <input type="text" id="firstName" name="firstName" value="{$firstName}" required autofocus maxlength="255" class="long">
- {if $errorField == 'firstName'}
- <small class="innerError">
- {if $errorType == 'empty'}
- {lang}wcf.global.form.error.empty{/lang}
- {else}
- {lang}wcf.acp.person.firstName.error.{$errorType}{/lang}
- {/if}
- </small>
- {/if}
- </dd>
- </dl>
-
- <dl{if $errorField == 'lastName'} class="formError"{/if}>
- <dt><label for="lastName">{lang}wcf.person.lastName{/lang}</label></dt>
- <dd>
- <input type="text" id="lastName" name="lastName" value="{$lastName}" required maxlength="255" class="long">
- {if $errorField == 'lastName'}
- <small class="innerError">
- {if $errorType == 'empty'}
- {lang}wcf.global.form.error.empty{/lang}
- {else}
- {lang}wcf.acp.person.lastName.error.{$errorType}{/lang}
- {/if}
- </small>
- {/if}
- </dd>
- </dl>
-
- {event name='dataFields'}
- </div>
-
- {event name='sections'}
-
- <div class="formSubmit">
- <input type="submit" value="{lang}wcf.global.button.submit{/lang}" accesskey="s">
- {csrfToken}
- </div>
-</form>
+{@$form->getHtml()}
{include file='footer'}
{/hascontent}
{if $objects|count}
- <div class="section tabularBox" id="personTableContainer">
- <table class="table">
+ <div class="section tabularBox">
+ <table class="table jsObjectActionContainer" data-object-action-class-name="wcf\data\person\PersonAction">
<thead>
<tr>
<th class="columnID columnPersonID{if $sortField == 'personID'} active {@$sortOrder}{/if}" colspan="2"><a href="{link controller='PersonList'}pageNo={@$pageNo}&sortField=personID&sortOrder={if $sortField == 'personID' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}wcf.global.objectID{/lang}</a></th>
<tbody class="jsReloadPageWhenEmpty">
{foreach from=$objects item=person}
- <tr class="jsPersonRow">
+ <tr class="jsObjectActionObject" data-object-id="{@$person->getObjectID()}">
<td class="columnIcon">
<a href="{link controller='PersonEdit' object=$person}{/link}" title="{lang}wcf.global.button.edit{/lang}" class="jsTooltip"><span class="icon icon16 fa-pencil"></span></a>
- <span class="icon icon16 fa-times jsDeleteButton jsTooltip pointer" title="{lang}wcf.global.button.delete{/lang}" data-object-id="{@$person->personID}" data-confirm-message-html="{lang __encode=true}wcf.acp.person.delete.confirmMessage{/lang}"></span>
+ {objectAction action="delete" objectTitle=$person->getTitle()}
{event name='rowButtons'}
</td>
<p class="info">{lang}wcf.global.noItems{/lang}</p>
{/if}
-<script data-relocate="true">
- $(function() {
- new WCF.Action.Delete('wcf\\data\\person\\PersonAction', '.jsPersonRow');
- });
-</script>
-
{include file='footer'}
--- /dev/null
+<?php
+
+use wcf\system\database\table\column\NotNullVarchar255DatabaseTableColumn;
+use wcf\system\database\table\column\ObjectIdDatabaseTableColumn;
+use wcf\system\database\table\DatabaseTable;
+
+return [
+ DatabaseTable::create('wcf1_person')
+ ->columns([
+ ObjectIdDatabaseTableColumn::create('personID'),
+ NotNullVarchar255DatabaseTableColumn::create('firstName'),
+ NotNullVarchar255DatabaseTableColumn::create('lastName'),
+ ]),
+];
<?php
+
namespace wcf\acp\form;
+
use wcf\data\person\PersonAction;
-use wcf\form\AbstractForm;
-use wcf\system\exception\UserInputException;
-use wcf\system\request\LinkHandler;
-use wcf\system\WCF;
-use wcf\util\StringUtil;
+use wcf\form\AbstractFormBuilderForm;
+use wcf\system\form\builder\container\FormContainer;
+use wcf\system\form\builder\field\TextFormField;
/**
* Shows the form to create a new person.
- *
- * @author Matthias Schmidt
- * @copyright 2001-2019 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package WoltLabSuite\Core\Acp\Form
+ *
+ * @author Matthias Schmidt
+ * @copyright 2001-2021 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package WoltLabSuite\Core\Acp\Form
*/
-class PersonAddForm extends AbstractForm {
- /**
- * @inheritDoc
- */
- public $activeMenuItem = 'wcf.acp.menu.link.person.add';
-
- /**
- * first name of the person
- * @var string
- */
- public $firstName = '';
-
- /**
- * last name of the person
- * @var string
- */
- public $lastName = '';
-
- /**
- * @inheritDoc
- */
- public $neededPermissions = ['admin.content.canManagePeople'];
-
- /**
- * @inheritDoc
- */
- public function assignVariables() {
- parent::assignVariables();
-
- WCF::getTPL()->assign([
- 'action' => 'add',
- 'firstName' => $this->firstName,
- 'lastName' => $this->lastName
- ]);
- }
-
- /**
- * @inheritDoc
- */
- public function readFormParameters() {
- parent::readFormParameters();
-
- if (isset($_POST['firstName'])) $this->firstName = StringUtil::trim($_POST['firstName']);
- if (isset($_POST['lastName'])) $this->lastName = StringUtil::trim($_POST['lastName']);
- }
-
- /**
- * @inheritDoc
- */
- public function save() {
- parent::save();
-
- $this->objectAction = new PersonAction([], 'create', [
- 'data' => array_merge($this->additionalFields, [
- 'firstName' => $this->firstName,
- 'lastName' => $this->lastName
- ])
- ]);
- $returnValues = $this->objectAction->executeAction();
-
- $this->saved();
-
- // reset values
- $this->firstName = '';
- $this->lastName = '';
-
- // show success message
- WCF::getTPL()->assign([
- 'success' => true,
- 'objectEditLink' => LinkHandler::getInstance()->getControllerLink(PersonEditForm::class, ['id' => $returnValues['returnValues']->personID]),
- ]);
- }
-
- /**
- * @inheritDoc
- */
- public function validate() {
- parent::validate();
-
- // validate first name
- if (empty($this->firstName)) {
- throw new UserInputException('firstName');
- }
- if (mb_strlen($this->firstName) > 255) {
- throw new UserInputException('firstName', 'tooLong');
- }
-
- // validate last name
- if (empty($this->lastName)) {
- throw new UserInputException('lastName');
- }
- if (mb_strlen($this->lastName) > 255) {
- throw new UserInputException('lastName', 'tooLong');
- }
- }
+class PersonAddForm extends AbstractFormBuilderForm
+{
+ /**
+ * @inheritDoc
+ */
+ public $activeMenuItem = 'wcf.acp.menu.link.person.add';
+
+ /**
+ * @inheritDoc
+ */
+ public $formAction = 'create';
+
+ /**
+ * @inheritDoc
+ */
+ public $neededPermissions = ['admin.content.canManagePeople'];
+
+ /**
+ * @inheritDoc
+ */
+ public $objectActionClass = PersonAction::class;
+
+ /**
+ * @inheritDoc
+ */
+ public $objectEditLinkController = PersonEditForm::class;
+
+ /**
+ * @inheritDoc
+ */
+ public function createForm()
+ {
+ parent::createForm();
+
+ $this->form->appendChild(
+ FormContainer::create('data')
+ ->label('wcf.global.form.data')
+ ->appendChildren([
+ TextFormField::create('firstName')
+ ->label('wcf.person.firstName')
+ ->required()
+ ->autoFocus()
+ ->maximumLength(255),
+
+ TextFormField::create('lastName')
+ ->label('wcf.person.lastName')
+ ->required()
+ ->maximumLength(255),
+ ])
+ );
+ }
}
<?php
+
namespace wcf\acp\form;
+
use wcf\data\person\Person;
-use wcf\data\person\PersonAction;
-use wcf\form\AbstractForm;
use wcf\system\exception\IllegalLinkException;
-use wcf\system\WCF;
/**
* Shows the form to edit an existing person.
- *
- * @author Matthias Schmidt
- * @copyright 2001-2019 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package WoltLabSuite\Core\Acp\Form
+ *
+ * @author Matthias Schmidt
+ * @copyright 2001-2021 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package WoltLabSuite\Core\Acp\Form
*/
-class PersonEditForm extends PersonAddForm {
- /**
- * @inheritDoc
- */
- public $activeMenuItem = 'wcf.acp.menu.link.person';
-
- /**
- * edited person object
- * @var Person
- */
- public $person = null;
-
- /**
- * id of the edited person
- * @var integer
- */
- public $personID = 0;
-
- /**
- * @inheritDoc
- */
- public function assignVariables() {
- parent::assignVariables();
-
- WCF::getTPL()->assign([
- 'action' => 'edit',
- 'person' => $this->person
- ]);
- }
-
- /**
- * @inheritDoc
- */
- public function readData() {
- parent::readData();
-
- if (empty($_POST)) {
- $this->firstName = $this->person->firstName;
- $this->lastName = $this->person->lastName;
- }
- }
-
- /**
- * @inheritDoc
- */
- public function readParameters() {
- parent::readParameters();
-
- if (isset($_REQUEST['id'])) $this->personID = intval($_REQUEST['id']);
- $this->person = new Person($this->personID);
- if (!$this->person->personID) {
- throw new IllegalLinkException();
- }
- }
-
- /**
- * @inheritDoc
- */
- public function save() {
- AbstractForm::save();
-
- $this->objectAction = new PersonAction([$this->person], 'update', [
- 'data' => array_merge($this->additionalFields, [
- 'firstName' => $this->firstName,
- 'lastName' => $this->lastName
- ])
- ]);
- $this->objectAction->executeAction();
-
- $this->saved();
-
- // show success message
- WCF::getTPL()->assign('success', true);
- }
+class PersonEditForm extends PersonAddForm
+{
+ /**
+ * @inheritDoc
+ */
+ public $activeMenuItem = 'wcf.acp.menu.link.person';
+
+ /**
+ * @inheritDoc
+ */
+ public $formAction = 'update';
+
+ /**
+ * @inheritDoc
+ */
+ public function readParameters()
+ {
+ parent::readParameters();
+
+ if (isset($_REQUEST['id'])) {
+ $this->formObject = new Person($_REQUEST['id']);
+
+ if (!$this->formObject->getObjectID()) {
+ throw new IllegalLinkException();
+ }
+ }
+ }
}
<?php
+
namespace wcf\acp\page;
+
use wcf\data\person\PersonList;
use wcf\page\SortablePage;
/**
* Shows the list of people.
- *
- * @author Matthias Schmidt
- * @copyright 2001-2019 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package WoltLabSuite\Core\Acp\Page
+ *
+ * @author Matthias Schmidt
+ * @copyright 2001-2021 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package WoltLabSuite\Core\Acp\Page
*/
-class PersonListPage extends SortablePage {
- /**
- * @inheritDoc
- */
- public $activeMenuItem = 'wcf.acp.menu.link.person.list';
-
- /**
- * @inheritDoc
- */
- public $neededPermissions = ['admin.content.canManagePeople'];
-
- /**
- * @inheritDoc
- */
- public $objectListClassName = PersonList::class;
-
- /**
- * @inheritDoc
- */
- public $validSortFields = ['personID', 'firstName', 'lastName'];
+class PersonListPage extends SortablePage
+{
+ /**
+ * @inheritDoc
+ */
+ public $activeMenuItem = 'wcf.acp.menu.link.person.list';
+
+ /**
+ * @inheritDoc
+ */
+ public $neededPermissions = ['admin.content.canManagePeople'];
+
+ /**
+ * @inheritDoc
+ */
+ public $objectListClassName = PersonList::class;
+
+ /**
+ * @inheritDoc
+ */
+ public $validSortFields = ['personID', 'firstName', 'lastName'];
}
<?php
+
namespace wcf\data\person;
+
use wcf\data\DatabaseObject;
use wcf\system\request\IRouteController;
/**
* Represents a person.
- *
- * @author Matthias Schmidt
- * @copyright 2001-2019 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package WoltLabSuite\Core\Data\Person
- *
- * @property-read integer $personID unique id of the person
- * @property-read string $firstName first name of the person
- * @property-read string $lastName last name of the person
+ *
+ * @author Matthias Schmidt
+ * @copyright 2001-2021 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package WoltLabSuite\Core\Data\Person
+ *
+ * @property-read integer $personID unique id of the person
+ * @property-read string $firstName first name of the person
+ * @property-read string $lastName last name of the person
*/
-class Person extends DatabaseObject implements IRouteController {
- /**
- * Returns the first and last name of the person if a person object is treated as a string.
- *
- * @return string
- */
- public function __toString() {
- return $this->getTitle();
- }
-
- /**
- * @inheritDoc
- */
- public function getTitle() {
- return $this->firstName . ' ' . $this->lastName;
- }
+class Person extends DatabaseObject implements IRouteController
+{
+ /**
+ * Returns the first and last name of the person if a person object is treated as a string.
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->getTitle();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getTitle()
+ {
+ return $this->firstName . ' ' . $this->lastName;
+ }
}
<?php
+
namespace wcf\data\person;
+
use wcf\data\AbstractDatabaseObjectAction;
/**
* Executes person-related actions.
- *
- * @author Matthias Schmidt
- * @copyright 2001-2019 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package WoltLabSuite\Core\Data\Person
*
- * @method Person create()
- * @method PersonEditor[] getObjects()
- * @method PersonEditor getSingleObject()
+ * @author Matthias Schmidt
+ * @copyright 2001-2021 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package WoltLabSuite\Core\Data\Person
+ *
+ * @method Person create()
+ * @method PersonEditor[] getObjects()
+ * @method PersonEditor getSingleObject()
*/
-class PersonAction extends AbstractDatabaseObjectAction {
- /**
- * @inheritDoc
- */
- protected $permissionsDelete = ['admin.content.canManagePeople'];
-
- /**
- * @inheritDoc
- */
- protected $requireACP = ['delete'];
+class PersonAction extends AbstractDatabaseObjectAction
+{
+ /**
+ * @inheritDoc
+ */
+ protected $permissionsDelete = ['admin.content.canManagePeople'];
+
+ /**
+ * @inheritDoc
+ */
+ protected $requireACP = ['delete'];
}
<?php
+
namespace wcf\data\person;
+
use wcf\data\DatabaseObjectEditor;
/**
* Provides functions to edit people.
- *
- * @author Matthias Schmidt
- * @copyright 2001-2019 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package WoltLabSuite\Core\Data\Person
- *
- * @method static Person create(array $parameters = [])
- * @method Person getDecoratedObject()
- * @mixin Person
+ *
+ * @author Matthias Schmidt
+ * @copyright 2001-2021 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package WoltLabSuite\Core\Data\Person
+ *
+ * @method static Person create(array $parameters = [])
+ * @method Person getDecoratedObject()
+ * @mixin Person
*/
-class PersonEditor extends DatabaseObjectEditor {
- /**
- * @inheritDoc
- */
- protected static $baseClass = Person::class;
+class PersonEditor extends DatabaseObjectEditor
+{
+ /**
+ * @inheritDoc
+ */
+ protected static $baseClass = Person::class;
}
<?php
+
namespace wcf\data\person;
+
use wcf\data\DatabaseObjectList;
/**
* Represents a list of people.
- *
- * @author Matthias Schmidt
- * @copyright 2001-2019 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package WoltLabSuite\Core\Data\Person
- *
- * @method Person current()
- * @method Person[] getObjects()
- * @method Person|null search($objectID)
- * @property Person[] $objects
+ *
+ * @author Matthias Schmidt
+ * @copyright 2001-2021 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package WoltLabSuite\Core\Data\Person
+ *
+ * @method Person current()
+ * @method Person[] getObjects()
+ * @method Person|null search($objectID)
+ * @property Person[] $objects
*/
-class PersonList extends DatabaseObjectList {}
+class PersonList extends DatabaseObjectList
+{
+}
<?php
+
namespace wcf\page;
+
use wcf\data\person\PersonList;
/**
* Shows the list of people.
- *
- * @author Matthias Schmidt
- * @copyright 2001-2019 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package WoltLabSuite\Core\Page
+ *
+ * @author Matthias Schmidt
+ * @copyright 2001-2021 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package WoltLabSuite\Core\Page
*/
-class PersonListPage extends SortablePage {
- /**
- * @inheritDoc
- */
- public $defaultSortField = 'lastName';
-
- /**
- * @inheritDoc
- */
- public $objectListClassName = PersonList::class;
-
- /**
- * @inheritDoc
- */
- public $validSortFields = ['personID', 'firstName', 'lastName'];
+class PersonListPage extends SortablePage
+{
+ /**
+ * @inheritDoc
+ */
+ public $defaultSortField = 'lastName';
+
+ /**
+ * @inheritDoc
+ */
+ public $objectListClassName = PersonList::class;
+
+ /**
+ * @inheritDoc
+ */
+ public $validSortFields = ['personID', 'firstName', 'lastName'];
}
+++ /dev/null
-DROP TABLE IF EXISTS wcf1_person;
-CREATE TABLE wcf1_person (
- personID INT(10) NOT NULL AUTO_INCREMENT PRIMARY KEY,
- firstName VARCHAR(255) NOT NULL,
- lastName VARCHAR(255) NOT NULL
-);
<?xml version="1.0" encoding="UTF-8"?>
-<language xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/tornado/language.xsd" languagecode="de">
+<language xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/5.4/language.xsd" languagecode="de">
<category name="wcf.acp.group">
<item name="wcf.acp.group.option.admin.content.canManagePeople"><![CDATA[Kann Personen verwalten]]></item>
</category>
<category name="wcf.acp.person">
<item name="wcf.acp.person.add"><![CDATA[Person hinzufügen]]></item>
- <item name="wcf.acp.person.delete.confirmMessage"><![CDATA[{if LANGUAGE_USE_INFORMAL_VARIANT}Willst du{else}Wollen Sie{/if} die Person <span class="confirmationObject">{$person}</span> wirklich löschen?]]></item>
<item name="wcf.acp.person.edit"><![CDATA[Person bearbeiten]]></item>
- <item name="wcf.acp.person.firstName.error.tooLong"><![CDATA[Der Vorname darf nicht länger als 255 Zeichen sein.]]></item>
- <item name="wcf.acp.person.lastName.error.tooLong"><![CDATA[Der Nachname darf nicht länger als 255 Zeichen sein.]]></item>
<item name="wcf.acp.person.list"><![CDATA[Personen]]></item>
</category>
<?xml version="1.0" encoding="UTF-8"?>
-<language xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/tornado/language.xsd" languagecode="en">
+<language xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/5.4/language.xsd" languagecode="en">
<category name="wcf.acp.group">
<item name="wcf.acp.group.option.admin.content.canManagePeople"><![CDATA[Can manage people]]></item>
</category>
<category name="wcf.acp.person">
<item name="wcf.acp.person.add"><![CDATA[Add Person]]></item>
- <item name="wcf.acp.person.delete.confirmMessage"><![CDATA[Do you really want to delete the person <span class="confirmationObject">{$person}</span>?]]></item>
<item name="wcf.acp.person.edit"><![CDATA[Edit Person]]></item>
- <item name="wcf.acp.person.firstName.error.tooLong"><![CDATA[The first name must not be longer than 255 characters.]]></item>
- <item name="wcf.acp.person.lastName.error.tooLong"><![CDATA[The last name must not be longer than 255 characters.]]></item>
<item name="wcf.acp.person.list"><![CDATA[People]]></item>
</category>
<?xml version="1.0" encoding="UTF-8"?>
-<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/tornado/menuItem.xsd">
+<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/5.4/menuItem.xsd">
<import>
<item identifier="com.woltlab.wcf.people.PersonList">
<menu>com.woltlab.wcf.MainMenu</menu>
<?xml version="1.0" encoding="UTF-8"?>
-<package name="com.woltlab.wcf.people" xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/tornado/package.xsd">
+<package name="com.woltlab.wcf.people" xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/5.4/package.xsd">
<packageinformation>
<packagename>WoltLab Suite Core Tutorial: People</packagename>
<packagedescription>Adds a simple management system for people as part of a tutorial to create packages.</packagedescription>
- <version>3.1.0</version>
- <date>2018-03-30</date>
+ <version>5.4.0</version>
+ <date>2021-04-16</date>
</packageinformation>
<authorinformation>
</authorinformation>
<requiredpackages>
- <requiredpackage minversion="3.1.0">com.woltlab.wcf</requiredpackage>
+ <requiredpackage minversion="5.4.0 Alpha 1">com.woltlab.wcf</requiredpackage>
</requiredpackages>
<excludedpackages>
- <excludedpackage version="3.2.0 Alpha 1">com.woltlab.wcf</excludedpackage>
+ <excludedpackage version="6.0.0 Alpha 1">com.woltlab.wcf</excludedpackage>
</excludedpackages>
-
- <compatibility>
- <api version="2018" />
- </compatibility>
<instructions type="install">
<instruction type="acpTemplate" />
<instruction type="file" />
- <instruction type="sql" />
+ <instruction type="database">acp/database/install_com.woltlab.wcf.people.php</instruction>
<instruction type="template" />
<instruction type="language" />
<?xml version="1.0" encoding="UTF-8"?>
-<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/tornado/page.xsd">
+<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/5.4/page.xsd">
<import>
<page identifier="com.woltlab.wcf.people.PersonList">
<pageType>system</pageType>
<?xml version="1.0" encoding="UTF-8"?>
-<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/tornado/userGroupOption.xsd">
+<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/5.4/userGroupOption.xsd">
<import>
<options>
<option name="admin.content.canManagePeople">