Update `codebox` macro
[GitHub/WoltLab/woltlab.github.io.git] / docs / tutorial / series / part_3.md
CommitLineData
376b2543 1# Part 3: Person Page and Comments
88aa7dc5
MS
2
3In 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.
4To 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.
5
6
7## Package Functionality
8
7e276cf9 9In addition to the existing functions from [part 1](part_1.md), the package will provide the following possibilities/functions after this part of the tutorial:
88aa7dc5
MS
10
11- Details page for each person linked in the front end person list
12- Comment on people on their respective page (can be disabled per person)
13- User online location for person details page with name and link to person details page
14- Create menu items linking to specific person details pages
15
16
17## Used Components
18
7e276cf9 19In addition to the components used in [part 1](part_1.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.
88aa7dc5
MS
20
21
22## Package Structure
23
7e276cf9 24The complete package will have the following file structure (including the files from [part 1](part_1.md)):
88aa7dc5
MS
25
26```
27├── acpMenu.xml
28├── acptemplates
60ed94fa
MS
29│ ├── personAdd.tpl
30│ └── personList.tpl
88aa7dc5 31├── files
21f91348
MS
32│ ├── acp
33│ │ └── database
34│ │ └── install_com.woltlab.wcf.people.php
60ed94fa
MS
35│ └── lib
36│ ├── acp
37│ │ ├── form
38│ │ │ ├── PersonAddForm.class.php
39│ │ │ └── PersonEditForm.class.php
40│ │ └── page
41│ │ └── PersonListPage.class.php
42│ ├── data
43│ │ └── person
44│ │ ├── Person.class.php
45│ │ ├── PersonAction.class.php
46│ │ ├── PersonEditor.class.php
47│ │ └── PersonList.class.php
48│ ├── page
49│ │ ├── PersonListPage.class.php
50│ │ └── PersonPage.class.php
51│ └── system
52│ ├── cache
53│ │ └── runtime
54│ │ └── PersonRuntimeCache.class.php
55│ ├── comment
56│ │ └── manager
57│ │ └── PersonCommentManager.class.php
58│ └── page
59│ └── handler
60│ └── PersonPageHandler.class.php
88aa7dc5 61├── language
60ed94fa
MS
62│ ├── de.xml
63│ └── en.xml
88aa7dc5
MS
64├── menuItem.xml
65├── objectType.xml
66├── package.xml
67├── page.xml
68├── templates
60ed94fa
MS
69│ ├── person.tpl
70│ └── personList.tpl
88aa7dc5
MS
71└── userGroupOption.xml
72```
73
086a42fa 74!!! warning "We will not mention every code change between the first part and this part, as we only want to focus on the important, new parts of the code. For example, there is a new `Person::getLink()` method and new language items have been added. For all changes, please refer to the [source code on GitHub]({jinja{ config.repo_url }}tree/{jinja{ config.edit_uri.split("/")[1] }}/snippets/tutorial/tutorial-series/part-3)."
88aa7dc5
MS
75
76
77## Runtime Cache
78
21609ed2 79To 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:
88aa7dc5 80
9a3f5fa3 81{jinja{ codebox(
f778fce2
MS
82 title="files/lib/system/cache/runtime/PersonRuntimeCache.class.php",
83 language="php",
84 filepath="tutorial/tutorial-series/part-3/files/lib/system/cache/runtime/PersonRuntimeCache.class.php"
9a3f5fa3 85) }}
88aa7dc5
MS
86
87
88## Comments
89
90To allow users to comment on people, we need to tell the system that people support comments.
91This is done by registering a `com.woltlab.wcf.comment.commentableContent` object type whose processor implements [ICommentManager](https://github.com/WoltLab/WCF/blob/master/wcfsetup/install/files/lib/system/comment/manager/ICommentManager.class.php):
92
9a3f5fa3 93{jinja{ codebox(
f778fce2
MS
94 title="objectType.xml",
95 language="xml",
96 filepath="tutorial/tutorial-series/part-3/objectType.xml"
9a3f5fa3 97) }}
88aa7dc5
MS
98
99The `PersonCommentManager` class extended `ICommentManager`’s default implementation [AbstractCommentManager](https://github.com/WoltLab/WCF/blob/master/wcfsetup/install/files/lib/system/comment/manager/AbstractCommentManager.class.php):
100
9a3f5fa3 101{jinja{ codebox(
f778fce2
MS
102 title="files/lib/system/comment/manager/PersonCommentManager.class.php",
103 language="php",
104 filepath="tutorial/tutorial-series/part-3/files/lib/system/comment/manager/PersonCommentManager.class.php"
9a3f5fa3 105) }}
88aa7dc5
MS
106
107- First, the system is told the names of the permissions via the `$permission*` properties.
21609ed2 108 More information about comment permissions can be found [here](../../php/api/comments.md#user-group-options).
88aa7dc5
MS
109- The `getLink()` method returns the link to the person with the passed comment id.
110 As in `isAccessible()`, `PersonRuntimeCache` is used to potentially save database queries.
111- The `isAccessible()` method checks if the active user can access the relevant person.
112 As we do not have any special restrictions for accessing people, we only need to check if the person exists.
113- The `getTitle()` method returns the title used for comments and responses, which is just a generic language item in this case.
114- The `updateCounter()` updates the comments’ counter of the person.
115 We have added a new `comments` database table column to the `wcf1_person` database table in order to keep track on the number of comments.
116
abb300ed 117Additionally, we have added a new `enableComments` database table column to the `wcf1_person` database table whose value can be set when creating or editing a person in the ACP.
88aa7dc5
MS
118With this option, comments on individual people can be disabled.
119
9003992d 120!!! info "Liking comments is already built-in and only requires some extra code in the `PersonPage` class for showing the likes of pre-loaded comments."
88aa7dc5
MS
121
122
123## Person Page
124
125### `PersonPage`
126
9a3f5fa3 127{jinja{ codebox(
f778fce2
MS
128 title="files/lib/page/PersonPage.class.php",
129 language="php",
130 filepath="tutorial/tutorial-series/part-3/files/lib/page/PersonPage.class.php"
9a3f5fa3 131) }}
88aa7dc5
MS
132
133The `PersonPage` class is similar to the `PersonEditForm` in the ACP in that it reads the id of the requested person from the request data and validates the id in `readParameters()`.
134The rest of the code only handles fetching the list of comments on the requested person.
135In `readData()`, this list is fetched using `CommentHandler::getCommentList()` if comments are enabled for the person.
136The `assignVariables()` method assigns some additional template variables like `$commentCanAdd`, which is `1` if the active person can add comments and is `0` otherwise, `$lastCommentTime`, which contains the UNIX timestamp of the last comment, and `$likeData`, which contains data related to the likes for the disabled comments.
137
138### `person.tpl`
139
9a3f5fa3 140{jinja{ codebox(
f778fce2
MS
141 title="templates/person.tpl",
142 language="tpl",
143 filepath="tutorial/tutorial-series/part-3/templates/person.tpl"
9a3f5fa3 144) }}
88aa7dc5
MS
145
146For now, the `person` template is still very empty and only shows the comments in the content area.
eb0aecac 147The template code shown for comments is very generic and used in this form in many locations as it only sets the header of the comment list and the container `ul#personCommentList` element for the comments shown by `commentList` template.
88aa7dc5 148The `ul#personCommentList` elements has five additional `data-` attributes required by the JavaScript API for comments for loading more comments or creating new ones.
eb0aecac
MS
149The `commentListAddComment` template adds the WYSIWYG support.
150The attribute `wysiwygSelector` should be the id of the comment list `personCommentList` with an additional `AddComment` suffix.
88aa7dc5
MS
151
152### `page.xml`
153
9a3f5fa3 154{jinja{ codebox(
f778fce2
MS
155 title="page.xml",
156 language="xml",
157 filepath="tutorial/tutorial-series/part-3/page.xml"
9a3f5fa3 158) }}
88aa7dc5
MS
159
160The `page.xml` file has been extended for the new person page with identifier `com.woltlab.wcf.people.Person`.
161Compared to the pre-existing `com.woltlab.wcf.people.PersonList` page, there are four differences:
162
1631. It has a `<handler>` element with a class name as value.
164 This aspect will be discussed in more detail in the next section.
1651. There are no `<content>` elements because, both, the title and the content of the page are dynamically generated in the template.
1661. The `<requireObjectID>` tells the system that this page requires an object id to properly work, in this case a valid person id.
1671. This page has a `<parent>` page, the person list page.
168 In general, the details page for any type of object that is listed on a different page has the list page as its parent.
169
170### `PersonPageHandler`
171
9a3f5fa3 172{jinja{ codebox(
f778fce2
MS
173 title="files/lib/system/page/handler/PersonPageHandler.class.php",
174 language="php",
175 filepath="tutorial/tutorial-series/part-3/files/lib/system/page/handler/PersonPageHandler.class.php"
9a3f5fa3 176) }}
88aa7dc5
MS
177
178Like any page handler, the `PersonPageHandler` class has to implement the [IMenuPageHandler](https://github.com/WoltLab/WCF/blob/master/wcfsetup/install/files/lib/system/page/handler/IMenuPageHandler.class.php) interface, which should be done by extending the [AbstractMenuPageHandler](https://github.com/WoltLab/WCF/blob/master/wcfsetup/install/files/lib/system/page/handler/AbstractMenuPageHandler.class.php) class.
179As we want administrators to link to specific people in menus, for example, we have to also implement the [ILookupPageHandler](https://github.com/WoltLab/WCF/blob/master/wcfsetup/install/files/lib/system/page/handler/ILookupPageHandler.class.php) interface by extending the [AbstractLookupPageHandler](https://github.com/WoltLab/WCF/blob/master/wcfsetup/install/files/lib/system/page/handler/AbstractLookupPageHandler.class.php) class.
180
181For the `ILookupPageHandler` interface, we need to implement three methods:
182
1831. `getLink($objectID)` returns the link to the person page with the given id.
184 In this case, we simply delegate this method call to the `Person` object returned by `PersonRuntimeCache::getObject()`.
1851. `isValid($objectID)` returns `true` if the person with the given id exists, otherwise `false`.
186 Here, we use `PersonRuntimeCache::getObject()` again and check if the return value is `null`, which is the case for non-existing people.
1871. `lookup($searchString)` is used when setting up an internal link and when searching for the linked person.
188 This method simply searches the first and last name of the people and returns an array with the person data.
189 While the `link`, the `objectID`, and the `title` element are self-explanatory, the `image` element can either contain an HTML `<img>` tag, which is displayed next to the search result (WoltLab Suite uses an image tag for users showing their avatar, for example), or a FontAwesome icon class (starting with `fa-`).
190
191Additionally, the class also implements [IOnlineLocationPageHandler](https://github.com/WoltLab/WCF/blob/master/wcfsetup/install/files/lib/system/page/handler/IOnlineLocationPageHandler.class.php) which is used to determine the online location of users.
192To ensure upwards-compatibility if the `IOnlineLocationPageHandler` interface changes, the [TOnlineLocationPageHandler](https://github.com/WoltLab/WCF/blob/master/wcfsetup/install/files/lib/system/page/handler/TOnlineLocationPageHandler.class.php) trait is used.
193The `IOnlineLocationPageHandler` interface requires two methods to be implemented:
194
1951. `getOnlineLocation(Page $page, UserOnline $user)` returns the textual description of the online location.
196 The language item for the user online locations should use the pattern `wcf.page.onlineLocation.{page identifier}`.
1971. `prepareOnlineLocation(Page $page, UserOnline $user)` is called for each user online before the `getOnlineLocation()` calls.
198 In this case, calling `prepareOnlineLocation()` first enables us to add all relevant person ids to the person runtime cache so that for all `getOnlineLocation()` calls combined, only one database query is necessary to fetch all person objects.
199
200---
201
202This concludes the third part of our tutorial series after which each person has a dedicated page on which people can comment on the person.
203
086a42fa 204The complete source code of this part can be found on [GitHub]({jinja{ config.repo_url }}tree/{jinja{ config.edit_uri.split("/")[1] }}/snippets/tutorial/tutorial-series/part-3).
88aa7dc5 205