3 <html lang=
"en" class=
"no-js">
7 <meta name=
"viewport" content=
"width=device-width,initial-scale=1">
12 <link rel=
"canonical" href=
"https://docs.woltlab.com/5.4/tutorial/series/part_1/">
14 <link rel=
"icon" href=
"../../../assets/default.favicon.ico">
15 <meta name=
"generator" content=
"mkdocs-1.1.2, mkdocs-material-7.1.2">
19 <title>Part
1 - WoltLab Suite Documentation
</title>
23 <link rel=
"stylesheet" href=
"../../../assets/stylesheets/main.6f955dcd.min.css">
26 <link rel=
"stylesheet" href=
"../../../assets/stylesheets/palette.ef6f36e2.min.css">
30 <meta name=
"theme-color" content=
"#009485">
40 <link rel=
"stylesheet" href=
"../../../stylesheets/extra.css">
54 <body dir=
"ltr" data-md-color-scheme=
"" data-md-color-primary=
"teal" data-md-color-accent=
"">
57 <script>function __prefix(e){return new URL(
"../../..",location).pathname+
"."+e}function __get(e,t=localStorage){return JSON.parse(t.getItem(__prefix(e)))}
</script>
59 <input class=
"md-toggle" data-md-toggle=
"drawer" type=
"checkbox" id=
"__drawer" autocomplete=
"off">
60 <input class=
"md-toggle" data-md-toggle=
"search" type=
"checkbox" id=
"__search" autocomplete=
"off">
61 <label class=
"md-overlay" for=
"__drawer"></label>
62 <div data-md-component=
"skip">
65 <a href=
"#tutorial-series-part-1-base-structure" class=
"md-skip">
70 <div data-md-component=
"announce">
72 <aside class=
"md-announce">
73 <div class=
"md-announce__inner md-grid md-typeset">
75 <a href=
"https://www.woltlab.com">Back to
<strong>woltlab.com
</strong></a>
82 <header class=
"md-header" data-md-component=
"header">
83 <nav class=
"md-header__inner md-grid" aria-label=
"Header">
84 <a href=
"../../.." title=
"WoltLab Suite Documentation" class=
"md-header__button md-logo" aria-label=
"WoltLab Suite Documentation" data-md-component=
"logo">
86 <img src=
"../../../assets/logo.png" alt=
"logo">
89 <label class=
"md-header__button md-icon" for=
"__drawer">
90 <svg xmlns=
"http://www.w3.org/2000/svg" viewBox=
"0 0 24 24"><path d=
"M3 6h18v2H3V6m0 5h18v2H3v-2m0 5h18v2H3v-2z"/></svg>
92 <div class=
"md-header__title" data-md-component=
"header-title">
93 <div class=
"md-header__ellipsis">
94 <div class=
"md-header__topic">
95 <span class=
"md-ellipsis">
96 WoltLab Suite Documentation
99 <div class=
"md-header__topic" data-md-component=
"header-topic">
100 <span class=
"md-ellipsis">
111 <label class=
"md-header__button md-icon" for=
"__search">
112 <svg xmlns=
"http://www.w3.org/2000/svg" viewBox=
"0 0 24 24"><path d=
"M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.516 6.516 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5z"/></svg>
115 <div class=
"md-search" data-md-component=
"search" role=
"dialog">
116 <label class=
"md-search__overlay" for=
"__search"></label>
117 <div class=
"md-search__inner" role=
"search">
118 <form class=
"md-search__form" name=
"search">
119 <input type=
"text" class=
"md-search__input" name=
"query" aria-label=
"Search" placeholder=
"Search" autocapitalize=
"off" autocorrect=
"off" autocomplete=
"off" spellcheck=
"false" data-md-component=
"search-query" data-md-state=
"active" required
>
120 <label class=
"md-search__icon md-icon" for=
"__search">
121 <svg xmlns=
"http://www.w3.org/2000/svg" viewBox=
"0 0 24 24"><path d=
"M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.516 6.516 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5z"/></svg>
122 <svg xmlns=
"http://www.w3.org/2000/svg" viewBox=
"0 0 24 24"><path d=
"M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12z"/></svg>
124 <button type=
"reset" class=
"md-search__icon md-icon" aria-label=
"Clear" tabindex=
"-1">
125 <svg xmlns=
"http://www.w3.org/2000/svg" viewBox=
"0 0 24 24"><path d=
"M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z"/></svg>
128 <div class=
"md-search__output">
129 <div class=
"md-search__scrollwrap" data-md-scrollfix
>
130 <div class=
"md-search-result" data-md-component=
"search-result">
131 <div class=
"md-search-result__meta">
134 <ol class=
"md-search-result__list"></ol>
142 <div class=
"md-header__source">
144 <a href=
"https://github.com/WoltLab/docs.woltlab.com/" title=
"Go to repository" class=
"md-source" data-md-component=
"source">
145 <div class=
"md-source__icon md-icon">
147 <svg xmlns=
"http://www.w3.org/2000/svg" viewBox=
"0 0 448 512"><path d=
"M439.55 236.05 244 40.45a28.87 28.87 0 0 0-40.81 0l-40.66 40.63 51.52 51.52c27.06-9.14 52.68 16.77 43.39 43.68l49.66 49.66c34.23-11.8 61.18 31 35.47 56.69-26.49 26.49-70.21-2.87-56-37.34L240.22 199v121.85c25.3 12.54 22.26 41.85 9.08 55a34.34 34.34 0 0 1-48.55 0c-17.57-17.6-11.07-46.91 11.25-56v-123c-20.8-8.51-24.6-30.74-18.64-45L142.57 101 8.45 235.14a28.86 28.86 0 0 0 0 40.81l195.61 195.6a28.86 28.86 0 0 0 40.8 0l194.69-194.69a28.86 28.86 0 0 0 0-40.81z"/></svg>
149 <div class=
"md-source__repository">
158 <div class=
"md-container" data-md-component=
"container">
163 <main class=
"md-main" data-md-component=
"main">
164 <div class=
"md-main__inner md-grid">
168 <div class=
"md-sidebar md-sidebar--primary" data-md-component=
"sidebar" data-md-type=
"navigation" >
169 <div class=
"md-sidebar__scrollwrap">
170 <div class=
"md-sidebar__inner">
174 <nav class=
"md-nav md-nav--primary" aria-label=
"Navigation" data-md-level=
"0">
175 <label class=
"md-nav__title" for=
"__drawer">
176 <a href=
"../../.." title=
"WoltLab Suite Documentation" class=
"md-nav__button md-logo" aria-label=
"WoltLab Suite Documentation" data-md-component=
"logo">
178 <img src=
"../../../assets/logo.png" alt=
"logo">
181 WoltLab Suite Documentation
184 <div class=
"md-nav__source">
186 <a href=
"https://github.com/WoltLab/docs.woltlab.com/" title=
"Go to repository" class=
"md-source" data-md-component=
"source">
187 <div class=
"md-source__icon md-icon">
189 <svg xmlns=
"http://www.w3.org/2000/svg" viewBox=
"0 0 448 512"><path d=
"M439.55 236.05 244 40.45a28.87 28.87 0 0 0-40.81 0l-40.66 40.63 51.52 51.52c27.06-9.14 52.68 16.77 43.39 43.68l49.66 49.66c34.23-11.8 61.18 31 35.47 56.69-26.49 26.49-70.21-2.87-56-37.34L240.22 199v121.85c25.3 12.54 22.26 41.85 9.08 55a34.34 34.34 0 0 1-48.55 0c-17.57-17.6-11.07-46.91 11.25-56v-123c-20.8-8.51-24.6-30.74-18.64-45L142.57 101 8.45 235.14a28.86 28.86 0 0 0 0 40.81l195.61 195.6a28.86 28.86 0 0 0 40.8 0l194.69-194.69a28.86 28.86 0 0 0 0-40.81z"/></svg>
191 <div class=
"md-source__repository">
197 <ul class=
"md-nav__list" data-md-scrollfix
>
206 <li class=
"md-nav__item">
207 <a href=
"../../../getting-started/" class=
"md-nav__link">
222 <li class=
"md-nav__item md-nav__item--nested">
225 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_2" type=
"checkbox" id=
"__nav_2" >
227 <label class=
"md-nav__link" for=
"__nav_2">
229 <span class=
"md-nav__icon md-icon"></span>
231 <nav class=
"md-nav" aria-label=
"PHP API" data-md-level=
"1">
232 <label class=
"md-nav__title" for=
"__nav_2">
233 <span class=
"md-nav__icon md-icon"></span>
236 <ul class=
"md-nav__list" data-md-scrollfix
>
242 <li class=
"md-nav__item">
243 <a href=
"../../../php/pages/" class=
"md-nav__link">
254 <li class=
"md-nav__item">
255 <a href=
"../../../php/database-objects/" class=
"md-nav__link">
266 <li class=
"md-nav__item">
267 <a href=
"../../../php/database-access/" class=
"md-nav__link">
278 <li class=
"md-nav__item">
279 <a href=
"../../../php/exceptions/" class=
"md-nav__link">
291 <li class=
"md-nav__item md-nav__item--nested">
294 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_2_5" type=
"checkbox" id=
"__nav_2_5" >
296 <label class=
"md-nav__link" for=
"__nav_2_5">
298 <span class=
"md-nav__icon md-icon"></span>
300 <nav class=
"md-nav" aria-label=
"API" data-md-level=
"2">
301 <label class=
"md-nav__title" for=
"__nav_2_5">
302 <span class=
"md-nav__icon md-icon"></span>
305 <ul class=
"md-nav__list" data-md-scrollfix
>
312 <li class=
"md-nav__item md-nav__item--nested">
315 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_2_5_1" type=
"checkbox" id=
"__nav_2_5_1" >
317 <label class=
"md-nav__link" for=
"__nav_2_5_1">
319 <span class=
"md-nav__icon md-icon"></span>
321 <nav class=
"md-nav" aria-label=
"Caches" data-md-level=
"3">
322 <label class=
"md-nav__title" for=
"__nav_2_5_1">
323 <span class=
"md-nav__icon md-icon"></span>
326 <ul class=
"md-nav__list" data-md-scrollfix
>
332 <li class=
"md-nav__item">
333 <a href=
"../../../php/api/caches/" class=
"md-nav__link">
344 <li class=
"md-nav__item">
345 <a href=
"../../../php/api/caches_persistent-caches/" class=
"md-nav__link">
356 <li class=
"md-nav__item">
357 <a href=
"../../../php/api/caches_runtime-caches/" class=
"md-nav__link">
374 <li class=
"md-nav__item">
375 <a href=
"../../../php/api/comments/" class=
"md-nav__link">
386 <li class=
"md-nav__item">
387 <a href=
"../../../php/api/cronjobs/" class=
"md-nav__link">
398 <li class=
"md-nav__item">
399 <a href=
"../../../php/api/events/" class=
"md-nav__link">
411 <li class=
"md-nav__item md-nav__item--nested">
414 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_2_5_5" type=
"checkbox" id=
"__nav_2_5_5" >
416 <label class=
"md-nav__link" for=
"__nav_2_5_5">
418 <span class=
"md-nav__icon md-icon"></span>
420 <nav class=
"md-nav" aria-label=
"Form Builder" data-md-level=
"3">
421 <label class=
"md-nav__title" for=
"__nav_2_5_5">
422 <span class=
"md-nav__icon md-icon"></span>
425 <ul class=
"md-nav__list" data-md-scrollfix
>
431 <li class=
"md-nav__item">
432 <a href=
"../../../php/api/form_builder/overview/" class=
"md-nav__link">
443 <li class=
"md-nav__item">
444 <a href=
"../../../php/api/form_builder/structure/" class=
"md-nav__link">
455 <li class=
"md-nav__item">
456 <a href=
"../../../php/api/form_builder/form_fields/" class=
"md-nav__link">
467 <li class=
"md-nav__item">
468 <a href=
"../../../php/api/form_builder/validation_data/" class=
"md-nav__link">
479 <li class=
"md-nav__item">
480 <a href=
"../../../php/api/form_builder/dependencies/" class=
"md-nav__link">
497 <li class=
"md-nav__item">
498 <a href=
"../../../php/api/package_installation_plugins/" class=
"md-nav__link">
499 Package Installation Plugins
509 <li class=
"md-nav__item">
510 <a href=
"../../../php/api/user_activity_points/" class=
"md-nav__link">
521 <li class=
"md-nav__item">
522 <a href=
"../../../php/api/user_notifications/" class=
"md-nav__link">
533 <li class=
"md-nav__item">
534 <a href=
"../../../php/api/sitemaps/" class=
"md-nav__link">
551 <li class=
"md-nav__item">
552 <a href=
"../../../php/code-style/" class=
"md-nav__link">
563 <li class=
"md-nav__item">
564 <a href=
"../../../php/apps/" class=
"md-nav__link">
575 <li class=
"md-nav__item">
576 <a href=
"../../../php/gdpr/" class=
"md-nav__link">
597 <li class=
"md-nav__item md-nav__item--nested">
600 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_3" type=
"checkbox" id=
"__nav_3" >
602 <label class=
"md-nav__link" for=
"__nav_3">
603 Languages, Templates & CSS
604 <span class=
"md-nav__icon md-icon"></span>
606 <nav class=
"md-nav" aria-label=
"Languages, Templates & CSS" data-md-level=
"1">
607 <label class=
"md-nav__title" for=
"__nav_3">
608 <span class=
"md-nav__icon md-icon"></span>
609 Languages, Templates & CSS
611 <ul class=
"md-nav__list" data-md-scrollfix
>
617 <li class=
"md-nav__item">
618 <a href=
"../../../view/languages/" class=
"md-nav__link">
629 <li class=
"md-nav__item">
630 <a href=
"../../../view/templates/" class=
"md-nav__link">
641 <li class=
"md-nav__item">
642 <a href=
"../../../view/template-plugins/" class=
"md-nav__link">
653 <li class=
"md-nav__item">
654 <a href=
"../../../view/css/" class=
"md-nav__link">
675 <li class=
"md-nav__item md-nav__item--nested">
678 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_4" type=
"checkbox" id=
"__nav_4" >
680 <label class=
"md-nav__link" for=
"__nav_4">
681 TypeScript and JavaScript API
682 <span class=
"md-nav__icon md-icon"></span>
684 <nav class=
"md-nav" aria-label=
"TypeScript and JavaScript API" data-md-level=
"1">
685 <label class=
"md-nav__title" for=
"__nav_4">
686 <span class=
"md-nav__icon md-icon"></span>
687 TypeScript and JavaScript API
689 <ul class=
"md-nav__list" data-md-scrollfix
>
695 <li class=
"md-nav__item">
696 <a href=
"../../../javascript/general-usage/" class=
"md-nav__link">
707 <li class=
"md-nav__item">
708 <a href=
"../../../javascript/typescript/" class=
"md-nav__link">
720 <li class=
"md-nav__item md-nav__item--nested">
723 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_4_3" type=
"checkbox" id=
"__nav_4_3" >
725 <label class=
"md-nav__link" for=
"__nav_4_3">
727 <span class=
"md-nav__icon md-icon"></span>
729 <nav class=
"md-nav" aria-label=
"New API" data-md-level=
"2">
730 <label class=
"md-nav__title" for=
"__nav_4_3">
731 <span class=
"md-nav__icon md-icon"></span>
734 <ul class=
"md-nav__list" data-md-scrollfix
>
740 <li class=
"md-nav__item">
741 <a href=
"../../../javascript/new-api_writing-a-module/" class=
"md-nav__link">
752 <li class=
"md-nav__item">
753 <a href=
"../../../javascript/new-api_data-structures/" class=
"md-nav__link">
764 <li class=
"md-nav__item">
765 <a href=
"../../../javascript/new-api_core/" class=
"md-nav__link">
776 <li class=
"md-nav__item">
777 <a href=
"../../../javascript/new-api_dom/" class=
"md-nav__link">
788 <li class=
"md-nav__item">
789 <a href=
"../../../javascript/new-api_events/" class=
"md-nav__link">
800 <li class=
"md-nav__item">
801 <a href=
"../../../javascript/new-api_ajax/" class=
"md-nav__link">
812 <li class=
"md-nav__item">
813 <a href=
"../../../javascript/new-api_dialogs/" class=
"md-nav__link">
824 <li class=
"md-nav__item">
825 <a href=
"../../../javascript/new-api_browser/" class=
"md-nav__link">
826 Browser and Screen Sizes
836 <li class=
"md-nav__item">
837 <a href=
"../../../javascript/new-api_ui/" class=
"md-nav__link">
854 <li class=
"md-nav__item">
855 <a href=
"../../../javascript/legacy-api/" class=
"md-nav__link">
866 <li class=
"md-nav__item">
867 <a href=
"../../../javascript/helper-functions/" class=
"md-nav__link">
878 <li class=
"md-nav__item">
879 <a href=
"../../../javascript/code-snippets/" class=
"md-nav__link">
900 <li class=
"md-nav__item md-nav__item--nested">
903 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_5" type=
"checkbox" id=
"__nav_5" >
905 <label class=
"md-nav__link" for=
"__nav_5">
907 <span class=
"md-nav__icon md-icon"></span>
909 <nav class=
"md-nav" aria-label=
"Package Components" data-md-level=
"1">
910 <label class=
"md-nav__title" for=
"__nav_5">
911 <span class=
"md-nav__icon md-icon"></span>
914 <ul class=
"md-nav__list" data-md-scrollfix
>
920 <li class=
"md-nav__item">
921 <a href=
"../../../package/package-xml/" class=
"md-nav__link">
933 <li class=
"md-nav__item md-nav__item--nested">
936 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_5_2" type=
"checkbox" id=
"__nav_5_2" >
938 <label class=
"md-nav__link" for=
"__nav_5_2">
940 <span class=
"md-nav__icon md-icon"></span>
942 <nav class=
"md-nav" aria-label=
"PIPs" data-md-level=
"2">
943 <label class=
"md-nav__title" for=
"__nav_5_2">
944 <span class=
"md-nav__icon md-icon"></span>
947 <ul class=
"md-nav__list" data-md-scrollfix
>
953 <li class=
"md-nav__item">
954 <a href=
"../../../package/pip/" class=
"md-nav__link">
965 <li class=
"md-nav__item">
966 <a href=
"../../../package/pip/acl-option/" class=
"md-nav__link">
977 <li class=
"md-nav__item">
978 <a href=
"../../../package/pip/acp-menu/" class=
"md-nav__link">
989 <li class=
"md-nav__item">
990 <a href=
"../../../package/pip/acp-search-provider/" class=
"md-nav__link">
1001 <li class=
"md-nav__item">
1002 <a href=
"../../../package/pip/acp-template/" class=
"md-nav__link">
1013 <li class=
"md-nav__item">
1014 <a href=
"../../../package/pip/bbcode/" class=
"md-nav__link">
1025 <li class=
"md-nav__item">
1026 <a href=
"../../../package/pip/box/" class=
"md-nav__link">
1037 <li class=
"md-nav__item">
1038 <a href=
"../../../package/pip/clipboard-action/" class=
"md-nav__link">
1049 <li class=
"md-nav__item">
1050 <a href=
"../../../package/pip/core-object/" class=
"md-nav__link">
1061 <li class=
"md-nav__item">
1062 <a href=
"../../../package/pip/cronjob/" class=
"md-nav__link">
1073 <li class=
"md-nav__item">
1074 <a href=
"../../../package/pip/database/" class=
"md-nav__link">
1085 <li class=
"md-nav__item">
1086 <a href=
"../../../package/pip/event-listener/" class=
"md-nav__link">
1097 <li class=
"md-nav__item">
1098 <a href=
"../../../package/pip/file/" class=
"md-nav__link">
1109 <li class=
"md-nav__item">
1110 <a href=
"../../../package/pip/language/" class=
"md-nav__link">
1121 <li class=
"md-nav__item">
1122 <a href=
"../../../package/pip/media-provider/" class=
"md-nav__link">
1133 <li class=
"md-nav__item">
1134 <a href=
"../../../package/pip/menu/" class=
"md-nav__link">
1145 <li class=
"md-nav__item">
1146 <a href=
"../../../package/pip/menu-item/" class=
"md-nav__link">
1157 <li class=
"md-nav__item">
1158 <a href=
"../../../package/pip/object-type/" class=
"md-nav__link">
1169 <li class=
"md-nav__item">
1170 <a href=
"../../../package/pip/object-type-definition/" class=
"md-nav__link">
1171 objectTypeDefinition
1181 <li class=
"md-nav__item">
1182 <a href=
"../../../package/pip/option/" class=
"md-nav__link">
1193 <li class=
"md-nav__item">
1194 <a href=
"../../../package/pip/page/" class=
"md-nav__link">
1205 <li class=
"md-nav__item">
1206 <a href=
"../../../package/pip/pip/" class=
"md-nav__link">
1217 <li class=
"md-nav__item">
1218 <a href=
"../../../package/pip/script/" class=
"md-nav__link">
1229 <li class=
"md-nav__item">
1230 <a href=
"../../../package/pip/smiley/" class=
"md-nav__link">
1241 <li class=
"md-nav__item">
1242 <a href=
"../../../package/pip/sql/" class=
"md-nav__link">
1253 <li class=
"md-nav__item">
1254 <a href=
"../../../package/pip/style/" class=
"md-nav__link">
1265 <li class=
"md-nav__item">
1266 <a href=
"../../../package/pip/template/" class=
"md-nav__link">
1277 <li class=
"md-nav__item">
1278 <a href=
"../../../package/pip/template-listener/" class=
"md-nav__link">
1289 <li class=
"md-nav__item">
1290 <a href=
"../../../package/pip/user-group-option/" class=
"md-nav__link">
1301 <li class=
"md-nav__item">
1302 <a href=
"../../../package/pip/user-menu/" class=
"md-nav__link">
1313 <li class=
"md-nav__item">
1314 <a href=
"../../../package/pip/user-notification-event/" class=
"md-nav__link">
1315 userNotificationEvent
1325 <li class=
"md-nav__item">
1326 <a href=
"../../../package/pip/user-option/" class=
"md-nav__link">
1337 <li class=
"md-nav__item">
1338 <a href=
"../../../package/pip/user-profile-menu/" class=
"md-nav__link">
1355 <li class=
"md-nav__item">
1356 <a href=
"../../../package/database-php-api/" class=
"md-nav__link">
1377 <li class=
"md-nav__item md-nav__item--nested">
1380 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_6" type=
"checkbox" id=
"__nav_6" >
1382 <label class=
"md-nav__link" for=
"__nav_6">
1384 <span class=
"md-nav__icon md-icon"></span>
1386 <nav class=
"md-nav" aria-label=
"Migration" data-md-level=
"1">
1387 <label class=
"md-nav__title" for=
"__nav_6">
1388 <span class=
"md-nav__icon md-icon"></span>
1391 <ul class=
"md-nav__list" data-md-scrollfix
>
1398 <li class=
"md-nav__item md-nav__item--nested">
1401 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_6_1" type=
"checkbox" id=
"__nav_6_1" >
1403 <label class=
"md-nav__link" for=
"__nav_6_1">
1404 Migrating from WSC
5.3
1405 <span class=
"md-nav__icon md-icon"></span>
1407 <nav class=
"md-nav" aria-label=
"Migrating from WSC 5.3" data-md-level=
"2">
1408 <label class=
"md-nav__title" for=
"__nav_6_1">
1409 <span class=
"md-nav__icon md-icon"></span>
1410 Migrating from WSC
5.3
1412 <ul class=
"md-nav__list" data-md-scrollfix
>
1418 <li class=
"md-nav__item">
1419 <a href=
"../../../migration/wsc53/php/" class=
"md-nav__link">
1430 <li class=
"md-nav__item">
1431 <a href=
"../../../migration/wsc53/session/" class=
"md-nav__link">
1432 Session Handling and Authentication
1442 <li class=
"md-nav__item">
1443 <a href=
"../../../migration/wsc53/javascript/" class=
"md-nav__link">
1444 TypeScript and JavaScript
1454 <li class=
"md-nav__item">
1455 <a href=
"../../../migration/wsc53/templates/" class=
"md-nav__link">
1466 <li class=
"md-nav__item">
1467 <a href=
"../../../migration/wsc53/libraries/" class=
"md-nav__link">
1468 Third Party Libraries
1485 <li class=
"md-nav__item md-nav__item--nested">
1488 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_6_2" type=
"checkbox" id=
"__nav_6_2" >
1490 <label class=
"md-nav__link" for=
"__nav_6_2">
1491 Migrating from WSC
5.2
1492 <span class=
"md-nav__icon md-icon"></span>
1494 <nav class=
"md-nav" aria-label=
"Migrating from WSC 5.2" data-md-level=
"2">
1495 <label class=
"md-nav__title" for=
"__nav_6_2">
1496 <span class=
"md-nav__icon md-icon"></span>
1497 Migrating from WSC
5.2
1499 <ul class=
"md-nav__list" data-md-scrollfix
>
1505 <li class=
"md-nav__item">
1506 <a href=
"../../../migration/wsc52/php/" class=
"md-nav__link">
1517 <li class=
"md-nav__item">
1518 <a href=
"../../../migration/wsc52/templates/" class=
"md-nav__link">
1519 Templates and Languages
1529 <li class=
"md-nav__item">
1530 <a href=
"../../../migration/wsc52/libraries/" class=
"md-nav__link">
1531 Third Party Libraries
1548 <li class=
"md-nav__item md-nav__item--nested">
1551 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_6_3" type=
"checkbox" id=
"__nav_6_3" >
1553 <label class=
"md-nav__link" for=
"__nav_6_3">
1554 Migrating from WSC
3.1
1555 <span class=
"md-nav__icon md-icon"></span>
1557 <nav class=
"md-nav" aria-label=
"Migrating from WSC 3.1" data-md-level=
"2">
1558 <label class=
"md-nav__title" for=
"__nav_6_3">
1559 <span class=
"md-nav__icon md-icon"></span>
1560 Migrating from WSC
3.1
1562 <ul class=
"md-nav__list" data-md-scrollfix
>
1568 <li class=
"md-nav__item">
1569 <a href=
"../../../migration/wsc31/php/" class=
"md-nav__link">
1587 <li class=
"md-nav__item md-nav__item--nested">
1590 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_6_4" type=
"checkbox" id=
"__nav_6_4" >
1592 <label class=
"md-nav__link" for=
"__nav_6_4">
1593 Migrating from WSC
3.0
1594 <span class=
"md-nav__icon md-icon"></span>
1596 <nav class=
"md-nav" aria-label=
"Migrating from WSC 3.0" data-md-level=
"2">
1597 <label class=
"md-nav__title" for=
"__nav_6_4">
1598 <span class=
"md-nav__icon md-icon"></span>
1599 Migrating from WSC
3.0
1601 <ul class=
"md-nav__list" data-md-scrollfix
>
1607 <li class=
"md-nav__item">
1608 <a href=
"../../../migration/wsc30/php/" class=
"md-nav__link">
1619 <li class=
"md-nav__item">
1620 <a href=
"../../../migration/wsc30/javascript/" class=
"md-nav__link">
1631 <li class=
"md-nav__item">
1632 <a href=
"../../../migration/wsc30/templates/" class=
"md-nav__link">
1643 <li class=
"md-nav__item">
1644 <a href=
"../../../migration/wsc30/css/" class=
"md-nav__link">
1655 <li class=
"md-nav__item">
1656 <a href=
"../../../migration/wsc30/package/" class=
"md-nav__link">
1674 <li class=
"md-nav__item md-nav__item--nested">
1677 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_6_5" type=
"checkbox" id=
"__nav_6_5" >
1679 <label class=
"md-nav__link" for=
"__nav_6_5">
1680 Migrating from WCF
2.1
1681 <span class=
"md-nav__icon md-icon"></span>
1683 <nav class=
"md-nav" aria-label=
"Migrating from WCF 2.1" data-md-level=
"2">
1684 <label class=
"md-nav__title" for=
"__nav_6_5">
1685 <span class=
"md-nav__icon md-icon"></span>
1686 Migrating from WCF
2.1
1688 <ul class=
"md-nav__list" data-md-scrollfix
>
1694 <li class=
"md-nav__item">
1695 <a href=
"../../../migration/wcf21/php/" class=
"md-nav__link">
1706 <li class=
"md-nav__item">
1707 <a href=
"../../../migration/wcf21/templates/" class=
"md-nav__link">
1718 <li class=
"md-nav__item">
1719 <a href=
"../../../migration/wcf21/css/" class=
"md-nav__link">
1730 <li class=
"md-nav__item">
1731 <a href=
"../../../migration/wcf21/package/" class=
"md-nav__link">
1760 <li class=
"md-nav__item md-nav__item--active md-nav__item--nested">
1763 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_7" type=
"checkbox" id=
"__nav_7" checked
>
1765 <label class=
"md-nav__link" for=
"__nav_7">
1767 <span class=
"md-nav__icon md-icon"></span>
1769 <nav class=
"md-nav" aria-label=
"Tutorials" data-md-level=
"1">
1770 <label class=
"md-nav__title" for=
"__nav_7">
1771 <span class=
"md-nav__icon md-icon"></span>
1774 <ul class=
"md-nav__list" data-md-scrollfix
>
1783 <li class=
"md-nav__item md-nav__item--active md-nav__item--nested">
1786 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_7_1" type=
"checkbox" id=
"__nav_7_1" checked
>
1788 <label class=
"md-nav__link" for=
"__nav_7_1">
1790 <span class=
"md-nav__icon md-icon"></span>
1792 <nav class=
"md-nav" aria-label=
"Tutorial Series" data-md-level=
"2">
1793 <label class=
"md-nav__title" for=
"__nav_7_1">
1794 <span class=
"md-nav__icon md-icon"></span>
1797 <ul class=
"md-nav__list" data-md-scrollfix
>
1803 <li class=
"md-nav__item">
1804 <a href=
"../overview/" class=
"md-nav__link">
1817 <li class=
"md-nav__item md-nav__item--active">
1819 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"toc" type=
"checkbox" id=
"__toc">
1825 <label class=
"md-nav__link md-nav__link--active" for=
"__toc">
1827 <span class=
"md-nav__icon md-icon"></span>
1830 <a href=
"./" class=
"md-nav__link md-nav__link--active">
1835 <nav class=
"md-nav md-nav--secondary" aria-label=
"Table of contents">
1842 <label class=
"md-nav__title" for=
"__toc">
1843 <span class=
"md-nav__icon md-icon"></span>
1846 <ul class=
"md-nav__list" data-md-component=
"toc" data-md-scrollfix
>
1848 <li class=
"md-nav__item">
1849 <a href=
"#package-functionality" class=
"md-nav__link">
1850 Package Functionality
1855 <li class=
"md-nav__item">
1856 <a href=
"#used-components" class=
"md-nav__link">
1862 <li class=
"md-nav__item">
1863 <a href=
"#package-structure" class=
"md-nav__link">
1869 <li class=
"md-nav__item">
1870 <a href=
"#person-modeling" class=
"md-nav__link">
1874 <nav class=
"md-nav" aria-label=
"Person Modeling">
1875 <ul class=
"md-nav__list">
1877 <li class=
"md-nav__item">
1878 <a href=
"#database-table" class=
"md-nav__link">
1884 <li class=
"md-nav__item">
1885 <a href=
"#database-object" class=
"md-nav__link">
1889 <nav class=
"md-nav" aria-label=
"Database Object">
1890 <ul class=
"md-nav__list">
1892 <li class=
"md-nav__item">
1893 <a href=
"#person" class=
"md-nav__link">
1899 <li class=
"md-nav__item">
1900 <a href=
"#personaction" class=
"md-nav__link">
1906 <li class=
"md-nav__item">
1907 <a href=
"#personeditor" class=
"md-nav__link">
1913 <li class=
"md-nav__item">
1914 <a href=
"#personlist" class=
"md-nav__link">
1930 <li class=
"md-nav__item">
1931 <a href=
"#acp" class=
"md-nav__link">
1935 <nav class=
"md-nav" aria-label=
"ACP">
1936 <ul class=
"md-nav__list">
1938 <li class=
"md-nav__item">
1939 <a href=
"#acp-menu" class=
"md-nav__link">
1945 <li class=
"md-nav__item">
1946 <a href=
"#people-list" class=
"md-nav__link">
1950 <nav class=
"md-nav" aria-label=
"People List">
1951 <ul class=
"md-nav__list">
1953 <li class=
"md-nav__item">
1954 <a href=
"#personlistpage" class=
"md-nav__link">
1960 <li class=
"md-nav__item">
1961 <a href=
"#personlisttpl" class=
"md-nav__link">
1972 <li class=
"md-nav__item">
1973 <a href=
"#person-add-form" class=
"md-nav__link">
1977 <nav class=
"md-nav" aria-label=
"Person Add Form">
1978 <ul class=
"md-nav__list">
1980 <li class=
"md-nav__item">
1981 <a href=
"#personaddform" class=
"md-nav__link">
1987 <li class=
"md-nav__item">
1988 <a href=
"#personaddtpl" class=
"md-nav__link">
1999 <li class=
"md-nav__item">
2000 <a href=
"#person-edit-form" class=
"md-nav__link">
2004 <nav class=
"md-nav" aria-label=
"Person Edit Form">
2005 <ul class=
"md-nav__list">
2007 <li class=
"md-nav__item">
2008 <a href=
"#personeditform" class=
"md-nav__link">
2024 <li class=
"md-nav__item">
2025 <a href=
"#frontend" class=
"md-nav__link">
2029 <nav class=
"md-nav" aria-label=
"Frontend">
2030 <ul class=
"md-nav__list">
2032 <li class=
"md-nav__item">
2033 <a href=
"#pagexml" class=
"md-nav__link">
2039 <li class=
"md-nav__item">
2040 <a href=
"#menuitemxml" class=
"md-nav__link">
2046 <li class=
"md-nav__item">
2047 <a href=
"#people-list_1" class=
"md-nav__link">
2051 <nav class=
"md-nav" aria-label=
"People List">
2052 <ul class=
"md-nav__list">
2054 <li class=
"md-nav__item">
2055 <a href=
"#personlistpage_1" class=
"md-nav__link">
2061 <li class=
"md-nav__item">
2062 <a href=
"#personlisttpl_1" class=
"md-nav__link">
2078 <li class=
"md-nav__item">
2079 <a href=
"#usergroupoptionxml" class=
"md-nav__link">
2085 <li class=
"md-nav__item">
2086 <a href=
"#packagexml" class=
"md-nav__link">
2104 <li class=
"md-nav__item">
2105 <a href=
"../part_2/" class=
"md-nav__link">
2116 <li class=
"md-nav__item">
2117 <a href=
"../part_3/" class=
"md-nav__link">
2128 <li class=
"md-nav__item">
2129 <a href=
"../part_4/" class=
"md-nav__link">
2140 <li class=
"md-nav__item">
2141 <a href=
"../part_5/" class=
"md-nav__link">
2168 <div class=
"md-sidebar md-sidebar--secondary" data-md-component=
"sidebar" data-md-type=
"toc" >
2169 <div class=
"md-sidebar__scrollwrap">
2170 <div class=
"md-sidebar__inner">
2172 <nav class=
"md-nav md-nav--secondary" aria-label=
"Table of contents">
2179 <label class=
"md-nav__title" for=
"__toc">
2180 <span class=
"md-nav__icon md-icon"></span>
2183 <ul class=
"md-nav__list" data-md-component=
"toc" data-md-scrollfix
>
2185 <li class=
"md-nav__item">
2186 <a href=
"#package-functionality" class=
"md-nav__link">
2187 Package Functionality
2192 <li class=
"md-nav__item">
2193 <a href=
"#used-components" class=
"md-nav__link">
2199 <li class=
"md-nav__item">
2200 <a href=
"#package-structure" class=
"md-nav__link">
2206 <li class=
"md-nav__item">
2207 <a href=
"#person-modeling" class=
"md-nav__link">
2211 <nav class=
"md-nav" aria-label=
"Person Modeling">
2212 <ul class=
"md-nav__list">
2214 <li class=
"md-nav__item">
2215 <a href=
"#database-table" class=
"md-nav__link">
2221 <li class=
"md-nav__item">
2222 <a href=
"#database-object" class=
"md-nav__link">
2226 <nav class=
"md-nav" aria-label=
"Database Object">
2227 <ul class=
"md-nav__list">
2229 <li class=
"md-nav__item">
2230 <a href=
"#person" class=
"md-nav__link">
2236 <li class=
"md-nav__item">
2237 <a href=
"#personaction" class=
"md-nav__link">
2243 <li class=
"md-nav__item">
2244 <a href=
"#personeditor" class=
"md-nav__link">
2250 <li class=
"md-nav__item">
2251 <a href=
"#personlist" class=
"md-nav__link">
2267 <li class=
"md-nav__item">
2268 <a href=
"#acp" class=
"md-nav__link">
2272 <nav class=
"md-nav" aria-label=
"ACP">
2273 <ul class=
"md-nav__list">
2275 <li class=
"md-nav__item">
2276 <a href=
"#acp-menu" class=
"md-nav__link">
2282 <li class=
"md-nav__item">
2283 <a href=
"#people-list" class=
"md-nav__link">
2287 <nav class=
"md-nav" aria-label=
"People List">
2288 <ul class=
"md-nav__list">
2290 <li class=
"md-nav__item">
2291 <a href=
"#personlistpage" class=
"md-nav__link">
2297 <li class=
"md-nav__item">
2298 <a href=
"#personlisttpl" class=
"md-nav__link">
2309 <li class=
"md-nav__item">
2310 <a href=
"#person-add-form" class=
"md-nav__link">
2314 <nav class=
"md-nav" aria-label=
"Person Add Form">
2315 <ul class=
"md-nav__list">
2317 <li class=
"md-nav__item">
2318 <a href=
"#personaddform" class=
"md-nav__link">
2324 <li class=
"md-nav__item">
2325 <a href=
"#personaddtpl" class=
"md-nav__link">
2336 <li class=
"md-nav__item">
2337 <a href=
"#person-edit-form" class=
"md-nav__link">
2341 <nav class=
"md-nav" aria-label=
"Person Edit Form">
2342 <ul class=
"md-nav__list">
2344 <li class=
"md-nav__item">
2345 <a href=
"#personeditform" class=
"md-nav__link">
2361 <li class=
"md-nav__item">
2362 <a href=
"#frontend" class=
"md-nav__link">
2366 <nav class=
"md-nav" aria-label=
"Frontend">
2367 <ul class=
"md-nav__list">
2369 <li class=
"md-nav__item">
2370 <a href=
"#pagexml" class=
"md-nav__link">
2376 <li class=
"md-nav__item">
2377 <a href=
"#menuitemxml" class=
"md-nav__link">
2383 <li class=
"md-nav__item">
2384 <a href=
"#people-list_1" class=
"md-nav__link">
2388 <nav class=
"md-nav" aria-label=
"People List">
2389 <ul class=
"md-nav__list">
2391 <li class=
"md-nav__item">
2392 <a href=
"#personlistpage_1" class=
"md-nav__link">
2398 <li class=
"md-nav__item">
2399 <a href=
"#personlisttpl_1" class=
"md-nav__link">
2415 <li class=
"md-nav__item">
2416 <a href=
"#usergroupoptionxml" class=
"md-nav__link">
2422 <li class=
"md-nav__item">
2423 <a href=
"#packagexml" class=
"md-nav__link">
2437 <div class=
"md-content" data-md-component=
"content">
2438 <article class=
"md-content__inner md-typeset">
2441 <a href=
"https://github.com/WoltLab/docs.woltlab.com/edit/5.4/docs/tutorial/series/part_1.md" title=
"Edit this page" class=
"md-content__button md-icon">
2442 <svg xmlns=
"http://www.w3.org/2000/svg" viewBox=
"0 0 24 24"><path d=
"M20.71 7.04c.39-.39.39-1.04 0-1.41l-2.34-2.34c-.37-.39-1.02-.39-1.41 0l-1.84 1.83 3.75 3.75M3 17.25V21h3.75L17.81 9.93l-3.75-3.75L3 17.25z"/></svg>
2446 <h1 id=
"tutorial-series-part-1-base-structure">Tutorial Series Part
1: Base Structure
<a class=
"headerlink" href=
"#tutorial-series-part-1-base-structure" title=
"Permanent link">#
</a></h1>
2447 <p>In the first part of this tutorial series, we will lay out what the basic version of package should be able to do and how to implement these functions.
</p>
2448 <h2 id=
"package-functionality">Package Functionality
<a class=
"headerlink" href=
"#package-functionality" title=
"Permanent link">#
</a></h2>
2449 <p>The package should provide the following possibilities/functions:
</p>
2451 <li>Sortable list of all people in the ACP
</li>
2452 <li>Ability to add, edit and delete people in the ACP
</li>
2453 <li>Restrict the ability to add, edit and delete people (in short: manage people) in the ACP
</li>
2454 <li>Sortable list of all people in the front end
</li>
2456 <h2 id=
"used-components">Used Components
<a class=
"headerlink" href=
"#used-components" title=
"Permanent link">#
</a></h2>
2457 <p>We will use the following package installation plugins:
</p>
2459 <li><a href=
"../../../package/pip/acp-template/">acpTemplate package installation plugin
</a>,
</li>
2460 <li><a href=
"../../../package/pip/acp-menu/">acpMenu package installation plugin
</a>,
</li>
2461 <li><a href=
"../../../package/pip/database/">database package installation plugin
</a>,
</li>
2462 <li><a href=
"../../../package/pip/file/">file package installation plugin
</a>,
</li>
2463 <li><a href=
"../../../package/pip/language/">language package installation plugin
</a>,
</li>
2464 <li><a href=
"../../../package/pip/menu-item/">menuItem package installation plugin
</a>,
</li>
2465 <li><a href=
"../../../package/pip/page/">page package installation plugin
</a>,
</li>
2466 <li><a href=
"../../../package/pip/template/">template package installation plugin
</a>,
</li>
2467 <li><a href=
"../../../package/pip/user-group-option/">userGroupOption package installation plugin
</a>,
</li>
2469 <p>use
<a href=
"../../../php/database-objects/">database objects
</a>, create
<a href=
"../../../php/pages/">pages
</a> and use
<a href=
"../../../view/templates/">templates
</a>.
</p>
2470 <h2 id=
"package-structure">Package Structure
<a class=
"headerlink" href=
"#package-structure" title=
"Permanent link">#
</a></h2>
2471 <p>The package will have the following file structure:
</p>
2472 <table class=
"highlighttable"><tr><td class=
"linenos"><div class=
"linenodiv"><pre><span></span><span class=
"normal"> 1</span>
2473 <span class=
"normal"> 2</span>
2474 <span class=
"normal"> 3</span>
2475 <span class=
"normal"> 4</span>
2476 <span class=
"normal"> 5</span>
2477 <span class=
"normal"> 6</span>
2478 <span class=
"normal"> 7</span>
2479 <span class=
"normal"> 8</span>
2480 <span class=
"normal"> 9</span>
2481 <span class=
"normal">10</span>
2482 <span class=
"normal">11</span>
2483 <span class=
"normal">12</span>
2484 <span class=
"normal">13</span>
2485 <span class=
"normal">14</span>
2486 <span class=
"normal">15</span>
2487 <span class=
"normal">16</span>
2488 <span class=
"normal">17</span>
2489 <span class=
"normal">18</span>
2490 <span class=
"normal">19</span>
2491 <span class=
"normal">20</span>
2492 <span class=
"normal">21</span>
2493 <span class=
"normal">22</span>
2494 <span class=
"normal">23</span>
2495 <span class=
"normal">24</span>
2496 <span class=
"normal">25</span>
2497 <span class=
"normal">26</span>
2498 <span class=
"normal">27</span>
2499 <span class=
"normal">28</span>
2500 <span class=
"normal">29</span>
2501 <span class=
"normal">30</span>
2502 <span class=
"normal">31</span>
2503 <span class=
"normal">32</span></pre></div></td><td class=
"code"><div class=
"highlight"><pre><span></span><code>├── acpMenu.xml
2506 │ └── personList.tpl
2510 │ │ └── install_com.woltlab.wcf.people.php
2514 │ │ │ ├── PersonAddForm.class.php
2515 │ │ │ └── PersonEditForm.class.php
2517 │ │ └── PersonListPage.class.php
2520 │ │ ├── Person.class.php
2521 │ │ ├── PersonAction.class.php
2522 │ │ ├── PersonEditor.class.php
2523 │ │ └── PersonList.class.php
2525 │ └── PersonListPage.class.php
2533 │ └── personList.tpl
2534 └── userGroupOption.xml
2537 <h2 id=
"person-modeling">Person Modeling
<a class=
"headerlink" href=
"#person-modeling" title=
"Permanent link">#
</a></h2>
2538 <h3 id=
"database-table">Database Table
<a class=
"headerlink" href=
"#database-table" title=
"Permanent link">#
</a></h3>
2539 <p>As the first step, we have to model the people we want to manage with this package.
2540 As this is only an introductory tutorial, we will keep things simple and only consider the first and last name of a person.
2541 Thus, the database table we will store the people in only contains three columns:
</p>
2543 <li><code>personID
</code> is the unique numeric identifier of each person created,
</li>
2544 <li><code>firstName
</code> contains the first name of the person,
</li>
2545 <li><code>lastName
</code> contains the last name of the person.
</li>
2547 <p>The first file for our package is the
<code>install_com.woltlab.wcf.people.php
</code> file used to create such a database table during package installation:
</p>
2548 <div class=
"titledCodeBox">
2549 <div class=
"codeBoxTitle"><code>files/acp/database/install_com.woltlab.wcf.people.php
</code></div>
2550 <table class=
"highlighttable"><tr><td class=
"linenos"><div class=
"linenodiv"><pre><span></span><span class=
"normal"> 1</span>
2551 <span class=
"normal"> 2</span>
2552 <span class=
"normal"> 3</span>
2553 <span class=
"normal"> 4</span>
2554 <span class=
"normal"> 5</span>
2555 <span class=
"normal"> 6</span>
2556 <span class=
"normal"> 7</span>
2557 <span class=
"normal"> 8</span>
2558 <span class=
"normal"> 9</span>
2559 <span class=
"normal">10</span>
2560 <span class=
"normal">11</span>
2561 <span class=
"normal">12</span>
2562 <span class=
"normal">13</span>
2563 <span class=
"normal">14</span></pre></div></td><td class=
"code"><div class=
"highlight"><pre><span></span><code><span class=
"o"><?
</span><span class=
"nx">php
</span>
2565 <span class=
"k">use
</span> <span class=
"nx">wcf\system\database\table\column\NotNullVarchar255DatabaseTableColumn
</span><span class=
"p">;
</span>
2566 <span class=
"k">use
</span> <span class=
"nx">wcf\system\database\table\column\ObjectIdDatabaseTableColumn
</span><span class=
"p">;
</span>
2567 <span class=
"k">use
</span> <span class=
"nx">wcf\system\database\table\DatabaseTable
</span><span class=
"p">;
</span>
2569 <span class=
"k">return
</span> <span class=
"p">[
</span>
2570 <span class=
"nx">DatabaseTable
</span><span class=
"o">::
</span><span class=
"na">create
</span><span class=
"p">(
</span><span class=
"s1">'wcf1_person
'</span><span class=
"p">)
</span>
2571 <span class=
"o">-
></span><span class=
"na">columns
</span><span class=
"p">([
</span>
2572 <span class=
"nx">ObjectIdDatabaseTableColumn
</span><span class=
"o">::
</span><span class=
"na">create
</span><span class=
"p">(
</span><span class=
"s1">'personID
'</span><span class=
"p">),
</span>
2573 <span class=
"nx">NotNullVarchar255DatabaseTableColumn
</span><span class=
"o">::
</span><span class=
"na">create
</span><span class=
"p">(
</span><span class=
"s1">'firstName
'</span><span class=
"p">),
</span>
2574 <span class=
"nx">NotNullVarchar255DatabaseTableColumn
</span><span class=
"o">::
</span><span class=
"na">create
</span><span class=
"p">(
</span><span class=
"s1">'lastName
'</span><span class=
"p">),
</span>
2575 <span class=
"p">]),
</span>
2576 <span class=
"p">];
</span>
2581 <h3 id=
"database-object">Database Object
<a class=
"headerlink" href=
"#database-object" title=
"Permanent link">#
</a></h3>
2582 <h4 id=
"person"><code>Person
</code><a class=
"headerlink" href=
"#person" title=
"Permanent link">#
</a></h4>
2583 <p>In our PHP code, each person will be represented by an object of the following class:
</p>
2584 <div class=
"titledCodeBox">
2585 <div class=
"codeBoxTitle"><code>files/lib/data/person/Person.class.php
</code></div>
2586 <table class=
"highlighttable"><tr><td class=
"linenos"><div class=
"linenodiv"><pre><span></span><span class=
"normal"> 1</span>
2587 <span class=
"normal"> 2</span>
2588 <span class=
"normal"> 3</span>
2589 <span class=
"normal"> 4</span>
2590 <span class=
"normal"> 5</span>
2591 <span class=
"normal"> 6</span>
2592 <span class=
"normal"> 7</span>
2593 <span class=
"normal"> 8</span>
2594 <span class=
"normal"> 9</span>
2595 <span class=
"normal">10</span>
2596 <span class=
"normal">11</span>
2597 <span class=
"normal">12</span>
2598 <span class=
"normal">13</span>
2599 <span class=
"normal">14</span>
2600 <span class=
"normal">15</span>
2601 <span class=
"normal">16</span>
2602 <span class=
"normal">17</span>
2603 <span class=
"normal">18</span>
2604 <span class=
"normal">19</span>
2605 <span class=
"normal">20</span>
2606 <span class=
"normal">21</span>
2607 <span class=
"normal">22</span>
2608 <span class=
"normal">23</span>
2609 <span class=
"normal">24</span>
2610 <span class=
"normal">25</span>
2611 <span class=
"normal">26</span>
2612 <span class=
"normal">27</span>
2613 <span class=
"normal">28</span>
2614 <span class=
"normal">29</span>
2615 <span class=
"normal">30</span>
2616 <span class=
"normal">31</span>
2617 <span class=
"normal">32</span>
2618 <span class=
"normal">33</span>
2619 <span class=
"normal">34</span>
2620 <span class=
"normal">35</span>
2621 <span class=
"normal">36</span>
2622 <span class=
"normal">37</span>
2623 <span class=
"normal">38</span>
2624 <span class=
"normal">39</span></pre></div></td><td class=
"code"><div class=
"highlight"><pre><span></span><code><span class=
"o"><?
</span><span class=
"nx">php
</span>
2626 <span class=
"k">namespace
</span> <span class=
"nx">wcf\data\person
</span><span class=
"p">;
</span>
2628 <span class=
"k">use
</span> <span class=
"nx">wcf\data\DatabaseObject
</span><span class=
"p">;
</span>
2629 <span class=
"k">use
</span> <span class=
"nx">wcf\system\request\IRouteController
</span><span class=
"p">;
</span>
2631 <span class=
"sd">/**
</span>
2632 <span class=
"sd"> * Represents a person.
</span>
2633 <span class=
"sd"> *
</span>
2634 <span class=
"sd"> * @author Matthias Schmidt
</span>
2635 <span class=
"sd"> * @copyright
2001-
2021 WoltLab GmbH
</span>
2636 <span class=
"sd"> * @license GNU Lesser General Public License
<http://opensource.org/licenses/lgpl-license.php
></span>
2637 <span class=
"sd"> * @package WoltLabSuite\Core\Data\Person
</span>
2638 <span class=
"sd"> *
</span>
2639 <span class=
"sd"> * @property-read integer $personID unique id of the person
</span>
2640 <span class=
"sd"> * @property-read string $firstName first name of the person
</span>
2641 <span class=
"sd"> * @property-read string $lastName last name of the person
</span>
2642 <span class=
"sd"> */
</span>
2643 <span class=
"k">class
</span> <span class=
"nc">Person
</span> <span class=
"k">extends
</span> <span class=
"nx">DatabaseObject
</span> <span class=
"k">implements
</span> <span class=
"nx">IRouteController
</span>
2644 <span class=
"p">{
</span>
2645 <span class=
"sd">/**
</span>
2646 <span class=
"sd"> * Returns the first and last name of the person if a person object is treated as a string.
</span>
2647 <span class=
"sd"> *
</span>
2648 <span class=
"sd"> * @return string
</span>
2649 <span class=
"sd"> */
</span>
2650 <span class=
"k">public
</span> <span class=
"k">function
</span> <span class=
"fm">__toString
</span><span class=
"p">()
</span>
2651 <span class=
"p">{
</span>
2652 <span class=
"k">return
</span> <span class=
"nv">$this
</span><span class=
"o">-
></span><span class=
"na">getTitle
</span><span class=
"p">();
</span>
2653 <span class=
"p">}
</span>
2655 <span class=
"sd">/**
</span>
2656 <span class=
"sd"> * @inheritDoc
</span>
2657 <span class=
"sd"> */
</span>
2658 <span class=
"k">public
</span> <span class=
"k">function
</span> <span class=
"nf">getTitle
</span><span class=
"p">()
</span>
2659 <span class=
"p">{
</span>
2660 <span class=
"k">return
</span> <span class=
"nv">$this
</span><span class=
"o">-
></span><span class=
"na">firstName
</span> <span class=
"o">.
</span> <span class=
"s1">' '</span> <span class=
"o">.
</span> <span class=
"nv">$this
</span><span class=
"o">-
></span><span class=
"na">lastName
</span><span class=
"p">;
</span>
2661 <span class=
"p">}
</span>
2662 <span class=
"p">}
</span>
2667 <p>The important thing here is that
<code>Person
</code> extends
<code>DatabaseObject
</code>.
2668 Additionally, we implement the
<code>IRouteController
</code> interface, which allows us to use
<code>Person
</code> objects to create links, and we implement PHP's magic
<a href=
"https://secure.php.net/manual/en/language.oop5.magic.php#object.tostring">__toString()
</a> method for convenience.
</p>
2669 <p>For every database object, you need to implement three additional classes:
2670 an action class, an editor class and a list class.
</p>
2671 <h4 id=
"personaction"><code>PersonAction
</code><a class=
"headerlink" href=
"#personaction" title=
"Permanent link">#
</a></h4>
2672 <div class=
"titledCodeBox">
2673 <div class=
"codeBoxTitle"><code>files/lib/data/person/PersonAction.class.php
</code></div>
2674 <table class=
"highlighttable"><tr><td class=
"linenos"><div class=
"linenodiv"><pre><span></span><span class=
"normal"> 1</span>
2675 <span class=
"normal"> 2</span>
2676 <span class=
"normal"> 3</span>
2677 <span class=
"normal"> 4</span>
2678 <span class=
"normal"> 5</span>
2679 <span class=
"normal"> 6</span>
2680 <span class=
"normal"> 7</span>
2681 <span class=
"normal"> 8</span>
2682 <span class=
"normal"> 9</span>
2683 <span class=
"normal">10</span>
2684 <span class=
"normal">11</span>
2685 <span class=
"normal">12</span>
2686 <span class=
"normal">13</span>
2687 <span class=
"normal">14</span>
2688 <span class=
"normal">15</span>
2689 <span class=
"normal">16</span>
2690 <span class=
"normal">17</span>
2691 <span class=
"normal">18</span>
2692 <span class=
"normal">19</span>
2693 <span class=
"normal">20</span>
2694 <span class=
"normal">21</span>
2695 <span class=
"normal">22</span>
2696 <span class=
"normal">23</span>
2697 <span class=
"normal">24</span>
2698 <span class=
"normal">25</span>
2699 <span class=
"normal">26</span>
2700 <span class=
"normal">27</span>
2701 <span class=
"normal">28</span>
2702 <span class=
"normal">29</span>
2703 <span class=
"normal">30</span></pre></div></td><td class=
"code"><div class=
"highlight"><pre><span></span><code><span class=
"o"><?
</span><span class=
"nx">php
</span>
2705 <span class=
"k">namespace
</span> <span class=
"nx">wcf\data\person
</span><span class=
"p">;
</span>
2707 <span class=
"k">use
</span> <span class=
"nx">wcf\data\AbstractDatabaseObjectAction
</span><span class=
"p">;
</span>
2709 <span class=
"sd">/**
</span>
2710 <span class=
"sd"> * Executes person-related actions.
</span>
2711 <span class=
"sd"> *
</span>
2712 <span class=
"sd"> * @author Matthias Schmidt
</span>
2713 <span class=
"sd"> * @copyright
2001-
2021 WoltLab GmbH
</span>
2714 <span class=
"sd"> * @license GNU Lesser General Public License
<http://opensource.org/licenses/lgpl-license.php
></span>
2715 <span class=
"sd"> * @package WoltLabSuite\Core\Data\Person
</span>
2716 <span class=
"sd"> *
</span>
2717 <span class=
"sd"> * @method Person create()
</span>
2718 <span class=
"sd"> * @method PersonEditor[] getObjects()
</span>
2719 <span class=
"sd"> * @method PersonEditor getSingleObject()
</span>
2720 <span class=
"sd"> */
</span>
2721 <span class=
"k">class
</span> <span class=
"nc">PersonAction
</span> <span class=
"k">extends
</span> <span class=
"nx">AbstractDatabaseObjectAction
</span>
2722 <span class=
"p">{
</span>
2723 <span class=
"sd">/**
</span>
2724 <span class=
"sd"> * @inheritDoc
</span>
2725 <span class=
"sd"> */
</span>
2726 <span class=
"k">protected
</span> <span class=
"nv">$permissionsDelete
</span> <span class=
"o">=
</span> <span class=
"p">[
</span><span class=
"s1">'admin.content.canManagePeople
'</span><span class=
"p">];
</span>
2728 <span class=
"sd">/**
</span>
2729 <span class=
"sd"> * @inheritDoc
</span>
2730 <span class=
"sd"> */
</span>
2731 <span class=
"k">protected
</span> <span class=
"nv">$requireACP
</span> <span class=
"o">=
</span> <span class=
"p">[
</span><span class=
"s1">'delete
'</span><span class=
"p">];
</span>
2732 <span class=
"p">}
</span>
2737 <p>This implementation of
<code>AbstractDatabaseObjectAction
</code> is very basic and only sets the
<code>$permissionsDelete
</code> and
<code>$requireACP
</code> properties.
2738 This is done so that later on, when implementing the people list for the ACP, we can delete people simply via AJAX.
2739 <code>$permissionsDelete
</code> has to be set to the permission needed in order to delete a person.
2740 We will later use the
<a href=
"../../../package/pip/user-group-option/">userGroupOption package installation plugin
</a> to create the
<code>admin.content.canManagePeople
</code> permission.
2741 <code>$requireACP
</code> restricts deletion of people to the ACP.
</p>
2742 <h4 id=
"personeditor"><code>PersonEditor
</code><a class=
"headerlink" href=
"#personeditor" title=
"Permanent link">#
</a></h4>
2743 <div class=
"titledCodeBox">
2744 <div class=
"codeBoxTitle"><code>files/lib/data/person/PersonEditor.class.php
</code></div>
2745 <table class=
"highlighttable"><tr><td class=
"linenos"><div class=
"linenodiv"><pre><span></span><span class=
"normal"> 1</span>
2746 <span class=
"normal"> 2</span>
2747 <span class=
"normal"> 3</span>
2748 <span class=
"normal"> 4</span>
2749 <span class=
"normal"> 5</span>
2750 <span class=
"normal"> 6</span>
2751 <span class=
"normal"> 7</span>
2752 <span class=
"normal"> 8</span>
2753 <span class=
"normal"> 9</span>
2754 <span class=
"normal">10</span>
2755 <span class=
"normal">11</span>
2756 <span class=
"normal">12</span>
2757 <span class=
"normal">13</span>
2758 <span class=
"normal">14</span>
2759 <span class=
"normal">15</span>
2760 <span class=
"normal">16</span>
2761 <span class=
"normal">17</span>
2762 <span class=
"normal">18</span>
2763 <span class=
"normal">19</span>
2764 <span class=
"normal">20</span>
2765 <span class=
"normal">21</span>
2766 <span class=
"normal">22</span>
2767 <span class=
"normal">23</span>
2768 <span class=
"normal">24</span>
2769 <span class=
"normal">25</span></pre></div></td><td class=
"code"><div class=
"highlight"><pre><span></span><code><span class=
"o"><?
</span><span class=
"nx">php
</span>
2771 <span class=
"k">namespace
</span> <span class=
"nx">wcf\data\person
</span><span class=
"p">;
</span>
2773 <span class=
"k">use
</span> <span class=
"nx">wcf\data\DatabaseObjectEditor
</span><span class=
"p">;
</span>
2775 <span class=
"sd">/**
</span>
2776 <span class=
"sd"> * Provides functions to edit people.
</span>
2777 <span class=
"sd"> *
</span>
2778 <span class=
"sd"> * @author Matthias Schmidt
</span>
2779 <span class=
"sd"> * @copyright
2001-
2021 WoltLab GmbH
</span>
2780 <span class=
"sd"> * @license GNU Lesser General Public License
<http://opensource.org/licenses/lgpl-license.php
></span>
2781 <span class=
"sd"> * @package WoltLabSuite\Core\Data\Person
</span>
2782 <span class=
"sd"> *
</span>
2783 <span class=
"sd"> * @method static Person create(array $parameters = [])
</span>
2784 <span class=
"sd"> * @method Person getDecoratedObject()
</span>
2785 <span class=
"sd"> * @mixin Person
</span>
2786 <span class=
"sd"> */
</span>
2787 <span class=
"k">class
</span> <span class=
"nc">PersonEditor
</span> <span class=
"k">extends
</span> <span class=
"nx">DatabaseObjectEditor
</span>
2788 <span class=
"p">{
</span>
2789 <span class=
"sd">/**
</span>
2790 <span class=
"sd"> * @inheritDoc
</span>
2791 <span class=
"sd"> */
</span>
2792 <span class=
"k">protected
</span> <span class=
"k">static
</span> <span class=
"nv">$baseClass
</span> <span class=
"o">=
</span> <span class=
"nx">Person
</span><span class=
"o">::
</span><span class=
"na">class
</span><span class=
"p">;
</span>
2793 <span class=
"p">}
</span>
2798 <p>This implementation of
<code>DatabaseObjectEditor
</code> fulfills the minimum requirement for a database object editor:
2799 setting the static
<code>$baseClass
</code> property to the database object class name.
</p>
2800 <h4 id=
"personlist"><code>PersonList
</code><a class=
"headerlink" href=
"#personlist" title=
"Permanent link">#
</a></h4>
2801 <div class=
"titledCodeBox">
2802 <div class=
"codeBoxTitle"><code>files/lib/data/person/PersonList.class.php
</code></div>
2803 <table class=
"highlighttable"><tr><td class=
"linenos"><div class=
"linenodiv"><pre><span></span><span class=
"normal"> 1</span>
2804 <span class=
"normal"> 2</span>
2805 <span class=
"normal"> 3</span>
2806 <span class=
"normal"> 4</span>
2807 <span class=
"normal"> 5</span>
2808 <span class=
"normal"> 6</span>
2809 <span class=
"normal"> 7</span>
2810 <span class=
"normal"> 8</span>
2811 <span class=
"normal"> 9</span>
2812 <span class=
"normal">10</span>
2813 <span class=
"normal">11</span>
2814 <span class=
"normal">12</span>
2815 <span class=
"normal">13</span>
2816 <span class=
"normal">14</span>
2817 <span class=
"normal">15</span>
2818 <span class=
"normal">16</span>
2819 <span class=
"normal">17</span>
2820 <span class=
"normal">18</span>
2821 <span class=
"normal">19</span>
2822 <span class=
"normal">20</span>
2823 <span class=
"normal">21</span>
2824 <span class=
"normal">22</span></pre></div></td><td class=
"code"><div class=
"highlight"><pre><span></span><code><span class=
"o"><?
</span><span class=
"nx">php
</span>
2826 <span class=
"k">namespace
</span> <span class=
"nx">wcf\data\person
</span><span class=
"p">;
</span>
2828 <span class=
"k">use
</span> <span class=
"nx">wcf\data\DatabaseObjectList
</span><span class=
"p">;
</span>
2830 <span class=
"sd">/**
</span>
2831 <span class=
"sd"> * Represents a list of people.
</span>
2832 <span class=
"sd"> *
</span>
2833 <span class=
"sd"> * @author Matthias Schmidt
</span>
2834 <span class=
"sd"> * @copyright
2001-
2021 WoltLab GmbH
</span>
2835 <span class=
"sd"> * @license GNU Lesser General Public License
<http://opensource.org/licenses/lgpl-license.php
></span>
2836 <span class=
"sd"> * @package WoltLabSuite\Core\Data\Person
</span>
2837 <span class=
"sd"> *
</span>
2838 <span class=
"sd"> * @method Person current()
</span>
2839 <span class=
"sd"> * @method Person[] getObjects()
</span>
2840 <span class=
"sd"> * @method Person|null search($objectID)
</span>
2841 <span class=
"sd"> * @property Person[] $objects
</span>
2842 <span class=
"sd"> */
</span>
2843 <span class=
"k">class
</span> <span class=
"nc">PersonList
</span> <span class=
"k">extends
</span> <span class=
"nx">DatabaseObjectList
</span>
2844 <span class=
"p">{
</span>
2845 <span class=
"p">}
</span>
2850 <p>Due to the default implementation of
<code>DatabaseObjectList
</code>, our
<code>PersonList
</code> class just needs to extend it and everything else is either automatically set by the code of
<code>DatabaseObjectList
</code> or, in the case of properties and methods, provided by that class.
</p>
2851 <h2 id=
"acp">ACP
<a class=
"headerlink" href=
"#acp" title=
"Permanent link">#
</a></h2>
2852 <p>Next, we will take care of the controllers and views for the ACP.
2853 In total, we need three each:
</p>
2855 <li>page to list people,
</li>
2856 <li>form to add people, and
</li>
2857 <li>form to edit people.
</li>
2859 <p>Before we create the controllers and views, let us first create the menu items for the pages in the ACP menu.
</p>
2860 <h3 id=
"acp-menu">ACP Menu
<a class=
"headerlink" href=
"#acp-menu" title=
"Permanent link">#
</a></h3>
2861 <p>We need to create three menu items:
</p>
2863 <li>a “parent” menu item on the second level of the ACP menu item tree,
</li>
2864 <li>a third level menu item for the people list page, and
</li>
2865 <li>a fourth level menu item for the form to add new people.
</li>
2867 <div class=
"titledCodeBox">
2868 <div class=
"codeBoxTitle"><code>acpMenu.xml
</code></div>
2869 <table class=
"highlighttable"><tr><td class=
"linenos"><div class=
"linenodiv"><pre><span></span><span class=
"normal"> 1</span>
2870 <span class=
"normal"> 2</span>
2871 <span class=
"normal"> 3</span>
2872 <span class=
"normal"> 4</span>
2873 <span class=
"normal"> 5</span>
2874 <span class=
"normal"> 6</span>
2875 <span class=
"normal"> 7</span>
2876 <span class=
"normal"> 8</span>
2877 <span class=
"normal"> 9</span>
2878 <span class=
"normal">10</span>
2879 <span class=
"normal">11</span>
2880 <span class=
"normal">12</span>
2881 <span class=
"normal">13</span>
2882 <span class=
"normal">14</span>
2883 <span class=
"normal">15</span>
2884 <span class=
"normal">16</span>
2885 <span class=
"normal">17</span>
2886 <span class=
"normal">18</span>
2887 <span class=
"normal">19</span></pre></div></td><td class=
"code"><div class=
"highlight"><pre><span></span><code><span class=
"cp"><?xml version=
"1.0" encoding=
"UTF-
8"?
></span>
2888 <span class=
"nt"><data
</span> <span class=
"na">xmlns=
</span><span class=
"s">"http://www.woltlab.com
"</span> <span class=
"na">xmlns:xsi=
</span><span class=
"s">"http://www.w3.org/
2001/XMLSchema-instance
"</span> <span class=
"na">xsi:schemaLocation=
</span><span class=
"s">"http://www.woltlab.com http://www.woltlab.com/XSD/
5.4/acpMenu.xsd
"</span><span class=
"nt">></span>
2889 <span class=
"nt"><import
></span>
2890 <span class=
"nt"><acpmenuitem
</span> <span class=
"na">name=
</span><span class=
"s">"wcf.acp.menu.link.person
"</span><span class=
"nt">></span>
2891 <span class=
"nt"><parent
></span>wcf.acp.menu.link.content
<span class=
"nt"></parent
></span>
2892 <span class=
"nt"></acpmenuitem
></span>
2893 <span class=
"nt"><acpmenuitem
</span> <span class=
"na">name=
</span><span class=
"s">"wcf.acp.menu.link.person.list
"</span><span class=
"nt">></span>
2894 <span class=
"nt"><controller
></span>wcf\acp\page\PersonListPage
<span class=
"nt"></controller
></span>
2895 <span class=
"nt"><parent
></span>wcf.acp.menu.link.person
<span class=
"nt"></parent
></span>
2896 <span class=
"nt"><permissions
></span>admin.content.canManagePeople
<span class=
"nt"></permissions
></span>
2897 <span class=
"nt"></acpmenuitem
></span>
2898 <span class=
"nt"><acpmenuitem
</span> <span class=
"na">name=
</span><span class=
"s">"wcf.acp.menu.link.person.add
"</span><span class=
"nt">></span>
2899 <span class=
"nt"><controller
></span>wcf\acp\form\PersonAddForm
<span class=
"nt"></controller
></span>
2900 <span class=
"nt"><parent
></span>wcf.acp.menu.link.person.list
<span class=
"nt"></parent
></span>
2901 <span class=
"nt"><permissions
></span>admin.content.canManagePeople
<span class=
"nt"></permissions
></span>
2902 <span class=
"nt"><icon
></span>fa-plus
<span class=
"nt"></icon
></span>
2903 <span class=
"nt"></acpmenuitem
></span>
2904 <span class=
"nt"></import
></span>
2905 <span class=
"nt"></data
></span>
2910 <p>We choose
<code>wcf.acp.menu.link.content
</code> as the parent menu item for the first menu item
<code>wcf.acp.menu.link.person
</code> because the people we are managing is just one form of content.
2911 The fourth level menu item
<code>wcf.acp.menu.link.person.add
</code> will only be shown as an icon and thus needs an additional element
<code>icon
</code> which takes a FontAwesome icon class as value.
</p>
2912 <h3 id=
"people-list">People List
<a class=
"headerlink" href=
"#people-list" title=
"Permanent link">#
</a></h3>
2913 <p>To list the people in the ACP, we need a
<code>PersonListPage
</code> class and a
<code>personList
</code> template.
</p>
2914 <h4 id=
"personlistpage"><code>PersonListPage
</code><a class=
"headerlink" href=
"#personlistpage" title=
"Permanent link">#
</a></h4>
2915 <div class=
"titledCodeBox">
2916 <div class=
"codeBoxTitle"><code>files/lib/data/person/PersonListPage.class.php
</code></div>
2917 <table class=
"highlighttable"><tr><td class=
"linenos"><div class=
"linenodiv"><pre><span></span><span class=
"normal"> 1</span>
2918 <span class=
"normal"> 2</span>
2919 <span class=
"normal"> 3</span>
2920 <span class=
"normal"> 4</span>
2921 <span class=
"normal"> 5</span>
2922 <span class=
"normal"> 6</span>
2923 <span class=
"normal"> 7</span>
2924 <span class=
"normal"> 8</span>
2925 <span class=
"normal"> 9</span>
2926 <span class=
"normal">10</span>
2927 <span class=
"normal">11</span>
2928 <span class=
"normal">12</span>
2929 <span class=
"normal">13</span>
2930 <span class=
"normal">14</span>
2931 <span class=
"normal">15</span>
2932 <span class=
"normal">16</span>
2933 <span class=
"normal">17</span>
2934 <span class=
"normal">18</span>
2935 <span class=
"normal">19</span>
2936 <span class=
"normal">20</span>
2937 <span class=
"normal">21</span>
2938 <span class=
"normal">22</span>
2939 <span class=
"normal">23</span>
2940 <span class=
"normal">24</span>
2941 <span class=
"normal">25</span>
2942 <span class=
"normal">26</span>
2943 <span class=
"normal">27</span>
2944 <span class=
"normal">28</span>
2945 <span class=
"normal">29</span>
2946 <span class=
"normal">30</span>
2947 <span class=
"normal">31</span>
2948 <span class=
"normal">32</span>
2949 <span class=
"normal">33</span>
2950 <span class=
"normal">34</span>
2951 <span class=
"normal">35</span>
2952 <span class=
"normal">36</span>
2953 <span class=
"normal">37</span></pre></div></td><td class=
"code"><div class=
"highlight"><pre><span></span><code><span class=
"o"><?
</span><span class=
"nx">php
</span>
2955 <span class=
"k">namespace
</span> <span class=
"nx">wcf\acp\page
</span><span class=
"p">;
</span>
2957 <span class=
"k">use
</span> <span class=
"nx">wcf\data\person\PersonList
</span><span class=
"p">;
</span>
2958 <span class=
"k">use
</span> <span class=
"nx">wcf\page\SortablePage
</span><span class=
"p">;
</span>
2960 <span class=
"sd">/**
</span>
2961 <span class=
"sd"> * Shows the list of people.
</span>
2962 <span class=
"sd"> *
</span>
2963 <span class=
"sd"> * @author Matthias Schmidt
</span>
2964 <span class=
"sd"> * @copyright
2001-
2021 WoltLab GmbH
</span>
2965 <span class=
"sd"> * @license GNU Lesser General Public License
<http://opensource.org/licenses/lgpl-license.php
></span>
2966 <span class=
"sd"> * @package WoltLabSuite\Core\Acp\Page
</span>
2967 <span class=
"sd"> */
</span>
2968 <span class=
"k">class
</span> <span class=
"nc">PersonListPage
</span> <span class=
"k">extends
</span> <span class=
"nx">SortablePage
</span>
2969 <span class=
"p">{
</span>
2970 <span class=
"sd">/**
</span>
2971 <span class=
"sd"> * @inheritDoc
</span>
2972 <span class=
"sd"> */
</span>
2973 <span class=
"k">public
</span> <span class=
"nv">$activeMenuItem
</span> <span class=
"o">=
</span> <span class=
"s1">'wcf.acp.menu.link.person.list
'</span><span class=
"p">;
</span>
2975 <span class=
"sd">/**
</span>
2976 <span class=
"sd"> * @inheritDoc
</span>
2977 <span class=
"sd"> */
</span>
2978 <span class=
"k">public
</span> <span class=
"nv">$neededPermissions
</span> <span class=
"o">=
</span> <span class=
"p">[
</span><span class=
"s1">'admin.content.canManagePeople
'</span><span class=
"p">];
</span>
2980 <span class=
"sd">/**
</span>
2981 <span class=
"sd"> * @inheritDoc
</span>
2982 <span class=
"sd"> */
</span>
2983 <span class=
"k">public
</span> <span class=
"nv">$objectListClassName
</span> <span class=
"o">=
</span> <span class=
"nx">PersonList
</span><span class=
"o">::
</span><span class=
"na">class
</span><span class=
"p">;
</span>
2985 <span class=
"sd">/**
</span>
2986 <span class=
"sd"> * @inheritDoc
</span>
2987 <span class=
"sd"> */
</span>
2988 <span class=
"k">public
</span> <span class=
"nv">$validSortFields
</span> <span class=
"o">=
</span> <span class=
"p">[
</span><span class=
"s1">'personID
'</span><span class=
"p">,
</span> <span class=
"s1">'firstName
'</span><span class=
"p">,
</span> <span class=
"s1">'lastName
'</span><span class=
"p">];
</span>
2989 <span class=
"p">}
</span>
2994 <p>As WoltLab Suite Core already provides a powerful default implementation of a sortable page, our work here is minimal:
</p>
2996 <li>We need to set the active ACP menu item via the
<code>$activeMenuItem
</code>.
</li>
2997 <li><code>$neededPermissions
</code> contains a list of permissions of which the user needs to have at least one in order to see the person list.
2998 We use the same permission for both the menu item and the page.
</li>
2999 <li>The database object list class whose name is provided via
<code>$objectListClassName
</code> and that handles fetching the people from database is the
<code>PersonList
</code> class, which we have already created.
</li>
3000 <li>To validate the sort field passed with the request, we set
<code>$validSortFields
</code> to the available database table columns.
</li>
3002 <h4 id=
"personlisttpl"><code>personList.tpl
</code><a class=
"headerlink" href=
"#personlisttpl" title=
"Permanent link">#
</a></h4>
3003 <div class=
"titledCodeBox">
3004 <div class=
"codeBoxTitle"><code>acptemplates/personList.tpl
</code></div>
3005 <table class=
"highlighttable"><tr><td class=
"linenos"><div class=
"linenodiv"><pre><span></span><span class=
"normal"> 1</span>
3006 <span class=
"normal"> 2</span>
3007 <span class=
"normal"> 3</span>
3008 <span class=
"normal"> 4</span>
3009 <span class=
"normal"> 5</span>
3010 <span class=
"normal"> 6</span>
3011 <span class=
"normal"> 7</span>
3012 <span class=
"normal"> 8</span>
3013 <span class=
"normal"> 9</span>
3014 <span class=
"normal">10</span>
3015 <span class=
"normal">11</span>
3016 <span class=
"normal">12</span>
3017 <span class=
"normal">13</span>
3018 <span class=
"normal">14</span>
3019 <span class=
"normal">15</span>
3020 <span class=
"normal">16</span>
3021 <span class=
"normal">17</span>
3022 <span class=
"normal">18</span>
3023 <span class=
"normal">19</span>
3024 <span class=
"normal">20</span>
3025 <span class=
"normal">21</span>
3026 <span class=
"normal">22</span>
3027 <span class=
"normal">23</span>
3028 <span class=
"normal">24</span>
3029 <span class=
"normal">25</span>
3030 <span class=
"normal">26</span>
3031 <span class=
"normal">27</span>
3032 <span class=
"normal">28</span>
3033 <span class=
"normal">29</span>
3034 <span class=
"normal">30</span>
3035 <span class=
"normal">31</span>
3036 <span class=
"normal">32</span>
3037 <span class=
"normal">33</span>
3038 <span class=
"normal">34</span>
3039 <span class=
"normal">35</span>
3040 <span class=
"normal">36</span>
3041 <span class=
"normal">37</span>
3042 <span class=
"normal">38</span>
3043 <span class=
"normal">39</span>
3044 <span class=
"normal">40</span>
3045 <span class=
"normal">41</span>
3046 <span class=
"normal">42</span>
3047 <span class=
"normal">43</span>
3048 <span class=
"normal">44</span>
3049 <span class=
"normal">45</span>
3050 <span class=
"normal">46</span>
3051 <span class=
"normal">47</span>
3052 <span class=
"normal">48</span>
3053 <span class=
"normal">49</span>
3054 <span class=
"normal">50</span>
3055 <span class=
"normal">51</span>
3056 <span class=
"normal">52</span>
3057 <span class=
"normal">53</span>
3058 <span class=
"normal">54</span>
3059 <span class=
"normal">55</span>
3060 <span class=
"normal">56</span>
3061 <span class=
"normal">57</span>
3062 <span class=
"normal">58</span>
3063 <span class=
"normal">59</span>
3064 <span class=
"normal">60</span>
3065 <span class=
"normal">61</span>
3066 <span class=
"normal">62</span>
3067 <span class=
"normal">63</span>
3068 <span class=
"normal">64</span>
3069 <span class=
"normal">65</span>
3070 <span class=
"normal">66</span>
3071 <span class=
"normal">67</span>
3072 <span class=
"normal">68</span>
3073 <span class=
"normal">69</span>
3074 <span class=
"normal">70</span>
3075 <span class=
"normal">71</span>
3076 <span class=
"normal">72</span>
3077 <span class=
"normal">73</span>
3078 <span class=
"normal">74</span>
3079 <span class=
"normal">75</span></pre></div></td><td class=
"code"><div class=
"highlight"><pre><span></span><code><span class=
"cp">{
</span><span class=
"nf">include
</span> <span class=
"na">file
</span><span class=
"o">=
</span><span class=
"s1">'header
'</span> <span class=
"na">pageTitle
</span><span class=
"o">=
</span><span class=
"s1">'wcf.acp.person.list
'</span><span class=
"cp">}
</span><span class=
"x"></span>
3081 <span class=
"x"><header class=
"contentHeader
"></span>
3082 <span class=
"x"> <div class=
"contentHeaderTitle
"></span>
3083 <span class=
"x"> <h1 class=
"contentTitle
"></span><span class=
"cp">{
</span><span class=
"nf">lang
</span><span class=
"cp">}
</span><span class=
"x">wcf.acp.person.list
</span><span class=
"cp">{
</span><span class=
"nf">/lang
</span><span class=
"cp">}
</span><span class=
"x"></h1
></span>
3084 <span class=
"x"> </div
></span>
3086 <span class=
"x"> <nav class=
"contentHeaderNavigation
"></span>
3087 <span class=
"x"> <ul
></span>
3088 <span class=
"x"> <li
><a href=
"</span><span class=
"cp">{
</span><span class=
"nf">link
</span> <span class=
"na">controller
</span><span class=
"o">=
</span><span class=
"s1">'PersonAdd
'</span><span class=
"cp">}{
</span><span class=
"nf">/link
</span><span class=
"cp">}
</span><span class=
"x">" class=
"button
"><span class=
"icon icon16 fa-plus
"></span
> <span
></span><span class=
"cp">{
</span><span class=
"nf">lang
</span><span class=
"cp">}
</span><span class=
"x">wcf.acp.menu.link.person.add
</span><span class=
"cp">{
</span><span class=
"nf">/lang
</span><span class=
"cp">}
</span><span class=
"x"></span
></a
></li
></span>
3090 <span class=
"x"> </span><span class=
"cp">{
</span><span class=
"nf">event
</span> <span class=
"na">name
</span><span class=
"o">=
</span><span class=
"s1">'contentHeaderNavigation
'</span><span class=
"cp">}
</span><span class=
"x"></span>
3091 <span class=
"x"> </ul
></span>
3092 <span class=
"x"> </nav
></span>
3093 <span class=
"x"></header
></span>
3095 <span class=
"cp">{
</span><span class=
"nf">hascontent
</span><span class=
"cp">}
</span><span class=
"x"></span>
3096 <span class=
"x"> <div class=
"paginationTop
"></span>
3097 <span class=
"x"> </span><span class=
"cp">{
</span><span class=
"nf">content
</span><span class=
"cp">}{
</span><span class=
"nf">pages
</span> <span class=
"na">print
</span><span class=
"o">=
</span><span class=
"kc">true
</span> <span class=
"na">assign
</span><span class=
"o">=
</span><span class=
"na">pagesLinks
</span> <span class=
"na">controller
</span><span class=
"o">=
</span><span class=
"s2">"PersonList
"</span> <span class=
"na">link
</span><span class=
"o">=
</span><span class=
"s2">"pageNo=%d
&sortField=$sortField
&sortOrder=$sortOrder
"</span><span class=
"cp">}{
</span><span class=
"nf">/content
</span><span class=
"cp">}
</span><span class=
"x"></span>
3098 <span class=
"x"> </div
></span>
3099 <span class=
"cp">{
</span><span class=
"nf">/hascontent
</span><span class=
"cp">}
</span><span class=
"x"></span>
3101 <span class=
"cp">{
</span><span class=
"nf">if
</span> <span class=
"nv">$objects
</span><span class=
"o">|
</span><span class=
"na">count
</span><span class=
"cp">}
</span><span class=
"x"></span>
3102 <span class=
"x"> <div class=
"section tabularBox
"></span>
3103 <span class=
"x"> <table class=
"table jsObjectActionContainer
" data-object-action-class-name=
"wcf\data\person\PersonAction
"></span>
3104 <span class=
"x"> <thead
></span>
3105 <span class=
"x"> <tr
></span>
3106 <span class=
"x"> <th class=
"columnID columnPersonID
</span><span class=
"cp">{
</span><span class=
"nf">if
</span> <span class=
"nv">$sortField
</span> <span class=
"o">==
</span> <span class=
"s1">'personID
'</span><span class=
"cp">}
</span><span class=
"x"> active
</span><span class=
"cp">{
</span><span class=
"o">@
</span><span class=
"nv">$sortOrder
</span><span class=
"cp">}{
</span><span class=
"nf">/if
</span><span class=
"cp">}
</span><span class=
"x">" colspan=
"2"><a href=
"</span><span class=
"cp">{
</span><span class=
"nf">link
</span> <span class=
"na">controller
</span><span class=
"o">=
</span><span class=
"s1">'PersonList
'</span><span class=
"cp">}
</span><span class=
"x">pageNo=
</span><span class=
"cp">{
</span><span class=
"o">@
</span><span class=
"nv">$pageNo
</span><span class=
"cp">}
</span><span class=
"x">&sortField=personID
&sortOrder=
</span><span class=
"cp">{
</span><span class=
"nf">if
</span> <span class=
"nv">$sortField
</span> <span class=
"o">==
</span> <span class=
"s1">'personID
'</span> <span class=
"o">&&</span> <span class=
"nv">$sortOrder
</span> <span class=
"o">==
</span> <span class=
"s1">'ASC
'</span><span class=
"cp">}
</span><span class=
"x">DESC
</span><span class=
"cp">{
</span><span class=
"nf">else
</span><span class=
"cp">}
</span><span class=
"x">ASC
</span><span class=
"cp">{
</span><span class=
"nf">/if
</span><span class=
"cp">}{
</span><span class=
"nf">/link
</span><span class=
"cp">}
</span><span class=
"x">"></span><span class=
"cp">{
</span><span class=
"nf">lang
</span><span class=
"cp">}
</span><span class=
"x">wcf.global.objectID
</span><span class=
"cp">{
</span><span class=
"nf">/lang
</span><span class=
"cp">}
</span><span class=
"x"></a
></th
></span>
3107 <span class=
"x"> <th class=
"columnTitle columnFirstName
</span><span class=
"cp">{
</span><span class=
"nf">if
</span> <span class=
"nv">$sortField
</span> <span class=
"o">==
</span> <span class=
"s1">'firstName
'</span><span class=
"cp">}
</span><span class=
"x"> active
</span><span class=
"cp">{
</span><span class=
"o">@
</span><span class=
"nv">$sortOrder
</span><span class=
"cp">}{
</span><span class=
"nf">/if
</span><span class=
"cp">}
</span><span class=
"x">"><a href=
"</span><span class=
"cp">{
</span><span class=
"nf">link
</span> <span class=
"na">controller
</span><span class=
"o">=
</span><span class=
"s1">'PersonList
'</span><span class=
"cp">}
</span><span class=
"x">pageNo=
</span><span class=
"cp">{
</span><span class=
"o">@
</span><span class=
"nv">$pageNo
</span><span class=
"cp">}
</span><span class=
"x">&sortField=firstName
&sortOrder=
</span><span class=
"cp">{
</span><span class=
"nf">if
</span> <span class=
"nv">$sortField
</span> <span class=
"o">==
</span> <span class=
"s1">'firstName
'</span> <span class=
"o">&&</span> <span class=
"nv">$sortOrder
</span> <span class=
"o">==
</span> <span class=
"s1">'ASC
'</span><span class=
"cp">}
</span><span class=
"x">DESC
</span><span class=
"cp">{
</span><span class=
"nf">else
</span><span class=
"cp">}
</span><span class=
"x">ASC
</span><span class=
"cp">{
</span><span class=
"nf">/if
</span><span class=
"cp">}{
</span><span class=
"nf">/link
</span><span class=
"cp">}
</span><span class=
"x">"></span><span class=
"cp">{
</span><span class=
"nf">lang
</span><span class=
"cp">}
</span><span class=
"x">wcf.person.firstName
</span><span class=
"cp">{
</span><span class=
"nf">/lang
</span><span class=
"cp">}
</span><span class=
"x"></a
></th
></span>
3108 <span class=
"x"> <th class=
"columnTitle columnLastName
</span><span class=
"cp">{
</span><span class=
"nf">if
</span> <span class=
"nv">$sortField
</span> <span class=
"o">==
</span> <span class=
"s1">'lastName
'</span><span class=
"cp">}
</span><span class=
"x"> active
</span><span class=
"cp">{
</span><span class=
"o">@
</span><span class=
"nv">$sortOrder
</span><span class=
"cp">}{
</span><span class=
"nf">/if
</span><span class=
"cp">}
</span><span class=
"x">"><a href=
"</span><span class=
"cp">{
</span><span class=
"nf">link
</span> <span class=
"na">controller
</span><span class=
"o">=
</span><span class=
"s1">'PersonList
'</span><span class=
"cp">}
</span><span class=
"x">pageNo=
</span><span class=
"cp">{
</span><span class=
"o">@
</span><span class=
"nv">$pageNo
</span><span class=
"cp">}
</span><span class=
"x">&sortField=lastName
&sortOrder=
</span><span class=
"cp">{
</span><span class=
"nf">if
</span> <span class=
"nv">$sortField
</span> <span class=
"o">==
</span> <span class=
"s1">'lastName
'</span> <span class=
"o">&&</span> <span class=
"nv">$sortOrder
</span> <span class=
"o">==
</span> <span class=
"s1">'ASC
'</span><span class=
"cp">}
</span><span class=
"x">DESC
</span><span class=
"cp">{
</span><span class=
"nf">else
</span><span class=
"cp">}
</span><span class=
"x">ASC
</span><span class=
"cp">{
</span><span class=
"nf">/if
</span><span class=
"cp">}{
</span><span class=
"nf">/link
</span><span class=
"cp">}
</span><span class=
"x">"></span><span class=
"cp">{
</span><span class=
"nf">lang
</span><span class=
"cp">}
</span><span class=
"x">wcf.person.lastName
</span><span class=
"cp">{
</span><span class=
"nf">/lang
</span><span class=
"cp">}
</span><span class=
"x"></a
></th
></span>
3110 <span class=
"x"> </span><span class=
"cp">{
</span><span class=
"nf">event
</span> <span class=
"na">name
</span><span class=
"o">=
</span><span class=
"s1">'columnHeads
'</span><span class=
"cp">}
</span><span class=
"x"></span>
3111 <span class=
"x"> </tr
></span>
3112 <span class=
"x"> </thead
></span>
3114 <span class=
"x"> <tbody class=
"jsReloadPageWhenEmpty
"></span>
3115 <span class=
"x"> </span><span class=
"cp">{
</span><span class=
"nf">foreach
</span> <span class=
"na">from
</span><span class=
"o">=
</span><span class=
"nv">$objects
</span> <span class=
"na">item
</span><span class=
"o">=
</span><span class=
"na">person
</span><span class=
"cp">}
</span><span class=
"x"></span>
3116 <span class=
"x"> <tr class=
"jsObjectActionObject
" data-object-id=
"</span><span class=
"cp">{
</span><span class=
"o">@
</span><span class=
"nv">$person
</span><span class=
"o">-
></span><span class=
"na">getObjectID
</span><span class=
"o">()
</span><span class=
"cp">}
</span><span class=
"x">"></span>
3117 <span class=
"x"> <td class=
"columnIcon
"></span>
3118 <span class=
"x"> <a href=
"</span><span class=
"cp">{
</span><span class=
"nf">link
</span> <span class=
"na">controller
</span><span class=
"o">=
</span><span class=
"s1">'PersonEdit
'</span> <span class=
"na">object
</span><span class=
"o">=
</span><span class=
"nv">$person
</span><span class=
"cp">}{
</span><span class=
"nf">/link
</span><span class=
"cp">}
</span><span class=
"x">" title=
"</span><span class=
"cp">{
</span><span class=
"nf">lang
</span><span class=
"cp">}
</span><span class=
"x">wcf.global.button.edit
</span><span class=
"cp">{
</span><span class=
"nf">/lang
</span><span class=
"cp">}
</span><span class=
"x">" class=
"jsTooltip
"><span class=
"icon icon16 fa-pencil
"></span
></a
></span>
3119 <span class=
"x"> </span><span class=
"cp">{
</span><span class=
"nf">objectAction
</span> <span class=
"na">action
</span><span class=
"o">=
</span><span class=
"s2">"delete
"</span> <span class=
"na">objectTitle
</span><span class=
"o">=
</span><span class=
"nv">$person
</span><span class=
"o">-
></span><span class=
"na">getTitle
</span><span class=
"o">()
</span><span class=
"cp">}
</span><span class=
"x"></span>
3121 <span class=
"x"> </span><span class=
"cp">{
</span><span class=
"nf">event
</span> <span class=
"na">name
</span><span class=
"o">=
</span><span class=
"s1">'rowButtons
'</span><span class=
"cp">}
</span><span class=
"x"></span>
3122 <span class=
"x"> </td
></span>
3123 <span class=
"x"> <td class=
"columnID
"></span><span class=
"cp">{
</span><span class=
"err">#
</span><span class=
"nv">$person
</span><span class=
"o">-
></span><span class=
"na">personID
</span><span class=
"cp">}
</span><span class=
"x"></td
></span>
3124 <span class=
"x"> <td class=
"columnTitle columnFirstName
"><a href=
"</span><span class=
"cp">{
</span><span class=
"nf">link
</span> <span class=
"na">controller
</span><span class=
"o">=
</span><span class=
"s1">'PersonEdit
'</span> <span class=
"na">object
</span><span class=
"o">=
</span><span class=
"nv">$person
</span><span class=
"cp">}{
</span><span class=
"nf">/link
</span><span class=
"cp">}
</span><span class=
"x">"></span><span class=
"cp">{
</span><span class=
"nv">$person
</span><span class=
"o">-
></span><span class=
"na">firstName
</span><span class=
"cp">}
</span><span class=
"x"></a
></td
></span>
3125 <span class=
"x"> <td class=
"columnTitle columnLastName
"><a href=
"</span><span class=
"cp">{
</span><span class=
"nf">link
</span> <span class=
"na">controller
</span><span class=
"o">=
</span><span class=
"s1">'PersonEdit
'</span> <span class=
"na">object
</span><span class=
"o">=
</span><span class=
"nv">$person
</span><span class=
"cp">}{
</span><span class=
"nf">/link
</span><span class=
"cp">}
</span><span class=
"x">"></span><span class=
"cp">{
</span><span class=
"nv">$person
</span><span class=
"o">-
></span><span class=
"na">lastName
</span><span class=
"cp">}
</span><span class=
"x"></a
></td
></span>
3127 <span class=
"x"> </span><span class=
"cp">{
</span><span class=
"nf">event
</span> <span class=
"na">name
</span><span class=
"o">=
</span><span class=
"s1">'columns
'</span><span class=
"cp">}
</span><span class=
"x"></span>
3128 <span class=
"x"> </tr
></span>
3129 <span class=
"x"> </span><span class=
"cp">{
</span><span class=
"nf">/foreach
</span><span class=
"cp">}
</span><span class=
"x"></span>
3130 <span class=
"x"> </tbody
></span>
3131 <span class=
"x"> </table
></span>
3132 <span class=
"x"> </div
></span>
3134 <span class=
"x"> <footer class=
"contentFooter
"></span>
3135 <span class=
"x"> </span><span class=
"cp">{
</span><span class=
"nf">hascontent
</span><span class=
"cp">}
</span><span class=
"x"></span>
3136 <span class=
"x"> <div class=
"paginationBottom
"></span>
3137 <span class=
"x"> </span><span class=
"cp">{
</span><span class=
"nf">content
</span><span class=
"cp">}{
</span><span class=
"o">@
</span><span class=
"nv">$pagesLinks
</span><span class=
"cp">}{
</span><span class=
"nf">/content
</span><span class=
"cp">}
</span><span class=
"x"></span>
3138 <span class=
"x"> </div
></span>
3139 <span class=
"x"> </span><span class=
"cp">{
</span><span class=
"nf">/hascontent
</span><span class=
"cp">}
</span><span class=
"x"></span>
3141 <span class=
"x"> <nav class=
"contentFooterNavigation
"></span>
3142 <span class=
"x"> <ul
></span>
3143 <span class=
"x"> <li
><a href=
"</span><span class=
"cp">{
</span><span class=
"nf">link
</span> <span class=
"na">controller
</span><span class=
"o">=
</span><span class=
"s1">'PersonAdd
'</span><span class=
"cp">}{
</span><span class=
"nf">/link
</span><span class=
"cp">}
</span><span class=
"x">" class=
"button
"><span class=
"icon icon16 fa-plus
"></span
> <span
></span><span class=
"cp">{
</span><span class=
"nf">lang
</span><span class=
"cp">}
</span><span class=
"x">wcf.acp.menu.link.person.add
</span><span class=
"cp">{
</span><span class=
"nf">/lang
</span><span class=
"cp">}
</span><span class=
"x"></span
></a
></li
></span>
3145 <span class=
"x"> </span><span class=
"cp">{
</span><span class=
"nf">event
</span> <span class=
"na">name
</span><span class=
"o">=
</span><span class=
"s1">'contentFooterNavigation
'</span><span class=
"cp">}
</span><span class=
"x"></span>
3146 <span class=
"x"> </ul
></span>
3147 <span class=
"x"> </nav
></span>
3148 <span class=
"x"> </footer
></span>
3149 <span class=
"cp">{
</span><span class=
"nf">else
</span><span class=
"cp">}
</span><span class=
"x"></span>
3150 <span class=
"x"> <p class=
"info
"></span><span class=
"cp">{
</span><span class=
"nf">lang
</span><span class=
"cp">}
</span><span class=
"x">wcf.global.noItems
</span><span class=
"cp">{
</span><span class=
"nf">/lang
</span><span class=
"cp">}
</span><span class=
"x"></p
></span>
3151 <span class=
"cp">{
</span><span class=
"nf">/if
</span><span class=
"cp">}
</span><span class=
"x"></span>
3153 <span class=
"cp">{
</span><span class=
"nf">include
</span> <span class=
"na">file
</span><span class=
"o">=
</span><span class=
"s1">'footer
'</span><span class=
"cp">}
</span><span class=
"x"></span>
3158 <p>We will go piece by piece through the template code:
</p>
3160 <li>We include the
<code>header
</code> template and set the page title
<code>wcf.acp.person.list
</code>.
3161 You have to include this template for every page!
</li>
3162 <li>We set the content header and additional provide a button to create a new person in the content header navigation.
</li>
3163 <li>As not all people are listed on the same page if many people have been created, we need a pagination for which we use the
<code>pages
</code> template plugin.
3164 The
<code>{hascontent}{content}{/content}{/hascontent}
</code> construct ensures the
<code>.paginationTop
</code> element is only shown if the
<code>pages
</code> template plugin has a return value, thus if a pagination is necessary.
</li>
3165 <li>Now comes the main part of the page, the list of the people, which will only be displayed if any people exist.
3166 Otherwise, an info box is displayed using the generic
<code>wcf.global.noItems
</code> language item.
3167 The
<code>$objects
</code> template variable is automatically assigned by
<code>wcf\page\MultipleLinkPage
</code> and contains the
<code>PersonList
</code> object used to read the people from database.
3168 The table itself consists of a
<code>thead
</code> and a
<code>tbody
</code> element and is extendable with more columns using the template events
<code>columnHeads
</code> and
<code>columns
</code>.
3169 In general, every table should provide these events.
3170 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
<code>rowButtons
</code>) and that the second column contains the ID of the person.
3171 The table can be sorted by clicking on the head of each column.
3172 The used variables
<code>$sortField
</code> and
<code>$sortOrder
</code> are automatically assigned to the template by
<code>SortablePage
</code>.
</li>
3173 <li>The
<code>.contentFooter
</code> element is only shown if people exist as it basically repeats the
<code>.contentHeaderNavigation
</code> and
<code>.paginationTop
</code> element.
</li>
3174 <li>The delete button for each person shown in the
<code>.columnIcon
</code> element relies on the global
<a href=
"../../../migration/wsc53/javascript/#wcfactiondelete-and-wcfactiontoggle"><code>WoltLabSuite/Core/Ui/Object/Action
</code></a> module which only requires the
<code>jsObjectActionContainer
</code> CSS class in combination with the
<code>data-object-action-class-name
</code> attribute for the
<code>table
</code> element, the
<code>jsObjectActionObject
</code> CSS class for each person's
<code>tr
</code> element in combination with the
<code>data-object-id
</code> attribute, and lastly the delete button itself, which is created with the
<a href=
"../../../view/template-plugins/#view/template-plugins/#54-objectaction"><code>objectAction
</code> template plugin
</a>.
</li>
3175 <li>The
<a href=
"../../../migration/wsc53/javascript/#wcftableemptytablehandler"><code>.jsReloadPageWhenEmpty
</code> CSS class
</a> on the
<code>tbody
</code> element ensures that once all persons on the page have been deleted, the page is reloaded.
</li>
3176 <li>Lastly, the
<code>footer
</code> template is included that terminates the page.
3177 You also have to include this template for every page!
</li>
3179 <p>Now, we have finished the page to manage the people so that we can move on to the forms with which we actually create and edit the people.
</p>
3180 <h3 id=
"person-add-form">Person Add Form
<a class=
"headerlink" href=
"#person-add-form" title=
"Permanent link">#
</a></h3>
3181 <p>Like the person list, the form to add new people requires a controller class and a template.
</p>
3182 <h4 id=
"personaddform"><code>PersonAddForm
</code><a class=
"headerlink" href=
"#personaddform" title=
"Permanent link">#
</a></h4>
3183 <div class=
"titledCodeBox">
3184 <div class=
"codeBoxTitle"><code>files/lib/acp/form/PersonAddForm.class.php
</code></div>
3185 <table class=
"highlighttable"><tr><td class=
"linenos"><div class=
"linenodiv"><pre><span></span><span class=
"normal"> 1</span>
3186 <span class=
"normal"> 2</span>
3187 <span class=
"normal"> 3</span>
3188 <span class=
"normal"> 4</span>
3189 <span class=
"normal"> 5</span>
3190 <span class=
"normal"> 6</span>
3191 <span class=
"normal"> 7</span>
3192 <span class=
"normal"> 8</span>
3193 <span class=
"normal"> 9</span>
3194 <span class=
"normal">10</span>
3195 <span class=
"normal">11</span>
3196 <span class=
"normal">12</span>
3197 <span class=
"normal">13</span>
3198 <span class=
"normal">14</span>
3199 <span class=
"normal">15</span>
3200 <span class=
"normal">16</span>
3201 <span class=
"normal">17</span>
3202 <span class=
"normal">18</span>
3203 <span class=
"normal">19</span>
3204 <span class=
"normal">20</span>
3205 <span class=
"normal">21</span>
3206 <span class=
"normal">22</span>
3207 <span class=
"normal">23</span>
3208 <span class=
"normal">24</span>
3209 <span class=
"normal">25</span>
3210 <span class=
"normal">26</span>
3211 <span class=
"normal">27</span>
3212 <span class=
"normal">28</span>
3213 <span class=
"normal">29</span>
3214 <span class=
"normal">30</span>
3215 <span class=
"normal">31</span>
3216 <span class=
"normal">32</span>
3217 <span class=
"normal">33</span>
3218 <span class=
"normal">34</span>
3219 <span class=
"normal">35</span>
3220 <span class=
"normal">36</span>
3221 <span class=
"normal">37</span>
3222 <span class=
"normal">38</span>
3223 <span class=
"normal">39</span>
3224 <span class=
"normal">40</span>
3225 <span class=
"normal">41</span>
3226 <span class=
"normal">42</span>
3227 <span class=
"normal">43</span>
3228 <span class=
"normal">44</span>
3229 <span class=
"normal">45</span>
3230 <span class=
"normal">46</span>
3231 <span class=
"normal">47</span>
3232 <span class=
"normal">48</span>
3233 <span class=
"normal">49</span>
3234 <span class=
"normal">50</span>
3235 <span class=
"normal">51</span>
3236 <span class=
"normal">52</span>
3237 <span class=
"normal">53</span>
3238 <span class=
"normal">54</span>
3239 <span class=
"normal">55</span>
3240 <span class=
"normal">56</span>
3241 <span class=
"normal">57</span>
3242 <span class=
"normal">58</span>
3243 <span class=
"normal">59</span>
3244 <span class=
"normal">60</span>
3245 <span class=
"normal">61</span>
3246 <span class=
"normal">62</span>
3247 <span class=
"normal">63</span>
3248 <span class=
"normal">64</span>
3249 <span class=
"normal">65</span>
3250 <span class=
"normal">66</span>
3251 <span class=
"normal">67</span>
3252 <span class=
"normal">68</span>
3253 <span class=
"normal">69</span></pre></div></td><td class=
"code"><div class=
"highlight"><pre><span></span><code><span class=
"o"><?
</span><span class=
"nx">php
</span>
3255 <span class=
"k">namespace
</span> <span class=
"nx">wcf\acp\form
</span><span class=
"p">;
</span>
3257 <span class=
"k">use
</span> <span class=
"nx">wcf\data\person\PersonAction
</span><span class=
"p">;
</span>
3258 <span class=
"k">use
</span> <span class=
"nx">wcf\form\AbstractFormBuilderForm
</span><span class=
"p">;
</span>
3259 <span class=
"k">use
</span> <span class=
"nx">wcf\system\form\builder\container\FormContainer
</span><span class=
"p">;
</span>
3260 <span class=
"k">use
</span> <span class=
"nx">wcf\system\form\builder\field\TextFormField
</span><span class=
"p">;
</span>
3262 <span class=
"sd">/**
</span>
3263 <span class=
"sd"> * Shows the form to create a new person.
</span>
3264 <span class=
"sd"> *
</span>
3265 <span class=
"sd"> * @author Matthias Schmidt
</span>
3266 <span class=
"sd"> * @copyright
2001-
2021 WoltLab GmbH
</span>
3267 <span class=
"sd"> * @license GNU Lesser General Public License
<http://opensource.org/licenses/lgpl-license.php
></span>
3268 <span class=
"sd"> * @package WoltLabSuite\Core\Acp\Form
</span>
3269 <span class=
"sd"> */
</span>
3270 <span class=
"k">class
</span> <span class=
"nc">PersonAddForm
</span> <span class=
"k">extends
</span> <span class=
"nx">AbstractFormBuilderForm
</span>
3271 <span class=
"p">{
</span>
3272 <span class=
"sd">/**
</span>
3273 <span class=
"sd"> * @inheritDoc
</span>
3274 <span class=
"sd"> */
</span>
3275 <span class=
"k">public
</span> <span class=
"nv">$activeMenuItem
</span> <span class=
"o">=
</span> <span class=
"s1">'wcf.acp.menu.link.person.add
'</span><span class=
"p">;
</span>
3277 <span class=
"sd">/**
</span>
3278 <span class=
"sd"> * @inheritDoc
</span>
3279 <span class=
"sd"> */
</span>
3280 <span class=
"k">public
</span> <span class=
"nv">$formAction
</span> <span class=
"o">=
</span> <span class=
"s1">'create
'</span><span class=
"p">;
</span>
3282 <span class=
"sd">/**
</span>
3283 <span class=
"sd"> * @inheritDoc
</span>
3284 <span class=
"sd"> */
</span>
3285 <span class=
"k">public
</span> <span class=
"nv">$neededPermissions
</span> <span class=
"o">=
</span> <span class=
"p">[
</span><span class=
"s1">'admin.content.canManagePeople
'</span><span class=
"p">];
</span>
3287 <span class=
"sd">/**
</span>
3288 <span class=
"sd"> * @inheritDoc
</span>
3289 <span class=
"sd"> */
</span>
3290 <span class=
"k">public
</span> <span class=
"nv">$objectActionClass
</span> <span class=
"o">=
</span> <span class=
"nx">PersonAction
</span><span class=
"o">::
</span><span class=
"na">class
</span><span class=
"p">;
</span>
3292 <span class=
"sd">/**
</span>
3293 <span class=
"sd"> * @inheritDoc
</span>
3294 <span class=
"sd"> */
</span>
3295 <span class=
"k">public
</span> <span class=
"nv">$objectEditLinkController
</span> <span class=
"o">=
</span> <span class=
"nx">PersonEditForm
</span><span class=
"o">::
</span><span class=
"na">class
</span><span class=
"p">;
</span>
3297 <span class=
"sd">/**
</span>
3298 <span class=
"sd"> * @inheritDoc
</span>
3299 <span class=
"sd"> */
</span>
3300 <span class=
"k">public
</span> <span class=
"k">function
</span> <span class=
"nf">createForm
</span><span class=
"p">()
</span>
3301 <span class=
"p">{
</span>
3302 <span class=
"k">parent
</span><span class=
"o">::
</span><span class=
"na">createForm
</span><span class=
"p">();
</span>
3304 <span class=
"nv">$this
</span><span class=
"o">-
></span><span class=
"na">form
</span><span class=
"o">-
></span><span class=
"na">appendChild
</span><span class=
"p">(
</span>
3305 <span class=
"nx">FormContainer
</span><span class=
"o">::
</span><span class=
"na">create
</span><span class=
"p">(
</span><span class=
"s1">'data
'</span><span class=
"p">)
</span>
3306 <span class=
"o">-
></span><span class=
"na">label
</span><span class=
"p">(
</span><span class=
"s1">'wcf.global.form.data
'</span><span class=
"p">)
</span>
3307 <span class=
"o">-
></span><span class=
"na">appendChildren
</span><span class=
"p">([
</span>
3308 <span class=
"nx">TextFormField
</span><span class=
"o">::
</span><span class=
"na">create
</span><span class=
"p">(
</span><span class=
"s1">'firstName
'</span><span class=
"p">)
</span>
3309 <span class=
"o">-
></span><span class=
"na">label
</span><span class=
"p">(
</span><span class=
"s1">'wcf.person.firstName
'</span><span class=
"p">)
</span>
3310 <span class=
"o">-
></span><span class=
"na">required
</span><span class=
"p">()
</span>
3311 <span class=
"o">-
></span><span class=
"na">autoFocus
</span><span class=
"p">()
</span>
3312 <span class=
"o">-
></span><span class=
"na">maximumLength
</span><span class=
"p">(
</span><span class=
"mi">255</span><span class=
"p">),
</span>
3314 <span class=
"nx">TextFormField
</span><span class=
"o">::
</span><span class=
"na">create
</span><span class=
"p">(
</span><span class=
"s1">'lastName
'</span><span class=
"p">)
</span>
3315 <span class=
"o">-
></span><span class=
"na">label
</span><span class=
"p">(
</span><span class=
"s1">'wcf.person.lastName
'</span><span class=
"p">)
</span>
3316 <span class=
"o">-
></span><span class=
"na">required
</span><span class=
"p">()
</span>
3317 <span class=
"o">-
></span><span class=
"na">maximumLength
</span><span class=
"p">(
</span><span class=
"mi">255</span><span class=
"p">),
</span>
3318 <span class=
"p">])
</span>
3319 <span class=
"p">);
</span>
3320 <span class=
"p">}
</span>
3321 <span class=
"p">}
</span>
3326 <p>The properties here consist of three types:
3327 the “housekeeping” properties
<code>$activeMenuItem
</code> and
<code>$neededPermissions
</code>, which fulfill the same roles as for
<code>PersonListPage
</code>, and the
<a href=
"../../../migration/wsc52/php/#addform"><code>$objectEditLinkController
</code> property
</a>, which is used to generate a link to edit the newly created person after submitting the form, and finally
<code>$formAction
</code> and
<code>$objectActionClass
</code> required by the
<a href=
"../../../php/api/form_builder/overview/">PHP form builder API
</a> used to generate the form.
</p>
3328 <p>Because of using form builder, we only have to set up the two form fields for entering the first and last name, respectively:
</p>
3330 <li>Each field is a simple single-line text field, thus we use
<a href=
"../../../php/api/form_builder/form_fields/#textformfield"><code>TextFormField
</code></a>.
</li>
3331 <li>The parameter of the
<code>create()
</code> method expects the id of the field/name of the database object property, which is
<code>firstName
</code> and
<code>lastName
</code>, respectively, here.
</li>
3332 <li>The language item of the label shown in the ouput above the input field is set via the
<code>label()
</code> method.
</li>
3333 <li>As both fields have to be filled out,
<code>required()
</code> is called, and the maximum length is set via
<code>maximumLength()
</code>.
</li>
3334 <li>Lastly, to make it easier to fill out the form more quickly, the first field is auto-focused by calling
<code>autoFocus()
</code>.
</li>
3336 <h4 id=
"personaddtpl"><code>personAdd.tpl
</code><a class=
"headerlink" href=
"#personaddtpl" title=
"Permanent link">#
</a></h4>
3337 <div class=
"titledCodeBox">
3338 <div class=
"codeBoxTitle"><code>acptemplates/personAdd.tpl
</code></div>
3339 <table class=
"highlighttable"><tr><td class=
"linenos"><div class=
"linenodiv"><pre><span></span><span class=
"normal"> 1</span>
3340 <span class=
"normal"> 2</span>
3341 <span class=
"normal"> 3</span>
3342 <span class=
"normal"> 4</span>
3343 <span class=
"normal"> 5</span>
3344 <span class=
"normal"> 6</span>
3345 <span class=
"normal"> 7</span>
3346 <span class=
"normal"> 8</span>
3347 <span class=
"normal"> 9</span>
3348 <span class=
"normal">10</span>
3349 <span class=
"normal">11</span>
3350 <span class=
"normal">12</span>
3351 <span class=
"normal">13</span>
3352 <span class=
"normal">14</span>
3353 <span class=
"normal">15</span>
3354 <span class=
"normal">16</span>
3355 <span class=
"normal">17</span>
3356 <span class=
"normal">18</span>
3357 <span class=
"normal">19</span></pre></div></td><td class=
"code"><div class=
"highlight"><pre><span></span><code><span class=
"cp">{
</span><span class=
"nf">include
</span> <span class=
"na">file
</span><span class=
"o">=
</span><span class=
"s1">'header
'</span> <span class=
"na">pageTitle
</span><span class=
"o">=
</span><span class=
"s1">'wcf.acp.person.
'</span><span class=
"o">|
</span><span class=
"na">concat
</span><span class=
"o">:
</span><span class=
"nv">$action
</span><span class=
"cp">}
</span><span class=
"x"></span>
3359 <span class=
"x"><header class=
"contentHeader
"></span>
3360 <span class=
"x"> <div class=
"contentHeaderTitle
"></span>
3361 <span class=
"x"> <h1 class=
"contentTitle
"></span><span class=
"cp">{
</span><span class=
"nf">lang
</span><span class=
"cp">}
</span><span class=
"x">wcf.acp.person.
</span><span class=
"cp">{
</span><span class=
"nv">$action
</span><span class=
"cp">}{
</span><span class=
"nf">/lang
</span><span class=
"cp">}
</span><span class=
"x"></h1
></span>
3362 <span class=
"x"> </div
></span>
3364 <span class=
"x"> <nav class=
"contentHeaderNavigation
"></span>
3365 <span class=
"x"> <ul
></span>
3366 <span class=
"x"> <li
><a href=
"</span><span class=
"cp">{
</span><span class=
"nf">link
</span> <span class=
"na">controller
</span><span class=
"o">=
</span><span class=
"s1">'PersonList
'</span><span class=
"cp">}{
</span><span class=
"nf">/link
</span><span class=
"cp">}
</span><span class=
"x">" class=
"button
"><span class=
"icon icon16 fa-list
"></span
> <span
></span><span class=
"cp">{
</span><span class=
"nf">lang
</span><span class=
"cp">}
</span><span class=
"x">wcf.acp.menu.link.person.list
</span><span class=
"cp">{
</span><span class=
"nf">/lang
</span><span class=
"cp">}
</span><span class=
"x"></span
></a
></li
></span>
3368 <span class=
"x"> </span><span class=
"cp">{
</span><span class=
"nf">event
</span> <span class=
"na">name
</span><span class=
"o">=
</span><span class=
"s1">'contentHeaderNavigation
'</span><span class=
"cp">}
</span><span class=
"x"></span>
3369 <span class=
"x"> </ul
></span>
3370 <span class=
"x"> </nav
></span>
3371 <span class=
"x"></header
></span>
3373 <span class=
"cp">{
</span><span class=
"o">@
</span><span class=
"nv">$form
</span><span class=
"o">-
></span><span class=
"na">getHtml
</span><span class=
"o">()
</span><span class=
"cp">}
</span><span class=
"x"></span>
3375 <span class=
"cp">{
</span><span class=
"nf">include
</span> <span class=
"na">file
</span><span class=
"o">=
</span><span class=
"s1">'footer
'</span><span class=
"cp">}
</span><span class=
"x"></span>
3380 <p>We will now only concentrate on the new parts compared to
<code>personList.tpl
</code>:
</p>
3382 <li>We use the
<code>$action
</code> variable to distinguish between the languages items used for adding a person and for creating a person.
</li>
3383 <li>Because of form builder, we only have to call
<code>{@$form-
>getHtml()}
</code> to generate all relevant output for the form.
</li>
3385 <h3 id=
"person-edit-form">Person Edit Form
<a class=
"headerlink" href=
"#person-edit-form" title=
"Permanent link">#
</a></h3>
3386 <p>As mentioned before, for the form to edit existing people, we only need a new controller as the template has already been implemented in a way that it handles both, adding and editing.
</p>
3387 <h4 id=
"personeditform"><code>PersonEditForm
</code><a class=
"headerlink" href=
"#personeditform" title=
"Permanent link">#
</a></h4>
3388 <div class=
"titledCodeBox">
3389 <div class=
"codeBoxTitle"><code>files/lib/acp/form/PersonEditForm.class.php
</code></div>
3390 <table class=
"highlighttable"><tr><td class=
"linenos"><div class=
"linenodiv"><pre><span></span><span class=
"normal"> 1</span>
3391 <span class=
"normal"> 2</span>
3392 <span class=
"normal"> 3</span>
3393 <span class=
"normal"> 4</span>
3394 <span class=
"normal"> 5</span>
3395 <span class=
"normal"> 6</span>
3396 <span class=
"normal"> 7</span>
3397 <span class=
"normal"> 8</span>
3398 <span class=
"normal"> 9</span>
3399 <span class=
"normal">10</span>
3400 <span class=
"normal">11</span>
3401 <span class=
"normal">12</span>
3402 <span class=
"normal">13</span>
3403 <span class=
"normal">14</span>
3404 <span class=
"normal">15</span>
3405 <span class=
"normal">16</span>
3406 <span class=
"normal">17</span>
3407 <span class=
"normal">18</span>
3408 <span class=
"normal">19</span>
3409 <span class=
"normal">20</span>
3410 <span class=
"normal">21</span>
3411 <span class=
"normal">22</span>
3412 <span class=
"normal">23</span>
3413 <span class=
"normal">24</span>
3414 <span class=
"normal">25</span>
3415 <span class=
"normal">26</span>
3416 <span class=
"normal">27</span>
3417 <span class=
"normal">28</span>
3418 <span class=
"normal">29</span>
3419 <span class=
"normal">30</span>
3420 <span class=
"normal">31</span>
3421 <span class=
"normal">32</span>
3422 <span class=
"normal">33</span>
3423 <span class=
"normal">34</span>
3424 <span class=
"normal">35</span>
3425 <span class=
"normal">36</span>
3426 <span class=
"normal">37</span>
3427 <span class=
"normal">38</span>
3428 <span class=
"normal">39</span>
3429 <span class=
"normal">40</span>
3430 <span class=
"normal">41</span>
3431 <span class=
"normal">42</span>
3432 <span class=
"normal">43</span></pre></div></td><td class=
"code"><div class=
"highlight"><pre><span></span><code><span class=
"o"><?
</span><span class=
"nx">php
</span>
3434 <span class=
"k">namespace
</span> <span class=
"nx">wcf\acp\form
</span><span class=
"p">;
</span>
3436 <span class=
"k">use
</span> <span class=
"nx">wcf\data\person\Person
</span><span class=
"p">;
</span>
3437 <span class=
"k">use
</span> <span class=
"nx">wcf\system\exception\IllegalLinkException
</span><span class=
"p">;
</span>
3439 <span class=
"sd">/**
</span>
3440 <span class=
"sd"> * Shows the form to edit an existing person.
</span>
3441 <span class=
"sd"> *
</span>
3442 <span class=
"sd"> * @author Matthias Schmidt
</span>
3443 <span class=
"sd"> * @copyright
2001-
2021 WoltLab GmbH
</span>
3444 <span class=
"sd"> * @license GNU Lesser General Public License
<http://opensource.org/licenses/lgpl-license.php
></span>
3445 <span class=
"sd"> * @package WoltLabSuite\Core\Acp\Form
</span>
3446 <span class=
"sd"> */
</span>
3447 <span class=
"k">class
</span> <span class=
"nc">PersonEditForm
</span> <span class=
"k">extends
</span> <span class=
"nx">PersonAddForm
</span>
3448 <span class=
"p">{
</span>
3449 <span class=
"sd">/**
</span>
3450 <span class=
"sd"> * @inheritDoc
</span>
3451 <span class=
"sd"> */
</span>
3452 <span class=
"k">public
</span> <span class=
"nv">$activeMenuItem
</span> <span class=
"o">=
</span> <span class=
"s1">'wcf.acp.menu.link.person
'</span><span class=
"p">;
</span>
3454 <span class=
"sd">/**
</span>
3455 <span class=
"sd"> * @inheritDoc
</span>
3456 <span class=
"sd"> */
</span>
3457 <span class=
"k">public
</span> <span class=
"nv">$formAction
</span> <span class=
"o">=
</span> <span class=
"s1">'update
'</span><span class=
"p">;
</span>
3459 <span class=
"sd">/**
</span>
3460 <span class=
"sd"> * @inheritDoc
</span>
3461 <span class=
"sd"> */
</span>
3462 <span class=
"k">public
</span> <span class=
"k">function
</span> <span class=
"nf">readParameters
</span><span class=
"p">()
</span>
3463 <span class=
"p">{
</span>
3464 <span class=
"k">parent
</span><span class=
"o">::
</span><span class=
"na">readParameters
</span><span class=
"p">();
</span>
3466 <span class=
"k">if
</span> <span class=
"p">(
</span><span class=
"nb">isset
</span><span class=
"p">(
</span><span class=
"nv">$_REQUEST
</span><span class=
"p">[
</span><span class=
"s1">'id
'</span><span class=
"p">]))
</span> <span class=
"p">{
</span>
3467 <span class=
"nv">$this
</span><span class=
"o">-
></span><span class=
"na">formObject
</span> <span class=
"o">=
</span> <span class=
"k">new
</span> <span class=
"nx">Person
</span><span class=
"p">(
</span><span class=
"nv">$_REQUEST
</span><span class=
"p">[
</span><span class=
"s1">'id
'</span><span class=
"p">]);
</span>
3469 <span class=
"k">if
</span> <span class=
"p">(
</span><span class=
"o">!
</span><span class=
"nv">$this
</span><span class=
"o">-
></span><span class=
"na">formObject
</span><span class=
"o">-
></span><span class=
"na">getObjectID
</span><span class=
"p">())
</span> <span class=
"p">{
</span>
3470 <span class=
"k">throw
</span> <span class=
"k">new
</span> <span class=
"nx">IllegalLinkException
</span><span class=
"p">();
</span>
3471 <span class=
"p">}
</span>
3472 <span class=
"p">}
</span>
3473 <span class=
"p">}
</span>
3474 <span class=
"p">}
</span>
3479 <p>In general, edit forms extend the associated add form so that the code to read and to validate the input data is simply inherited.
</p>
3480 <p>After setting a different active menu item, we have to change the value of
<code>$formAction
</code> because this form, in contrast to
<code>PersonAddForm
</code>, does not create but update existing persons.
</p>
3481 <p>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
<code>readParameters()
</code>.
</p>
3482 <h2 id=
"frontend">Frontend
<a class=
"headerlink" href=
"#frontend" title=
"Permanent link">#
</a></h2>
3483 <p>For the front end, that means the part with which the visitors of a website interact, we want to implement a simple sortable page that lists the people.
3484 This page should also be directly linked in the main menu.
</p>
3485 <h3 id=
"pagexml"><code>page.xml
</code><a class=
"headerlink" href=
"#pagexml" title=
"Permanent link">#
</a></h3>
3486 <p>First, let us register the page with the system because every front end page or form needs to be explicitly registered using the
<a href=
"../../../package/pip/page/">page package installation plugin
</a>:
</p>
3487 <div class=
"titledCodeBox">
3488 <div class=
"codeBoxTitle"><code>page.xml
</code></div>
3489 <table class=
"highlighttable"><tr><td class=
"linenos"><div class=
"linenodiv"><pre><span></span><span class=
"normal"> 1</span>
3490 <span class=
"normal"> 2</span>
3491 <span class=
"normal"> 3</span>
3492 <span class=
"normal"> 4</span>
3493 <span class=
"normal"> 5</span>
3494 <span class=
"normal"> 6</span>
3495 <span class=
"normal"> 7</span>
3496 <span class=
"normal"> 8</span>
3497 <span class=
"normal"> 9</span>
3498 <span class=
"normal">10</span>
3499 <span class=
"normal">11</span>
3500 <span class=
"normal">12</span>
3501 <span class=
"normal">13</span>
3502 <span class=
"normal">14</span>
3503 <span class=
"normal">15</span>
3504 <span class=
"normal">16</span>
3505 <span class=
"normal">17</span>
3506 <span class=
"normal">18</span></pre></div></td><td class=
"code"><div class=
"highlight"><pre><span></span><code><span class=
"cp"><?xml version=
"1.0" encoding=
"UTF-
8"?
></span>
3507 <span class=
"nt"><data
</span> <span class=
"na">xmlns=
</span><span class=
"s">"http://www.woltlab.com
"</span> <span class=
"na">xmlns:xsi=
</span><span class=
"s">"http://www.w3.org/
2001/XMLSchema-instance
"</span> <span class=
"na">xsi:schemaLocation=
</span><span class=
"s">"http://www.woltlab.com http://www.woltlab.com/XSD/
5.4/page.xsd
"</span><span class=
"nt">></span>
3508 <span class=
"nt"><import
></span>
3509 <span class=
"nt"><page
</span> <span class=
"na">identifier=
</span><span class=
"s">"com.woltlab.wcf.people.PersonList
"</span><span class=
"nt">></span>
3510 <span class=
"nt"><pageType
></span>system
<span class=
"nt"></pageType
></span>
3511 <span class=
"nt"><controller
></span>wcf\page\PersonListPage
<span class=
"nt"></controller
></span>
3512 <span class=
"nt"><name
</span> <span class=
"na">language=
</span><span class=
"s">"de
"</span><span class=
"nt">></span>Personen-Liste
<span class=
"nt"></name
></span>
3513 <span class=
"nt"><name
</span> <span class=
"na">language=
</span><span class=
"s">"en
"</span><span class=
"nt">></span>Person List
<span class=
"nt"></name
></span>
3515 <span class=
"nt"><content
</span> <span class=
"na">language=
</span><span class=
"s">"de
"</span><span class=
"nt">></span>
3516 <span class=
"nt"><title
></span>Personen
<span class=
"nt"></title
></span>
3517 <span class=
"nt"></content
></span>
3518 <span class=
"nt"><content
</span> <span class=
"na">language=
</span><span class=
"s">"en
"</span><span class=
"nt">></span>
3519 <span class=
"nt"><title
></span>People
<span class=
"nt"></title
></span>
3520 <span class=
"nt"></content
></span>
3521 <span class=
"nt"></page
></span>
3522 <span class=
"nt"></import
></span>
3523 <span class=
"nt"></data
></span>
3528 <p>For more information about what each of the elements means, please refer to the
<a href=
"../../../package/pip/page/">page package installation plugin page
</a>.
</p>
3529 <h3 id=
"menuitemxml"><code>menuItem.xml
</code><a class=
"headerlink" href=
"#menuitemxml" title=
"Permanent link">#
</a></h3>
3530 <p>Next, we register the menu item using the
<a href=
"../../../package/pip/menu-item/">menuItem package installation plugin
</a>:
</p>
3531 <div class=
"titledCodeBox">
3532 <div class=
"codeBoxTitle"><code>menuItem.xml
</code></div>
3533 <table class=
"highlighttable"><tr><td class=
"linenos"><div class=
"linenodiv"><pre><span></span><span class=
"normal"> 1</span>
3534 <span class=
"normal"> 2</span>
3535 <span class=
"normal"> 3</span>
3536 <span class=
"normal"> 4</span>
3537 <span class=
"normal"> 5</span>
3538 <span class=
"normal"> 6</span>
3539 <span class=
"normal"> 7</span>
3540 <span class=
"normal"> 8</span>
3541 <span class=
"normal"> 9</span>
3542 <span class=
"normal">10</span>
3543 <span class=
"normal">11</span></pre></div></td><td class=
"code"><div class=
"highlight"><pre><span></span><code><span class=
"cp"><?xml version=
"1.0" encoding=
"UTF-
8"?
></span>
3544 <span class=
"nt"><data
</span> <span class=
"na">xmlns=
</span><span class=
"s">"http://www.woltlab.com
"</span> <span class=
"na">xmlns:xsi=
</span><span class=
"s">"http://www.w3.org/
2001/XMLSchema-instance
"</span> <span class=
"na">xsi:schemaLocation=
</span><span class=
"s">"http://www.woltlab.com http://www.woltlab.com/XSD/
5.4/menuItem.xsd
"</span><span class=
"nt">></span>
3545 <span class=
"nt"><import
></span>
3546 <span class=
"nt"><item
</span> <span class=
"na">identifier=
</span><span class=
"s">"com.woltlab.wcf.people.PersonList
"</span><span class=
"nt">></span>
3547 <span class=
"nt"><menu
></span>com.woltlab.wcf.MainMenu
<span class=
"nt"></menu
></span>
3548 <span class=
"nt"><title
</span> <span class=
"na">language=
</span><span class=
"s">"de
"</span><span class=
"nt">></span>Personen
<span class=
"nt"></title
></span>
3549 <span class=
"nt"><title
</span> <span class=
"na">language=
</span><span class=
"s">"en
"</span><span class=
"nt">></span>People
<span class=
"nt"></title
></span>
3550 <span class=
"nt"><page
></span>com.woltlab.wcf.people.PersonList
<span class=
"nt"></page
></span>
3551 <span class=
"nt"></item
></span>
3552 <span class=
"nt"></import
></span>
3553 <span class=
"nt"></data
></span>
3558 <p>Here, the import parts are that we register the menu item for the main menu
<code>com.woltlab.wcf.MainMenu
</code> and link the menu item with the page
<code>com.woltlab.wcf.people.PersonList
</code>, which we just registered.
</p>
3559 <h3 id=
"people-list_1">People List
<a class=
"headerlink" href=
"#people-list_1" title=
"Permanent link">#
</a></h3>
3560 <p>As in the ACP, we need a controller and a template.
3561 You might notice that both the controller’s (unqualified) class name and the template name are the same for the ACP and the front end.
3562 This is no problem because the qualified names of the classes differ and the files are stored in different directories and because the templates are installed by different package installation plugins and are also stored in different directories.
</p>
3563 <h4 id=
"personlistpage_1"><code>PersonListPage
</code><a class=
"headerlink" href=
"#personlistpage_1" title=
"Permanent link">#
</a></h4>
3564 <div class=
"titledCodeBox">
3565 <div class=
"codeBoxTitle"><code>files/lib/page/PersonListPage.class.php
</code></div>
3566 <table class=
"highlighttable"><tr><td class=
"linenos"><div class=
"linenodiv"><pre><span></span><span class=
"normal"> 1</span>
3567 <span class=
"normal"> 2</span>
3568 <span class=
"normal"> 3</span>
3569 <span class=
"normal"> 4</span>
3570 <span class=
"normal"> 5</span>
3571 <span class=
"normal"> 6</span>
3572 <span class=
"normal"> 7</span>
3573 <span class=
"normal"> 8</span>
3574 <span class=
"normal"> 9</span>
3575 <span class=
"normal">10</span>
3576 <span class=
"normal">11</span>
3577 <span class=
"normal">12</span>
3578 <span class=
"normal">13</span>
3579 <span class=
"normal">14</span>
3580 <span class=
"normal">15</span>
3581 <span class=
"normal">16</span>
3582 <span class=
"normal">17</span>
3583 <span class=
"normal">18</span>
3584 <span class=
"normal">19</span>
3585 <span class=
"normal">20</span>
3586 <span class=
"normal">21</span>
3587 <span class=
"normal">22</span>
3588 <span class=
"normal">23</span>
3589 <span class=
"normal">24</span>
3590 <span class=
"normal">25</span>
3591 <span class=
"normal">26</span>
3592 <span class=
"normal">27</span>
3593 <span class=
"normal">28</span>
3594 <span class=
"normal">29</span>
3595 <span class=
"normal">30</span>
3596 <span class=
"normal">31</span></pre></div></td><td class=
"code"><div class=
"highlight"><pre><span></span><code><span class=
"o"><?
</span><span class=
"nx">php
</span>
3598 <span class=
"k">namespace
</span> <span class=
"nx">wcf\page
</span><span class=
"p">;
</span>
3600 <span class=
"k">use
</span> <span class=
"nx">wcf\data\person\PersonList
</span><span class=
"p">;
</span>
3602 <span class=
"sd">/**
</span>
3603 <span class=
"sd"> * Shows the list of people.
</span>
3604 <span class=
"sd"> *
</span>
3605 <span class=
"sd"> * @author Matthias Schmidt
</span>
3606 <span class=
"sd"> * @copyright
2001-
2021 WoltLab GmbH
</span>
3607 <span class=
"sd"> * @license GNU Lesser General Public License
<http://opensource.org/licenses/lgpl-license.php
></span>
3608 <span class=
"sd"> * @package WoltLabSuite\Core\Page
</span>
3609 <span class=
"sd"> */
</span>
3610 <span class=
"k">class
</span> <span class=
"nc">PersonListPage
</span> <span class=
"k">extends
</span> <span class=
"nx">SortablePage
</span>
3611 <span class=
"p">{
</span>
3612 <span class=
"sd">/**
</span>
3613 <span class=
"sd"> * @inheritDoc
</span>
3614 <span class=
"sd"> */
</span>
3615 <span class=
"k">public
</span> <span class=
"nv">$defaultSortField
</span> <span class=
"o">=
</span> <span class=
"s1">'lastName
'</span><span class=
"p">;
</span>
3617 <span class=
"sd">/**
</span>
3618 <span class=
"sd"> * @inheritDoc
</span>
3619 <span class=
"sd"> */
</span>
3620 <span class=
"k">public
</span> <span class=
"nv">$objectListClassName
</span> <span class=
"o">=
</span> <span class=
"nx">PersonList
</span><span class=
"o">::
</span><span class=
"na">class
</span><span class=
"p">;
</span>
3622 <span class=
"sd">/**
</span>
3623 <span class=
"sd"> * @inheritDoc
</span>
3624 <span class=
"sd"> */
</span>
3625 <span class=
"k">public
</span> <span class=
"nv">$validSortFields
</span> <span class=
"o">=
</span> <span class=
"p">[
</span><span class=
"s1">'personID
'</span><span class=
"p">,
</span> <span class=
"s1">'firstName
'</span><span class=
"p">,
</span> <span class=
"s1">'lastName
'</span><span class=
"p">];
</span>
3626 <span class=
"p">}
</span>
3631 <p>This class is almost identical to the ACP version.
3632 In the front end, we do not need to set the active menu item manually because the system determines the active menu item automatically based on the requested page.
3633 Furthermore,
<code>$neededPermissions
</code> has not been set because in the front end, users do not need any special permission to access the page.
3634 In the front end, we explicitly set the
<code>$defaultSortField
</code> so that the people listed on the page are sorted by their last name (in ascending order) by default.
</p>
3635 <h4 id=
"personlisttpl_1"><code>personList.tpl
</code><a class=
"headerlink" href=
"#personlisttpl_1" title=
"Permanent link">#
</a></h4>
3636 <div class=
"titledCodeBox">
3637 <div class=
"codeBoxTitle"><code>templates/personList.tpl
</code></div>
3638 <table class=
"highlighttable"><tr><td class=
"linenos"><div class=
"linenodiv"><pre><span></span><span class=
"normal"> 1</span>
3639 <span class=
"normal"> 2</span>
3640 <span class=
"normal"> 3</span>
3641 <span class=
"normal"> 4</span>
3642 <span class=
"normal"> 5</span>
3643 <span class=
"normal"> 6</span>
3644 <span class=
"normal"> 7</span>
3645 <span class=
"normal"> 8</span>
3646 <span class=
"normal"> 9</span>
3647 <span class=
"normal"> 10</span>
3648 <span class=
"normal"> 11</span>
3649 <span class=
"normal"> 12</span>
3650 <span class=
"normal"> 13</span>
3651 <span class=
"normal"> 14</span>
3652 <span class=
"normal"> 15</span>
3653 <span class=
"normal"> 16</span>
3654 <span class=
"normal"> 17</span>
3655 <span class=
"normal"> 18</span>
3656 <span class=
"normal"> 19</span>
3657 <span class=
"normal"> 20</span>
3658 <span class=
"normal"> 21</span>
3659 <span class=
"normal"> 22</span>
3660 <span class=
"normal"> 23</span>
3661 <span class=
"normal"> 24</span>
3662 <span class=
"normal"> 25</span>
3663 <span class=
"normal"> 26</span>
3664 <span class=
"normal"> 27</span>
3665 <span class=
"normal"> 28</span>
3666 <span class=
"normal"> 29</span>
3667 <span class=
"normal"> 30</span>
3668 <span class=
"normal"> 31</span>
3669 <span class=
"normal"> 32</span>
3670 <span class=
"normal"> 33</span>
3671 <span class=
"normal"> 34</span>
3672 <span class=
"normal"> 35</span>
3673 <span class=
"normal"> 36</span>
3674 <span class=
"normal"> 37</span>
3675 <span class=
"normal"> 38</span>
3676 <span class=
"normal"> 39</span>
3677 <span class=
"normal"> 40</span>
3678 <span class=
"normal"> 41</span>
3679 <span class=
"normal"> 42</span>
3680 <span class=
"normal"> 43</span>
3681 <span class=
"normal"> 44</span>
3682 <span class=
"normal"> 45</span>
3683 <span class=
"normal"> 46</span>
3684 <span class=
"normal"> 47</span>
3685 <span class=
"normal"> 48</span>
3686 <span class=
"normal"> 49</span>
3687 <span class=
"normal"> 50</span>
3688 <span class=
"normal"> 51</span>
3689 <span class=
"normal"> 52</span>
3690 <span class=
"normal"> 53</span>
3691 <span class=
"normal"> 54</span>
3692 <span class=
"normal"> 55</span>
3693 <span class=
"normal"> 56</span>
3694 <span class=
"normal"> 57</span>
3695 <span class=
"normal"> 58</span>
3696 <span class=
"normal"> 59</span>
3697 <span class=
"normal"> 60</span>
3698 <span class=
"normal"> 61</span>
3699 <span class=
"normal"> 62</span>
3700 <span class=
"normal"> 63</span>
3701 <span class=
"normal"> 64</span>
3702 <span class=
"normal"> 65</span>
3703 <span class=
"normal"> 66</span>
3704 <span class=
"normal"> 67</span>
3705 <span class=
"normal"> 68</span>
3706 <span class=
"normal"> 69</span>
3707 <span class=
"normal"> 70</span>
3708 <span class=
"normal"> 71</span>
3709 <span class=
"normal"> 72</span>
3710 <span class=
"normal"> 73</span>
3711 <span class=
"normal"> 74</span>
3712 <span class=
"normal"> 75</span>
3713 <span class=
"normal"> 76</span>
3714 <span class=
"normal"> 77</span>
3715 <span class=
"normal"> 78</span>
3716 <span class=
"normal"> 79</span>
3717 <span class=
"normal"> 80</span>
3718 <span class=
"normal"> 81</span>
3719 <span class=
"normal"> 82</span>
3720 <span class=
"normal"> 83</span>
3721 <span class=
"normal"> 84</span>
3722 <span class=
"normal"> 85</span>
3723 <span class=
"normal"> 86</span>
3724 <span class=
"normal"> 87</span>
3725 <span class=
"normal"> 88</span>
3726 <span class=
"normal"> 89</span>
3727 <span class=
"normal"> 90</span>
3728 <span class=
"normal"> 91</span>
3729 <span class=
"normal"> 92</span>
3730 <span class=
"normal"> 93</span>
3731 <span class=
"normal"> 94</span>
3732 <span class=
"normal"> 95</span>
3733 <span class=
"normal"> 96</span>
3734 <span class=
"normal"> 97</span>
3735 <span class=
"normal"> 98</span>
3736 <span class=
"normal"> 99</span>
3737 <span class=
"normal">100</span>
3738 <span class=
"normal">101</span>
3739 <span class=
"normal">102</span></pre></div></td><td class=
"code"><div class=
"highlight"><pre><span></span><code><span class=
"cp">{
</span><span class=
"nf">capture
</span> <span class=
"na">assign
</span><span class=
"o">=
</span><span class=
"s1">'contentTitle
'</span><span class=
"cp">}{
</span><span class=
"nf">lang
</span><span class=
"cp">}
</span><span class=
"x">wcf.person.list
</span><span class=
"cp">{
</span><span class=
"nf">/lang
</span><span class=
"cp">}
</span><span class=
"x"> <span class=
"badge
"></span><span class=
"cp">{
</span><span class=
"err">#
</span><span class=
"nv">$items
</span><span class=
"cp">}
</span><span class=
"x"></span
></span><span class=
"cp">{
</span><span class=
"nf">/capture
</span><span class=
"cp">}
</span><span class=
"x"></span>
3741 <span class=
"cp">{
</span><span class=
"nf">capture
</span> <span class=
"na">assign
</span><span class=
"o">=
</span><span class=
"s1">'headContent
'</span><span class=
"cp">}
</span><span class=
"x"></span>
3742 <span class=
"x"> </span><span class=
"cp">{
</span><span class=
"nf">if
</span> <span class=
"nv">$pageNo
</span> <span class=
"o"><</span> <span class=
"nv">$pages
</span><span class=
"cp">}
</span><span class=
"x"></span>
3743 <span class=
"x"> <link rel=
"next
" href=
"</span><span class=
"cp">{
</span><span class=
"nf">link
</span> <span class=
"na">controller
</span><span class=
"o">=
</span><span class=
"s1">'PersonList
'</span><span class=
"cp">}
</span><span class=
"x">pageNo=
</span><span class=
"cp">{
</span><span class=
"o">@
</span><span class=
"nv">$pageNo
</span><span class=
"o">+
</span><span class=
"m">1</span><span class=
"cp">}{
</span><span class=
"nf">/link
</span><span class=
"cp">}
</span><span class=
"x">"></span>
3744 <span class=
"x"> </span><span class=
"cp">{
</span><span class=
"nf">/if
</span><span class=
"cp">}
</span><span class=
"x"></span>
3745 <span class=
"x"> </span><span class=
"cp">{
</span><span class=
"nf">if
</span> <span class=
"nv">$pageNo
</span> <span class=
"o">></span> <span class=
"m">1</span><span class=
"cp">}
</span><span class=
"x"></span>
3746 <span class=
"x"> <link rel=
"prev
" href=
"</span><span class=
"cp">{
</span><span class=
"nf">link
</span> <span class=
"na">controller
</span><span class=
"o">=
</span><span class=
"s1">'PersonList
'</span><span class=
"cp">}{
</span><span class=
"nf">if
</span> <span class=
"nv">$pageNo
</span> <span class=
"o">></span> <span class=
"m">2</span><span class=
"cp">}
</span><span class=
"x">pageNo=
</span><span class=
"cp">{
</span><span class=
"o">@
</span><span class=
"nv">$pageNo
</span><span class=
"o">-
</span><span class=
"m">1</span><span class=
"cp">}{
</span><span class=
"nf">/if
</span><span class=
"cp">}{
</span><span class=
"nf">/link
</span><span class=
"cp">}
</span><span class=
"x">"></span>
3747 <span class=
"x"> </span><span class=
"cp">{
</span><span class=
"nf">/if
</span><span class=
"cp">}
</span><span class=
"x"></span>
3748 <span class=
"x"> <link rel=
"canonical
" href=
"</span><span class=
"cp">{
</span><span class=
"nf">link
</span> <span class=
"na">controller
</span><span class=
"o">=
</span><span class=
"s1">'PersonList
'</span><span class=
"cp">}{
</span><span class=
"nf">if
</span> <span class=
"nv">$pageNo
</span> <span class=
"o">></span> <span class=
"m">1</span><span class=
"cp">}
</span><span class=
"x">pageNo=
</span><span class=
"cp">{
</span><span class=
"o">@
</span><span class=
"nv">$pageNo
</span><span class=
"cp">}{
</span><span class=
"nf">/if
</span><span class=
"cp">}{
</span><span class=
"nf">/link
</span><span class=
"cp">}
</span><span class=
"x">"></span>
3749 <span class=
"cp">{
</span><span class=
"nf">/capture
</span><span class=
"cp">}
</span><span class=
"x"></span>
3751 <span class=
"cp">{
</span><span class=
"nf">capture
</span> <span class=
"na">assign
</span><span class=
"o">=
</span><span class=
"s1">'sidebarRight
'</span><span class=
"cp">}
</span><span class=
"x"></span>
3752 <span class=
"x"> <section class=
"box
"></span>
3753 <span class=
"x"> <form method=
"post
" action=
"</span><span class=
"cp">{
</span><span class=
"nf">link
</span> <span class=
"na">controller
</span><span class=
"o">=
</span><span class=
"s1">'PersonList
'</span><span class=
"cp">}{
</span><span class=
"nf">/link
</span><span class=
"cp">}
</span><span class=
"x">"></span>
3754 <span class=
"x"> <h2 class=
"boxTitle
"></span><span class=
"cp">{
</span><span class=
"nf">lang
</span><span class=
"cp">}
</span><span class=
"x">wcf.global.sorting
</span><span class=
"cp">{
</span><span class=
"nf">/lang
</span><span class=
"cp">}
</span><span class=
"x"></h2
></span>
3756 <span class=
"x"> <div class=
"boxContent
"></span>
3757 <span class=
"x"> <dl
></span>
3758 <span class=
"x"> <dt
></dt
></span>
3759 <span class=
"x"> <dd
></span>
3760 <span class=
"x"> <select id=
"sortField
" name=
"sortField
"></span>
3761 <span class=
"x"> <option value=
"firstName
"</span><span class=
"cp">{
</span><span class=
"nf">if
</span> <span class=
"nv">$sortField
</span> <span class=
"o">==
</span> <span class=
"s1">'firstName
'</span><span class=
"cp">}
</span><span class=
"x"> selected
</span><span class=
"cp">{
</span><span class=
"nf">/if
</span><span class=
"cp">}
</span><span class=
"x">></span><span class=
"cp">{
</span><span class=
"nf">lang
</span><span class=
"cp">}
</span><span class=
"x">wcf.person.firstName
</span><span class=
"cp">{
</span><span class=
"nf">/lang
</span><span class=
"cp">}
</span><span class=
"x"></option
></span>
3762 <span class=
"x"> <option value=
"lastName
"</span><span class=
"cp">{
</span><span class=
"nf">if
</span> <span class=
"nv">$sortField
</span> <span class=
"o">==
</span> <span class=
"s1">'lastName
'</span><span class=
"cp">}
</span><span class=
"x"> selected
</span><span class=
"cp">{
</span><span class=
"nf">/if
</span><span class=
"cp">}
</span><span class=
"x">></span><span class=
"cp">{
</span><span class=
"nf">lang
</span><span class=
"cp">}
</span><span class=
"x">wcf.person.lastName
</span><span class=
"cp">{
</span><span class=
"nf">/lang
</span><span class=
"cp">}
</span><span class=
"x"></option
></span>
3763 <span class=
"x"> </span><span class=
"cp">{
</span><span class=
"nf">event
</span> <span class=
"na">name
</span><span class=
"o">=
</span><span class=
"s1">'sortField
'</span><span class=
"cp">}
</span><span class=
"x"></span>
3764 <span class=
"x"> </select
></span>
3765 <span class=
"x"> <select name=
"sortOrder
"></span>
3766 <span class=
"x"> <option value=
"ASC
"</span><span class=
"cp">{
</span><span class=
"nf">if
</span> <span class=
"nv">$sortOrder
</span> <span class=
"o">==
</span> <span class=
"s1">'ASC
'</span><span class=
"cp">}
</span><span class=
"x"> selected
</span><span class=
"cp">{
</span><span class=
"nf">/if
</span><span class=
"cp">}
</span><span class=
"x">></span><span class=
"cp">{
</span><span class=
"nf">lang
</span><span class=
"cp">}
</span><span class=
"x">wcf.global.sortOrder.ascending
</span><span class=
"cp">{
</span><span class=
"nf">/lang
</span><span class=
"cp">}
</span><span class=
"x"></option
></span>
3767 <span class=
"x"> <option value=
"DESC
"</span><span class=
"cp">{
</span><span class=
"nf">if
</span> <span class=
"nv">$sortOrder
</span> <span class=
"o">==
</span> <span class=
"s1">'DESC
'</span><span class=
"cp">}
</span><span class=
"x"> selected
</span><span class=
"cp">{
</span><span class=
"nf">/if
</span><span class=
"cp">}
</span><span class=
"x">></span><span class=
"cp">{
</span><span class=
"nf">lang
</span><span class=
"cp">}
</span><span class=
"x">wcf.global.sortOrder.descending
</span><span class=
"cp">{
</span><span class=
"nf">/lang
</span><span class=
"cp">}
</span><span class=
"x"></option
></span>
3768 <span class=
"x"> </select
></span>
3769 <span class=
"x"> </dd
></span>
3770 <span class=
"x"> </dl
></span>
3772 <span class=
"x"> <div class=
"formSubmit
"></span>
3773 <span class=
"x"> <input type=
"submit
" value=
"</span><span class=
"cp">{
</span><span class=
"nf">lang
</span><span class=
"cp">}
</span><span class=
"x">wcf.global.button.submit
</span><span class=
"cp">{
</span><span class=
"nf">/lang
</span><span class=
"cp">}
</span><span class=
"x">" accesskey=
"s
"></span>
3774 <span class=
"x"> </div
></span>
3775 <span class=
"x"> </div
></span>
3776 <span class=
"x"> </form
></span>
3777 <span class=
"x"> </section
></span>
3778 <span class=
"cp">{
</span><span class=
"nf">/capture
</span><span class=
"cp">}
</span><span class=
"x"></span>
3780 <span class=
"cp">{
</span><span class=
"nf">include
</span> <span class=
"na">file
</span><span class=
"o">=
</span><span class=
"s1">'header
'</span><span class=
"cp">}
</span><span class=
"x"></span>
3782 <span class=
"cp">{
</span><span class=
"nf">hascontent
</span><span class=
"cp">}
</span><span class=
"x"></span>
3783 <span class=
"x"> <div class=
"paginationTop
"></span>
3784 <span class=
"x"> </span><span class=
"cp">{
</span><span class=
"nf">content
</span><span class=
"cp">}
</span><span class=
"x"></span>
3785 <span class=
"x"> </span><span class=
"cp">{
</span><span class=
"nf">pages
</span> <span class=
"na">print
</span><span class=
"o">=
</span><span class=
"kc">true
</span> <span class=
"na">assign
</span><span class=
"o">=
</span><span class=
"na">pagesLinks
</span> <span class=
"na">controller
</span><span class=
"o">=
</span><span class=
"s1">'PersonList
'</span> <span class=
"na">link
</span><span class=
"o">=
</span><span class=
"s2">"pageNo=%d
&sortField=$sortField
&sortOrder=$sortOrder
"</span><span class=
"cp">}
</span><span class=
"x"></span>
3786 <span class=
"x"> </span><span class=
"cp">{
</span><span class=
"nf">/content
</span><span class=
"cp">}
</span><span class=
"x"></span>
3787 <span class=
"x"> </div
></span>
3788 <span class=
"cp">{
</span><span class=
"nf">/hascontent
</span><span class=
"cp">}
</span><span class=
"x"></span>
3790 <span class=
"cp">{
</span><span class=
"nf">if
</span> <span class=
"nv">$items
</span><span class=
"cp">}
</span><span class=
"x"></span>
3791 <span class=
"x"> <div class=
"section sectionContainerList
"></span>
3792 <span class=
"x"> <ol class=
"containerList personList
"></span>
3793 <span class=
"x"> </span><span class=
"cp">{
</span><span class=
"nf">foreach
</span> <span class=
"na">from
</span><span class=
"o">=
</span><span class=
"nv">$objects
</span> <span class=
"na">item
</span><span class=
"o">=
</span><span class=
"na">person
</span><span class=
"cp">}
</span><span class=
"x"></span>
3794 <span class=
"x"> <li
></span>
3795 <span class=
"x"> <div class=
"box48
"></span>
3796 <span class=
"x"> <span class=
"icon icon48 fa-user
"></span
></span>
3798 <span class=
"x"> <div class=
"details personInformation
"></span>
3799 <span class=
"x"> <div class=
"containerHeadline
"></span>
3800 <span class=
"x"> <h3
></span><span class=
"cp">{
</span><span class=
"nv">$person
</span><span class=
"cp">}
</span><span class=
"x"></h3
></span>
3801 <span class=
"x"> </div
></span>
3803 <span class=
"x"> </span><span class=
"cp">{
</span><span class=
"nf">hascontent
</span><span class=
"cp">}
</span><span class=
"x"></span>
3804 <span class=
"x"> <ul class=
"inlineList commaSeparated
"></span>
3805 <span class=
"x"> </span><span class=
"cp">{
</span><span class=
"nf">content
</span><span class=
"cp">}{
</span><span class=
"nf">event
</span> <span class=
"na">name
</span><span class=
"o">=
</span><span class=
"s1">'personData
'</span><span class=
"cp">}{
</span><span class=
"nf">/content
</span><span class=
"cp">}
</span><span class=
"x"></span>
3806 <span class=
"x"> </ul
></span>
3807 <span class=
"x"> </span><span class=
"cp">{
</span><span class=
"nf">/hascontent
</span><span class=
"cp">}
</span><span class=
"x"></span>
3809 <span class=
"x"> </span><span class=
"cp">{
</span><span class=
"nf">hascontent
</span><span class=
"cp">}
</span><span class=
"x"></span>
3810 <span class=
"x"> <dl class=
"plain inlineDataList small
"></span>
3811 <span class=
"x"> </span><span class=
"cp">{
</span><span class=
"nf">content
</span><span class=
"cp">}{
</span><span class=
"nf">event
</span> <span class=
"na">name
</span><span class=
"o">=
</span><span class=
"s1">'personStatistics
'</span><span class=
"cp">}{
</span><span class=
"nf">/content
</span><span class=
"cp">}
</span><span class=
"x"></span>
3812 <span class=
"x"> </dl
></span>
3813 <span class=
"x"> </span><span class=
"cp">{
</span><span class=
"nf">/hascontent
</span><span class=
"cp">}
</span><span class=
"x"></span>
3814 <span class=
"x"> </div
></span>
3815 <span class=
"x"> </div
></span>
3816 <span class=
"x"> </li
></span>
3817 <span class=
"x"> </span><span class=
"cp">{
</span><span class=
"nf">/foreach
</span><span class=
"cp">}
</span><span class=
"x"></span>
3818 <span class=
"x"> </ol
></span>
3819 <span class=
"x"> </div
></span>
3820 <span class=
"cp">{
</span><span class=
"nf">else
</span><span class=
"cp">}
</span><span class=
"x"></span>
3821 <span class=
"x"> <p class=
"info
"></span><span class=
"cp">{
</span><span class=
"nf">lang
</span><span class=
"cp">}
</span><span class=
"x">wcf.global.noItems
</span><span class=
"cp">{
</span><span class=
"nf">/lang
</span><span class=
"cp">}
</span><span class=
"x"></p
></span>
3822 <span class=
"cp">{
</span><span class=
"nf">/if
</span><span class=
"cp">}
</span><span class=
"x"></span>
3824 <span class=
"x"><footer class=
"contentFooter
"></span>
3825 <span class=
"x"> </span><span class=
"cp">{
</span><span class=
"nf">hascontent
</span><span class=
"cp">}
</span><span class=
"x"></span>
3826 <span class=
"x"> <div class=
"paginationBottom
"></span>
3827 <span class=
"x"> </span><span class=
"cp">{
</span><span class=
"nf">content
</span><span class=
"cp">}{
</span><span class=
"o">@
</span><span class=
"nv">$pagesLinks
</span><span class=
"cp">}{
</span><span class=
"nf">/content
</span><span class=
"cp">}
</span><span class=
"x"></span>
3828 <span class=
"x"> </div
></span>
3829 <span class=
"x"> </span><span class=
"cp">{
</span><span class=
"nf">/hascontent
</span><span class=
"cp">}
</span><span class=
"x"></span>
3831 <span class=
"x"> </span><span class=
"cp">{
</span><span class=
"nf">hascontent
</span><span class=
"cp">}
</span><span class=
"x"></span>
3832 <span class=
"x"> <nav class=
"contentFooterNavigation
"></span>
3833 <span class=
"x"> <ul
></span>
3834 <span class=
"x"> </span><span class=
"cp">{
</span><span class=
"nf">content
</span><span class=
"cp">}{
</span><span class=
"nf">event
</span> <span class=
"na">name
</span><span class=
"o">=
</span><span class=
"s1">'contentFooterNavigation
'</span><span class=
"cp">}{
</span><span class=
"nf">/content
</span><span class=
"cp">}
</span><span class=
"x"></span>
3835 <span class=
"x"> </ul
></span>
3836 <span class=
"x"> </nav
></span>
3837 <span class=
"x"> </span><span class=
"cp">{
</span><span class=
"nf">/hascontent
</span><span class=
"cp">}
</span><span class=
"x"></span>
3838 <span class=
"x"></footer
></span>
3840 <span class=
"cp">{
</span><span class=
"nf">include
</span> <span class=
"na">file
</span><span class=
"o">=
</span><span class=
"s1">'footer
'</span><span class=
"cp">}
</span><span class=
"x"></span>
3845 <p>If you compare this template to the one used in the ACP, you will recognize similar elements like the
<code>.paginationTop
</code> element, the
<code>p.info
</code> element if no people exist, and the
<code>.contentFooter
</code> element.
3846 Furthermore, we include a template called
<code>header
</code> before actually showing any of the page contents and terminate the template by including the
<code>footer
</code> template.
</p>
3847 <p>Now, let us take a closer look at the differences:
</p>
3849 <li>We do not explicitly create a
<code>.contentHeader
</code> element but simply assign the title to the
<code>contentTitle
</code> variable.
3850 The value of the assignment is simply the title of the page and a badge showing the number of listed people.
3851 The
<code>header
</code> template that we include later will handle correctly displaying the content header on its own based on the
<code>$contentTitle
</code> variable.
</li>
3852 <li>Next, we create additional element for the HTML document’s
<code><head
></code> element.
3853 In this case, we define the
<a href=
"https://en.wikipedia.org/wiki/Canonical_link_element">canonical link of the page
</a> and, because we are showing paginated content, add links to the previous and next page (if they exist).
</li>
3854 <li>We want the page to be sortable but as we will not be using a table for listing the people like in the ACP, we are not able to place links to sort the people into the table head.
3855 Instead, usually a box is created in the sidebar on the right-hand side that contains
<code>select
</code> elements to determine sort field and sort order.
</li>
3856 <li>The main part of the page is the listing of the people.
3857 We use a structure similar to the one used for displaying registered users.
3858 Here, for each person, we simply display a FontAwesome icon representing a person and show the person’s full name relying on
<code>Person::__toString()
</code>.
3859 Additionally, like in the user list, we provide the initially empty
<code>ul.inlineList.commaSeparated
</code> and
<code>dl.plain.inlineDataList.small
</code> elements that can be filled by plugins using the templates events.
</li>
3861 <h2 id=
"usergroupoptionxml"><code>userGroupOption.xml
</code><a class=
"headerlink" href=
"#usergroupoptionxml" title=
"Permanent link">#
</a></h2>
3862 <p>We have already used the
<code>admin.content.canManagePeople
</code> permissions several times, now we need to install it using the
<a href=
"../../../package/pip/user-group-option/">userGroupOption package installation plugin
</a>:
</p>
3863 <div class=
"titledCodeBox">
3864 <div class=
"codeBoxTitle"><code>userGroupOption.xml
</code></div>
3865 <table class=
"highlighttable"><tr><td class=
"linenos"><div class=
"linenodiv"><pre><span></span><span class=
"normal"> 1</span>
3866 <span class=
"normal"> 2</span>
3867 <span class=
"normal"> 3</span>
3868 <span class=
"normal"> 4</span>
3869 <span class=
"normal"> 5</span>
3870 <span class=
"normal"> 6</span>
3871 <span class=
"normal"> 7</span>
3872 <span class=
"normal"> 8</span>
3873 <span class=
"normal"> 9</span>
3874 <span class=
"normal">10</span>
3875 <span class=
"normal">11</span>
3876 <span class=
"normal">12</span>
3877 <span class=
"normal">13</span>
3878 <span class=
"normal">14</span></pre></div></td><td class=
"code"><div class=
"highlight"><pre><span></span><code><span class=
"cp"><?xml version=
"1.0" encoding=
"UTF-
8"?
></span>
3879 <span class=
"nt"><data
</span> <span class=
"na">xmlns=
</span><span class=
"s">"http://www.woltlab.com
"</span> <span class=
"na">xmlns:xsi=
</span><span class=
"s">"http://www.w3.org/
2001/XMLSchema-instance
"</span> <span class=
"na">xsi:schemaLocation=
</span><span class=
"s">"http://www.woltlab.com http://www.woltlab.com/XSD/
5.4/userGroupOption.xsd
"</span><span class=
"nt">></span>
3880 <span class=
"nt"><import
></span>
3881 <span class=
"nt"><options
></span>
3882 <span class=
"nt"><option
</span> <span class=
"na">name=
</span><span class=
"s">"admin.content.canManagePeople
"</span><span class=
"nt">></span>
3883 <span class=
"nt"><categoryname
></span>admin.content
<span class=
"nt"></categoryname
></span>
3884 <span class=
"nt"><optiontype
></span>boolean
<span class=
"nt"></optiontype
></span>
3885 <span class=
"nt"><defaultvalue
></span>0<span class=
"nt"></defaultvalue
></span>
3886 <span class=
"nt"><admindefaultvalue
></span>1<span class=
"nt"></admindefaultvalue
></span>
3887 <span class=
"nt"><usersonly
></span>1<span class=
"nt"></usersonly
></span>
3888 <span class=
"nt"></option
></span>
3889 <span class=
"nt"></options
></span>
3890 <span class=
"nt"></import
></span>
3891 <span class=
"nt"></data
></span>
3896 <p>We use the existing
<code>admin.content
</code> user group option category for the permission as the people are “content” (similar the the ACP menu item).
3897 As the permission is for administrators only, we set
<code>defaultvalue
</code> to
<code>0</code> and
<code>admindefaultvalue
</code> to
<code>1</code>.
3898 This permission is only relevant for registered users so that it should not be visible when editing the guest user group.
3899 This is achieved by setting
<code>usersonly
</code> to
<code>1</code>.
</p>
3900 <h2 id=
"packagexml"><code>package.xml
</code><a class=
"headerlink" href=
"#packagexml" title=
"Permanent link">#
</a></h2>
3901 <p>Lastly, we need to create the
<code>package.xml
</code> file.
3902 For more information about this kind of file, please refer to
<a href=
"../../../package/package-xml/">the
<code>package.xml
</code> page
</a>.
</p>
3903 <div class=
"titledCodeBox">
3904 <div class=
"codeBoxTitle"><code>package.xml
</code></div>
3905 <table class=
"highlighttable"><tr><td class=
"linenos"><div class=
"linenodiv"><pre><span></span><span class=
"normal"> 1</span>
3906 <span class=
"normal"> 2</span>
3907 <span class=
"normal"> 3</span>
3908 <span class=
"normal"> 4</span>
3909 <span class=
"normal"> 5</span>
3910 <span class=
"normal"> 6</span>
3911 <span class=
"normal"> 7</span>
3912 <span class=
"normal"> 8</span>
3913 <span class=
"normal"> 9</span>
3914 <span class=
"normal">10</span>
3915 <span class=
"normal">11</span>
3916 <span class=
"normal">12</span>
3917 <span class=
"normal">13</span>
3918 <span class=
"normal">14</span>
3919 <span class=
"normal">15</span>
3920 <span class=
"normal">16</span>
3921 <span class=
"normal">17</span>
3922 <span class=
"normal">18</span>
3923 <span class=
"normal">19</span>
3924 <span class=
"normal">20</span>
3925 <span class=
"normal">21</span>
3926 <span class=
"normal">22</span>
3927 <span class=
"normal">23</span>
3928 <span class=
"normal">24</span>
3929 <span class=
"normal">25</span>
3930 <span class=
"normal">26</span>
3931 <span class=
"normal">27</span>
3932 <span class=
"normal">28</span>
3933 <span class=
"normal">29</span>
3934 <span class=
"normal">30</span>
3935 <span class=
"normal">31</span>
3936 <span class=
"normal">32</span>
3937 <span class=
"normal">33</span>
3938 <span class=
"normal">34</span>
3939 <span class=
"normal">35</span></pre></div></td><td class=
"code"><div class=
"highlight"><pre><span></span><code><span class=
"cp"><?xml version=
"1.0" encoding=
"UTF-
8"?
></span>
3940 <span class=
"nt"><package
</span> <span class=
"na">name=
</span><span class=
"s">"com.woltlab.wcf.people
"</span> <span class=
"na">xmlns=
</span><span class=
"s">"http://www.woltlab.com
"</span> <span class=
"na">xmlns:xsi=
</span><span class=
"s">"http://www.w3.org/
2001/XMLSchema-instance
"</span> <span class=
"na">xsi:schemaLocation=
</span><span class=
"s">"http://www.woltlab.com http://www.woltlab.com/XSD/
5.4/package.xsd
"</span><span class=
"nt">></span>
3941 <span class=
"nt"><packageinformation
></span>
3942 <span class=
"nt"><packagename
></span>WoltLab Suite Core Tutorial: People
<span class=
"nt"></packagename
></span>
3943 <span class=
"nt"><packagedescription
></span>Adds a simple management system for people as part of a tutorial to create packages.
<span class=
"nt"></packagedescription
></span>
3944 <span class=
"nt"><version
></span>5.4.0<span class=
"nt"></version
></span>
3945 <span class=
"nt"><date
></span>2021-
04-
16<span class=
"nt"></date
></span>
3946 <span class=
"nt"></packageinformation
></span>
3948 <span class=
"nt"><authorinformation
></span>
3949 <span class=
"nt"><author
></span>WoltLab GmbH
<span class=
"nt"></author
></span>
3950 <span class=
"nt"><authorurl
></span>http://www.woltlab.com
<span class=
"nt"></authorurl
></span>
3951 <span class=
"nt"></authorinformation
></span>
3953 <span class=
"nt"><requiredpackages
></span>
3954 <span class=
"nt"><requiredpackage
</span> <span class=
"na">minversion=
</span><span class=
"s">"5.4.0 Alpha
1"</span><span class=
"nt">></span>com.woltlab.wcf
<span class=
"nt"></requiredpackage
></span>
3955 <span class=
"nt"></requiredpackages
></span>
3957 <span class=
"nt"><excludedpackages
></span>
3958 <span class=
"nt"><excludedpackage
</span> <span class=
"na">version=
</span><span class=
"s">"6.0.0 Alpha
1"</span><span class=
"nt">></span>com.woltlab.wcf
<span class=
"nt"></excludedpackage
></span>
3959 <span class=
"nt"></excludedpackages
></span>
3961 <span class=
"nt"><instructions
</span> <span class=
"na">type=
</span><span class=
"s">"install
"</span><span class=
"nt">></span>
3962 <span class=
"nt"><instruction
</span> <span class=
"na">type=
</span><span class=
"s">"acpTemplate
"</span> <span class=
"nt">/
></span>
3963 <span class=
"nt"><instruction
</span> <span class=
"na">type=
</span><span class=
"s">"file
"</span> <span class=
"nt">/
></span>
3964 <span class=
"nt"><instruction
</span> <span class=
"na">type=
</span><span class=
"s">"database
"</span><span class=
"nt">></span>acp/database/install_com.woltlab.wcf.people.php
<span class=
"nt"></instruction
></span>
3965 <span class=
"nt"><instruction
</span> <span class=
"na">type=
</span><span class=
"s">"template
"</span> <span class=
"nt">/
></span>
3966 <span class=
"nt"><instruction
</span> <span class=
"na">type=
</span><span class=
"s">"language
"</span> <span class=
"nt">/
></span>
3968 <span class=
"nt"><instruction
</span> <span class=
"na">type=
</span><span class=
"s">"acpMenu
"</span> <span class=
"nt">/
></span>
3969 <span class=
"nt"><instruction
</span> <span class=
"na">type=
</span><span class=
"s">"page
"</span> <span class=
"nt">/
></span>
3970 <span class=
"nt"><instruction
</span> <span class=
"na">type=
</span><span class=
"s">"menuItem
"</span> <span class=
"nt">/
></span>
3971 <span class=
"nt"><instruction
</span> <span class=
"na">type=
</span><span class=
"s">"userGroupOption
"</span> <span class=
"nt">/
></span>
3972 <span class=
"nt"></instructions
></span>
3973 <span class=
"nt"></package
></span>
3978 <p>As this is a package for WoltLab Suite Core
3, we need to require it using
<code><requiredpackage
></code>.
3979 We require the latest version (when writing this tutorial)
<code>5.4.0 Alpha
1</code>.
3980 Additionally, we disallow installation of the package in the next major version
<code>6.0</code> by excluding the
<code>6.0.0 Alpha
1</code> version.
</p>
3981 <p>The most important part are to installation instructions.
3982 First, we install the ACP templates, files and templates, create the database table and import the language item.
3983 Afterwards, the ACP menu items and the permission are added.
3984 Now comes the part of the instructions where the order of the instructions is crucial:
3985 In
<code>menuItem.xml
</code>, we refer to the
<code>com.woltlab.wcf.people.PersonList
</code> page that is delivered by
<code>page.xml
</code>.
3986 As the menu item package installation plugin validates the given page and throws an exception if the page does not exist, we need to install the page before the menu item!
</p>
3988 <p>This concludes the first part of our tutorial series after which you now have a working simple package with which you can manage people in the ACP and show the visitors of your website a simple list of all created people in the front end.
</p>
3989 <p>The complete source code of this part can be found on
<a href=
"https://github.com/WoltLab/docs.woltlab.com/tree/5.4/snippets/tutorial/tutorial-series/part-1">GitHub
</a>.
</p>
3995 <div class=
"md-source-date">
3998 Last update:
2021-
04-
23
4017 <footer class=
"md-footer">
4019 <nav class=
"md-footer__inner md-grid" aria-label=
"Footer">
4021 <a href=
"../overview/" class=
"md-footer__link md-footer__link--prev" rel=
"prev">
4022 <div class=
"md-footer__button md-icon">
4023 <svg xmlns=
"http://www.w3.org/2000/svg" viewBox=
"0 0 24 24"><path d=
"M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12z"/></svg>
4025 <div class=
"md-footer__title">
4026 <div class=
"md-ellipsis">
4027 <span class=
"md-footer__direction">
4036 <a href=
"../part_2/" class=
"md-footer__link md-footer__link--next" rel=
"next">
4037 <div class=
"md-footer__title">
4038 <div class=
"md-ellipsis">
4039 <span class=
"md-footer__direction">
4045 <div class=
"md-footer__button md-icon">
4046 <svg xmlns=
"http://www.w3.org/2000/svg" viewBox=
"0 0 24 24"><path d=
"M4 11v2h12l-5.5 5.5 1.42 1.42L19.84 12l-7.92-7.92L10.5 5.5 16 11H4z"/></svg>
4052 <div class=
"md-footer-meta md-typeset">
4053 <div class=
"md-footer-meta__inner md-grid">
4054 <div class=
"md-footer-copyright">
4056 <div class=
"md-footer-copyright__highlight">
4057 Copyright ©
2020 WoltLab GmbH
4061 <a href=
"https://squidfunk.github.io/mkdocs-material/" target=
"_blank" rel=
"noopener">
4066 <div class=
"md-footer-copyright">
4067 <a href=
"https://www.woltlab.com/legal-notice/">Legal Notice
</a>
4068 <a href=
"https://www.woltlab.com/privacy-policy/">Privacy Policy
</a>
4075 <div class=
"md-dialog" data-md-component=
"dialog">
4076 <div class=
"md-dialog__inner md-typeset"></div>
4078 <script id=
"__config" type=
"application/json">{
"base":
"../../..",
"features": [],
"translations": {
"clipboard.copy":
"Copy to clipboard",
"clipboard.copied":
"Copied to clipboard",
"search.config.lang":
"en",
"search.config.pipeline":
"trimmer, stopWordFilter",
"search.config.separator":
"[\\s\\-]+",
"search.placeholder":
"Search",
"search.result.placeholder":
"Type to start searching",
"search.result.none":
"No matching documents",
"search.result.one":
"1 matching document",
"search.result.other":
"# matching documents",
"search.result.more.one":
"1 more on this page",
"search.result.more.other":
"# more on this page",
"search.result.term.missing":
"Missing"},
"search":
"../../../assets/javascripts/workers/search.fe42c31b.min.js",
"version": {
"provider":
"mike"}}
</script>
4081 <script src=
"../../../assets/javascripts/bundle.4ea5477f.min.js"></script>