Deployed 3bf25ab to 5.4 with MkDocs 1.1.2 and mike 0.5.5
[GitHub/WoltLab/woltlab.github.io.git] / 5.3 / tutorial_tutorial-series_part-3-person-page-and-comments.html
CommitLineData
d9cdc0cc
TD
1<!DOCTYPE html>
2<head>
3 <meta charset="utf-8">
4<meta http-equiv="X-UA-Compatible" content="IE=edge">
5<meta name="viewport" content="width=device-width, initial-scale=1">
6<meta name="description" content="">
7<meta name="keywords" content=" ">
8<title>Tutorial Series Part 3: Person Page and Comments | WoltLab Suite 5.3 Documentation</title>
9
e2f8eee7 10<link rel="stylesheet" href="https://docs.woltlab.com/5.3/css/syntax.css">
d9cdc0cc 11<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans:400,300,600">
e2f8eee7 12<link rel="stylesheet" href="https://docs.woltlab.com/5.3/css/font-awesome.min.css">
d9cdc0cc 13<!--<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css">-->
e2f8eee7
TD
14<link rel="stylesheet" href="https://docs.woltlab.com/5.3/css/modern-business.css">
15<link rel="stylesheet" href="https://docs.woltlab.com/5.3/css/lavish-bootstrap.css">
16<link rel="stylesheet" href="https://docs.woltlab.com/5.3/css/customstyles.css">
17<link rel="stylesheet" href="https://docs.woltlab.com/5.3/css/theme-blue.css?v=3">
d9cdc0cc 18
e2f8eee7
TD
19<script src="https://docs.woltlab.com/5.3/js/jquery.min.js"></script>
20<script src="https://docs.woltlab.com/5.3/js/jquery.cookie.min.js"></script>
21<script src="https://docs.woltlab.com/5.3/js/jquery.navgoco.min.js"></script>
22<script src="https://docs.woltlab.com/5.3/js/bootstrap.min.js"></script>
23<script src="https://docs.woltlab.com/5.3/js/anchor.min.js"></script>
24<script src="https://docs.woltlab.com/5.3/js/toc.js"></script>
25<script src="https://docs.woltlab.com/5.3/js/customscripts.js"></script>
d9cdc0cc 26
e2f8eee7 27<link rel="shortcut icon" href="https://docs.woltlab.com/5.3/images/favicon.ico">
d9cdc0cc 28
e2f8eee7 29<link rel="alternate" type="application/rss+xml" title="woltlab.github.io" href="https://docs.woltlab.com/5.3feed.xml">
d9cdc0cc
TD
30
31 <script>
32 $(document).ready(function() {
33 // Initialize navgoco with default options
34 $("#mysidebar").navgoco({
35 caretHtml: '',
36 accordion: true,
37 openClass: 'active', // open
38 save: false, // leave false or nav highlighting doesn't work right
39 cookie: {
40 name: 'navgoco',
41 expires: false,
42 path: '/'
43 },
44 slide: {
45 duration: 400,
46 easing: 'swing'
47 }
48 });
49
50 $("#collapseAll").click(function(e) {
51 e.preventDefault();
52 $("#mysidebar").navgoco('toggle', false);
53 });
54
55 $("#expandAll").click(function(e) {
56 e.preventDefault();
57 $("#mysidebar").navgoco('toggle', true);
58 });
59
60 });
61
62 </script>
63 <script>
64 $(function () {
65 $('[data-toggle="tooltip"]').tooltip()
66 })
67 </script>
68
69
70</head>
71<body>
72 <!-- Navigation -->
73<nav class="navbar navbar-inverse navbar-fixed-top">
74 <div class="container topnavlinks">
75 <div class="navbar-header">
76 <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
77 <span class="sr-only">Toggle navigation</span>
78 <span class="icon-bar"></span>
79 <span class="icon-bar"></span>
80 <span class="icon-bar"></span>
81 </button>
82 <a class="fa fa-home fa-lg navbar-brand" href="index.html">&nbsp;<span class="projectTitle"> WoltLab Suite 5.3 Documentation</span></a>
83 </div>
84 <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
85 <ul class="nav navbar-nav navbar-right">
86 <!-- entries without drop-downs appear here -->
87
88
89
90 <li><a href="https://www.woltlab.com" target="_blank">woltlab.com</a></li>
91
92
93
94
95
96 <li><a href="https://github.com/WoltLab/WCF/" target="_blank">Code on github.com</a></li>
97
98
99
100 <!-- entries with drop-downs appear here -->
101 <!-- conditional logic to control which topnav appears for the audience defined in the configuration file.-->
102
103
104 <!--comment out this block if you want to hide search-->
105 <li>
106 <!--start search-->
107 <div id="search-demo-container">
108 <input type="text" id="search-input" placeholder="search...">
109 <ul id="results-container"></ul>
110 </div>
e2f8eee7 111 <script src="https://docs.woltlab.com/5.3/js/jekyll-search.js" type="text/javascript"></script>
d9cdc0cc
TD
112 <script type="text/javascript">
113 SimpleJekyllSearch.init({
114 searchInput: document.getElementById('search-input'),
115 resultsContainer: document.getElementById('results-container'),
e2f8eee7 116 dataSource: 'https://docs.woltlab.com/5.3/search.json',
d9cdc0cc
TD
117 searchResultTemplate: '<li><a href="{url}" title="Tutorial Series Part 3: Person Page and Comments">{title}</a></li>',
118 noResultsText: 'No results found.',
119 limit: 10,
120 fuzzy: true,
121 })
122 </script>
123 <!--end search-->
124 </li>
125 </ul>
126 </div>
127 </div>
128 <!-- /.container -->
129</nav>
130
131
132 <div class="container">
133 <div class="col-lg-12">&nbsp;</div>
134
135 <div class="row">
136 <div class="col-md-3">
137
138
139
140<ul id="mysidebar" class="nav">
141 <li class="sidebarTitle">WoltLab Suite 5.3</li>
142
143
144
145 <li>
146 <a href="#">Getting Started</a>
147 <ul>
148
149
150
151
152 <li data-identifier="index"><a href="index.html">Introduction</a></li>
153
154
155
156
157
158
159
160
161 <li data-identifier="getting-started_quick-start"><a href="getting-started_quick-start.html">Quick Start</a></li>
162
163
164
165
166
167 </ul>
168 </li>
169
170 <li>
171 <a href="#">PHP API</a>
172 <ul>
173
174
175
176
177 <li data-identifier="php_pages"><a href="php_pages.html">Pages</a></li>
178
179
180
181
182
183
184
185
186 <li data-identifier="php_database-objects"><a href="php_database-objects.html">Database Objects</a></li>
187
188
189
190
191
192
193
194
195 <li data-identifier="php_database-access"><a href="php_database-access.html">Database Access</a></li>
196
197
198
199
200
201
202
203
204 <li data-identifier="php_exceptions"><a href="php_exceptions.html">Exceptions</a></li>
205
206
207
208
209
210
211
212
213 <li class="subfolders">
214 <a href="#">API</a>
215 <ul>
216
217
218
219 <li data-identifier="php_api_caches"><a href="php_api_caches.html">Caches</a></li>
220
221
222
223
224 <li data-identifier="php_api_comments"><a href="php_api_comments.html">Comments</a></li>
225
226
227
228
229 <li data-identifier="php_api_cronjobs"><a href="php_api_cronjobs.html">Cronjobs</a></li>
230
231
232
233
234 <li data-identifier="php_api_events"><a href="php_api_events.html">Events</a></li>
235
236
237
238
239 <li data-identifier="php_api_form_builder"><a href="php_api_form_builder.html">Form Builder</a></li>
240
241
242
243
244 <li data-identifier="php_api_package_installation_plugins"><a href="php_api_package_installation_plugins.html">Package Installation Plugins</a></li>
245
246
247
248
249 <li data-identifier="php_api_user_activity_points"><a href="php_api_user_activity_points.html">User Activity Points</a></li>
250
251
252
253
254 <li data-identifier="php_api_user_notifications"><a href="php_api_user_notifications.html">User Notifications</a></li>
255
256
257
258
259 <li data-identifier="php_api_sitemaps"><a href="php_api_sitemaps.html">Sitemaps</a></li>
260
261
262 </ul>
263 </li>
264
265
266
267
268
269 <li data-identifier="php_code-style"><a href="php_code-style.html">Code Style</a></li>
270
271
272
273
274
275
276
277
278 <li data-identifier="php_apps"><a href="php_apps.html">Apps</a></li>
279
280
281
282
283
284
285
286
287 <li data-identifier="php_gdpr"><a href="php_gdpr.html">GDPR</a></li>
288
289
290
291
292
293 </ul>
294 </li>
295
296 <li>
297 <a href="#">Languages, Templates & CSS</a>
298 <ul>
299
300
301
302
303 <li data-identifier="view_languages"><a href="view_languages.html">Languages</a></li>
304
305
306
307
308
309
310
311
312 <li data-identifier="view_templates"><a href="view_templates.html">Templates</a></li>
313
314
315
316
317
318
319
320
321 <li data-identifier="view_css"><a href="view_css.html">CSS</a></li>
322
323
324
325
326
327 </ul>
328 </li>
329
330 <li>
331 <a href="#">JavaScript API</a>
332 <ul>
333
334
335
336
337 <li data-identifier="javascript_general-usage"><a href="javascript_general-usage.html">General Usage</a></li>
338
339
340
341
342
343
344
345
346 <li class="subfolders">
347 <a href="#">New API</a>
348 <ul>
349
350
351
352 <li data-identifier="javascript_new-api_writing-a-module"><a href="javascript_new-api_writing-a-module.html">Writing a module</a></li>
353
354
355
356
357 <li data-identifier="javascript_new-api_data-structures"><a href="javascript_new-api_data-structures.html">Data Structures</a></li>
358
359
360
361
362 <li data-identifier="javascript_new-api_core"><a href="javascript_new-api_core.html">Core Functions</a></li>
363
364
365
366
367 <li data-identifier="javascript_new-api_dom"><a href="javascript_new-api_dom.html">DOM</a></li>
368
369
370
371
372 <li data-identifier="javascript_new-api_events"><a href="javascript_new-api_events.html">Event Handling</a></li>
373
374
375
376
377 <li data-identifier="javascript_new-api_ajax"><a href="javascript_new-api_ajax.html">Ajax</a></li>
378
379
380
381
382 <li data-identifier="javascript_new-api_dialogs"><a href="javascript_new-api_dialogs.html">Dialogs</a></li>
383
384
385
386
387 <li data-identifier="javascript_new-api_browser"><a href="javascript_new-api_browser.html">Browser and Screen Sizes</a></li>
388
389
390
391
392 <li data-identifier="javascript_new-api_ui"><a href="javascript_new-api_ui.html">User Interface</a></li>
393
394
395 </ul>
396 </li>
397
398
399
400
401
402 <li data-identifier="javascript_legacy-api"><a href="javascript_legacy-api.html">Legacy API</a></li>
403
404
405
406
407
408
409
410
411 <li data-identifier="javascript_helper-functions"><a href="javascript_helper-functions.html">Helper Functions</a></li>
412
413
414
415
416
417
418
419
420 <li data-identifier="javascript_code-snippets"><a href="javascript_code-snippets.html">Code Snippets</a></li>
421
422
423
424
425
426 </ul>
427 </li>
428
429 <li>
430 <a href="#">Package Components</a>
431 <ul>
432
433
434
435
436 <li data-identifier="package_package-xml"><a href="package_package-xml.html">package.xml</a></li>
437
438
439
440
441
442
443
444
445 <li data-identifier="package_pip"><a href="package_pip.html">PIPs</a></li>
446
447
448
449
450
451 </ul>
452 </li>
453
454 <li>
455 <a href="#">Migration</a>
456 <ul>
457
458
459
460
461 <li class="subfolders">
462 <a href="#">Migrating from WSC 5.2</a>
463 <ul>
464
465
466
467 <li data-identifier="migration_wsc-52_php"><a href="migration_wsc-52_php.html">PHP API</a></li>
468
469
470
471
472 <li data-identifier="migration_wsc-52_templates"><a href="migration_wsc-52_templates.html">Templates and Languages</a></li>
473
474
475
476
477 <li data-identifier="migration_wsc-52_libraries"><a href="migration_wsc-52_libraries.html">Third Party Libraries</a></li>
478
479
480 </ul>
481 </li>
482
483 <li class="subfolders">
484 <a href="#">Migrating from WSC 3.1</a>
485 <ul>
486
487
488
489 <li data-identifier="migration_wsc-31_php"><a href="migration_wsc-31_php.html">PHP API</a></li>
490
491
492 </ul>
493 </li>
494
495 <li class="subfolders">
496 <a href="#">Migrating from WSC 3.0</a>
497 <ul>
498
499
500
501 <li data-identifier="migration_wsc-30_php"><a href="migration_wsc-30_php.html">PHP API</a></li>
502
503
504
505
506 <li data-identifier="migration_wsc-30_javascript"><a href="migration_wsc-30_javascript.html">JavaScript API</a></li>
507
508
509
510
511 <li data-identifier="migration_wsc-30_templates"><a href="migration_wsc-30_templates.html">Templates</a></li>
512
513
514
515
516 <li data-identifier="migration_wsc-30_css"><a href="migration_wsc-30_css.html">CSS</a></li>
517
518
519
520
521 <li data-identifier="migration_wsc-30_package"><a href="migration_wsc-30_package.html">Package Components</a></li>
522
523
524 </ul>
525 </li>
526
527 <li class="subfolders">
528 <a href="#">Migrating from WCF 2.1</a>
529 <ul>
530
531
532
533 <li data-identifier="migration_wcf-21_php"><a href="migration_wcf-21_php.html">PHP API</a></li>
534
535
536
537
538 <li data-identifier="migration_wcf-21_templates"><a href="migration_wcf-21_templates.html">Templates</a></li>
539
540
541
542
543 <li data-identifier="migration_wcf-21_css"><a href="migration_wcf-21_css.html">CSS</a></li>
544
545
546
547
548 <li data-identifier="migration_wcf-21_package"><a href="migration_wcf-21_package.html">Package Components</a></li>
549
550
551 </ul>
552 </li>
553
554
555 </ul>
556 </li>
557
558 <li>
559 <a href="#">Tutorials</a>
560 <ul>
561
562
563
564
565 <li data-identifier="tutorial_tutorial-series"><a href="tutorial_tutorial-series.html">Tutorial Series</a></li>
566
567
568
569
570
571 </ul>
572 </li>
573
574
575</ul>
576
577<script>
578(function() {
579 var sidebar = $('#mysidebar');
580 var item = sidebar.find('.active');
581 if (item.length === 0) {
582 var parent = 'tutorial_tutorial-series';
583 if (parent) {
584 sidebar.find('li[data-identifier="' + parent + '"]').addClass('active');
585 }
586 }
587
588 sidebar.find(".active").parents('li').toggleClass("active");
589})();
590</script>
591
592 </div>
593
594 <div class="col-md-9">
595 <div class="post-header">
596 <h1 class="post-title-main">Tutorial Series Part 3: Person Page and Comments</h1>
597</div>
598
599
600
601<div class="post-content">
602
603
604
605
606
607<!-- this handles the automatic toc. use ## for subheads to auto-generate the on-page minitoc. if you use html tags, you must supply an ID for the heading element in order for it to appear in the minitoc. -->
608<script>
609$( document ).ready(function() {
610 // Handler for .ready() called.
611
612$('#toc').toc({ minimumHeaders: 0, listType: 'ul', showSpeed: 0, headers: 'h2,h3,h4' });
613
614/* this offset helps account for the space taken up by the floating toolbar. */
615$('#toc').on('click', 'a', function() {
616 var target = $(this.getAttribute('href'))
617 , scroll_target = target.offset().top
618
619 $(window).scrollTop(scroll_target - 10);
620 return false
621})
622
623});
624</script>
625
626<div id="toc"></div>
627
628
629
630 <p>In this part of our tutorial series, we will add a new front end page to our package that is dedicated to each person and shows their personal details.
631To make good use of this new page and introduce a new API of WoltLab Suite, we will add the opportunity for users to comment on the person using WoltLab Suite’s reusable comment functionality.</p>
632
633<h2 id="package-functionality">Package Functionality</h2>
634
635<p>In addition to the existing functions from <a href="tutorial_tutorial-series_part-1-base-structure.html">part 1</a>, the package will provide the following possibilities/functions after this part of the tutorial:</p>
636
637<ul>
638 <li>Details page for each person linked in the front end person list</li>
639 <li>Comment on people on their respective page (can be disabled per person)</li>
640 <li>User online location for person details page with name and link to person details page</li>
641 <li>Create menu items linking to specific person details pages</li>
642</ul>
643
644<h2 id="used-components">Used Components</h2>
645
646<p>In addition to the components used in <a href="tutorial_tutorial-series_part-1-base-structure.html">part 1</a>, we will use the <a href="package_pip_object-type.html">objectType package installation plugin</a>, use the <a href="php_api_comments.html">comment API</a>, create a <a href="php_api_caches_runtime-caches.html">runtime cache</a>, and create a page handler.</p>
647
648<h2 id="package-structure">Package Structure</h2>
649
650<p>The complete package will have the following file structure (including the files from <a href="tutorial_tutorial-series_part-1-base-structure.html">part 1</a>):</p>
651
652<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>├── acpMenu.xml
653├── acptemplates
654│   ├── personAdd.tpl
655│   └── personList.tpl
656├── files
657│   └── lib
658│   ├── acp
659│   │   ├── form
660│   │   │   ├── PersonAddForm.class.php
661│   │   │   └── PersonEditForm.class.php
662│   │   └── page
663│   │   └── PersonListPage.class.php
664│   ├── data
665│   │   └── person
666│   │   ├── Person.class.php
667│   │   ├── PersonAction.class.php
668│   │   ├── PersonEditor.class.php
669│   │   └── PersonList.class.php
670│   ├── page
671│   │   ├── PersonListPage.class.php
672│   │   └── PersonPage.class.php
673│   └── system
674│   ├── cache
675│   │   └── runtime
676│   │   └── PersonRuntimeCache.class.php
677│   ├── comment
678│   │   └── manager
679│   │   └── PersonCommentManager.class.php
680│   └── page
681│   └── handler
682│   └── PersonPageHandler.class.php
683├── install.sql
684├── language
685│   ├── de.xml
686│   └── en.xml
687├── menuItem.xml
688├── objectType.xml
689├── package.xml
690├── page.xml
691├── templates
692│   ├── person.tpl
693│   └── personList.tpl
694└── userGroupOption.xml
695</code></pre></div></div>
696
697<div class="bs-callout bs-callout-warning">We will not mention every code change between the first part and this part, as we only want to focus on the important, new parts of the code. For example, there is a new <code class="language-plaintext highlighter-rouge">Person::getLink()</code> method and new language items have been added. For all changes, please refer to the <a href="https://github.com/WoltLab/woltlab.github.io/tree/master/_includes/tutorial/tutorial-series/part-3">source code on GitHub</a>.</div>
698
699<h2 id="runtime-cache">Runtime Cache</h2>
700
701<p>To reduce the number of database queries when different APIs require person objects, we implement a <a href="php_api_caches_runtime-caches.html">runtime cache</a> for people:</p>
702
703<figure class="highlight"><pre><code class="language-php" data-lang="php"><span class="cp">&lt;?php</span>
704<span class="kn">namespace</span> <span class="nn">wcf\system\cache\runtime</span><span class="p">;</span>
705<span class="kn">use</span> <span class="nn">wcf\data\person\Person</span><span class="p">;</span>
706<span class="kn">use</span> <span class="nn">wcf\data\person\PersonList</span><span class="p">;</span>
707
708<span class="cd">/**
709 * Runtime cache implementation for people.
710 *
711 * @author Matthias Schmidt
712 * @copyright 2001-2019 WoltLab GmbH
713 * @license GNU Lesser General Public License &lt;http://opensource.org/licenses/lgpl-license.php&gt;
714 * @package WoltLabSuite\Core\System\Cache\Runtime
715 * @since 3.0
716 *
717 * @method Person[] getCachedObjects()
718 * @method Person getObject($objectID)
719 * @method Person[] getObjects(array $objectIDs)
720 */</span>
721<span class="kd">class</span> <span class="nc">PersonRuntimeCache</span> <span class="k">extends</span> <span class="nx">AbstractRuntimeCache</span> <span class="p">{</span>
722 <span class="cd">/**
723 * @inheritDoc
724 */</span>
725 <span class="k">protected</span> <span class="nv">$listClassName</span> <span class="o">=</span> <span class="nx">PersonList</span><span class="o">::</span><span class="na">class</span><span class="p">;</span>
726<span class="p">}</span></code></pre></figure>
727
728<h2 id="comments">Comments</h2>
729
730<p>To allow users to comment on people, we need to tell the system that people support comments.
731This is done by registering a <code class="language-plaintext highlighter-rouge">com.woltlab.wcf.comment.commentableContent</code> object type whose processor implements <a href="https://github.com/WoltLab/WCF/blob/master/wcfsetup/install/files/lib/system/comment/manager/ICommentManager.class.php">ICommentManager</a>:</p>
732
733<figure class="highlight"><pre><code class="language-xml" data-lang="xml"><span class="cp">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span>
734<span class="nt">&lt;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/tornado/objectType.xsd"</span><span class="nt">&gt;</span>
735 <span class="nt">&lt;import&gt;</span>
736 <span class="nt">&lt;type&gt;</span>
737 <span class="nt">&lt;name&gt;</span>com.woltlab.wcf.person.personComment<span class="nt">&lt;/name&gt;</span>
738 <span class="nt">&lt;definitionname&gt;</span>com.woltlab.wcf.comment.commentableContent<span class="nt">&lt;/definitionname&gt;</span>
739 <span class="nt">&lt;classname&gt;</span>wcf\system\comment\manager\PersonCommentManager<span class="nt">&lt;/classname&gt;</span>
740 <span class="nt">&lt;/type&gt;</span>
741 <span class="nt">&lt;/import&gt;</span>
742<span class="nt">&lt;/data&gt;</span></code></pre></figure>
743
744<p>The <code class="language-plaintext highlighter-rouge">PersonCommentManager</code> class extended <code class="language-plaintext highlighter-rouge">ICommentManager</code>’s default implementation <a href="https://github.com/WoltLab/WCF/blob/master/wcfsetup/install/files/lib/system/comment/manager/AbstractCommentManager.class.php">AbstractCommentManager</a>:</p>
745
746<figure class="highlight"><pre><code class="language-php" data-lang="php"><span class="cp">&lt;?php</span>
747<span class="kn">namespace</span> <span class="nn">wcf\system\comment\manager</span><span class="p">;</span>
748<span class="kn">use</span> <span class="nn">wcf\data\person\Person</span><span class="p">;</span>
749<span class="kn">use</span> <span class="nn">wcf\data\person\PersonEditor</span><span class="p">;</span>
750<span class="kn">use</span> <span class="nn">wcf\system\cache\runtime\PersonRuntimeCache</span><span class="p">;</span>
751<span class="kn">use</span> <span class="nn">wcf\system\WCF</span><span class="p">;</span>
752
753<span class="cd">/**
754 * Comment manager implementation for people.
755 *
756 * @author Matthias Schmidt
757 * @copyright 2001-2019 WoltLab GmbH
758 * @license GNU Lesser General Public License &lt;http://opensource.org/licenses/lgpl-license.php&gt;
759 * @package WoltLabSuite\Core\System\Comment\Manager
760 */</span>
761<span class="kd">class</span> <span class="nc">PersonCommentManager</span> <span class="k">extends</span> <span class="nx">AbstractCommentManager</span> <span class="p">{</span>
762 <span class="cd">/**
763 * @inheritDoc
764 */</span>
765 <span class="k">protected</span> <span class="nv">$permissionAdd</span> <span class="o">=</span> <span class="s1">'user.person.canAddComment'</span><span class="p">;</span>
766
767 <span class="cd">/**
768 * @inheritDoc
769 */</span>
770 <span class="k">protected</span> <span class="nv">$permissionAddWithoutModeration</span> <span class="o">=</span> <span class="s1">'user.person.canAddCommentWithoutModeration'</span><span class="p">;</span>
771
772 <span class="cd">/**
773 * @inheritDoc
774 */</span>
775 <span class="k">protected</span> <span class="nv">$permissionCanModerate</span> <span class="o">=</span> <span class="s1">'mod.person.canModerateComment'</span><span class="p">;</span>
776
777 <span class="cd">/**
778 * @inheritDoc
779 */</span>
780 <span class="k">protected</span> <span class="nv">$permissionDelete</span> <span class="o">=</span> <span class="s1">'user.person.canDeleteComment'</span><span class="p">;</span>
781
782 <span class="cd">/**
783 * @inheritDoc
784 */</span>
785 <span class="k">protected</span> <span class="nv">$permissionEdit</span> <span class="o">=</span> <span class="s1">'user.person.canEditComment'</span><span class="p">;</span>
786
787 <span class="cd">/**
788 * @inheritDoc
789 */</span>
790 <span class="k">protected</span> <span class="nv">$permissionModDelete</span> <span class="o">=</span> <span class="s1">'mod.person.canDeleteComment'</span><span class="p">;</span>
791
792 <span class="cd">/**
793 * @inheritDoc
794 */</span>
795 <span class="k">protected</span> <span class="nv">$permissionModEdit</span> <span class="o">=</span> <span class="s1">'mod.person.canEditComment'</span><span class="p">;</span>
796
797 <span class="cd">/**
798 * @inheritDoc
799 */</span>
800 <span class="k">public</span> <span class="k">function</span> <span class="nf">getLink</span><span class="p">(</span><span class="nv">$objectTypeID</span><span class="p">,</span> <span class="nv">$objectID</span><span class="p">)</span> <span class="p">{</span>
801 <span class="k">return</span> <span class="nx">PersonRuntimeCache</span><span class="o">::</span><span class="na">getInstance</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">getObject</span><span class="p">(</span><span class="nv">$objectID</span><span class="p">)</span><span class="o">-&gt;</span><span class="na">getLink</span><span class="p">();</span>
802 <span class="p">}</span>
803
804 <span class="cd">/**
805 * @inheritDoc
806 */</span>
807 <span class="k">public</span> <span class="k">function</span> <span class="nf">isAccessible</span><span class="p">(</span><span class="nv">$objectID</span><span class="p">,</span> <span class="nv">$validateWritePermission</span> <span class="o">=</span> <span class="kc">false</span><span class="p">)</span> <span class="p">{</span>
808 <span class="k">return</span> <span class="nx">PersonRuntimeCache</span><span class="o">::</span><span class="na">getInstance</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">getObject</span><span class="p">(</span><span class="nv">$objectID</span><span class="p">)</span> <span class="o">!==</span> <span class="kc">null</span><span class="p">;</span>
809 <span class="p">}</span>
810
811 <span class="cd">/**
812 * @inheritDoc
813 */</span>
814 <span class="k">public</span> <span class="k">function</span> <span class="nf">getTitle</span><span class="p">(</span><span class="nv">$objectTypeID</span><span class="p">,</span> <span class="nv">$objectID</span><span class="p">,</span> <span class="nv">$isResponse</span> <span class="o">=</span> <span class="kc">false</span><span class="p">)</span> <span class="p">{</span>
815 <span class="k">if</span> <span class="p">(</span><span class="nv">$isResponse</span><span class="p">)</span> <span class="p">{</span>
816 <span class="k">return</span> <span class="nx">WCF</span><span class="o">::</span><span class="na">getLanguage</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">get</span><span class="p">(</span><span class="s1">'wcf.person.commentResponse'</span><span class="p">);</span>
817 <span class="p">}</span>
818
819 <span class="k">return</span> <span class="nx">WCF</span><span class="o">::</span><span class="na">getLanguage</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">getDynamicVariable</span><span class="p">(</span><span class="s1">'wcf.person.comment'</span><span class="p">);</span>
820 <span class="p">}</span>
821
822 <span class="cd">/**
823 * @inheritDoc
824 */</span>
825 <span class="k">public</span> <span class="k">function</span> <span class="nf">updateCounter</span><span class="p">(</span><span class="nv">$objectID</span><span class="p">,</span> <span class="nv">$value</span><span class="p">)</span> <span class="p">{</span>
826 <span class="p">(</span><span class="k">new</span> <span class="nx">PersonEditor</span><span class="p">(</span><span class="k">new</span> <span class="nx">Person</span><span class="p">(</span><span class="nv">$objectID</span><span class="p">)))</span><span class="o">-&gt;</span><span class="na">updateCounters</span><span class="p">([</span><span class="s1">'comments'</span> <span class="o">=&gt;</span> <span class="nv">$value</span><span class="p">]);</span>
827 <span class="p">}</span>
828<span class="p">}</span></code></pre></figure>
829
830<ul>
831 <li>First, the system is told the names of the permissions via the <code class="language-plaintext highlighter-rouge">$permission*</code> properties.
832More information about comment permissions can be found <a href="php_api_comments.html#user-group-options">here</a>.</li>
833 <li>The <code class="language-plaintext highlighter-rouge">getLink()</code> method returns the link to the person with the passed comment id.
834As in <code class="language-plaintext highlighter-rouge">isAccessible()</code>, <code class="language-plaintext highlighter-rouge">PersonRuntimeCache</code> is used to potentially save database queries.</li>
835 <li>The <code class="language-plaintext highlighter-rouge">isAccessible()</code> method checks if the active user can access the relevant person.
836As we do not have any special restrictions for accessing people, we only need to check if the person exists.</li>
837 <li>The <code class="language-plaintext highlighter-rouge">getTitle()</code> method returns the title used for comments and responses, which is just a generic language item in this case.</li>
838 <li>The <code class="language-plaintext highlighter-rouge">updateCounter()</code> updates the comments’ counter of the person.
839We have added a new <code class="language-plaintext highlighter-rouge">comments</code> database table column to the <code class="language-plaintext highlighter-rouge">wcf1_person</code> database table in order to keep track on the number of comments.</li>
840</ul>
841
842<p>Additionally, we have added a new <code class="language-plaintext highlighter-rouge">enableComments</code> database table column to the <code class="language-plaintext highlighter-rouge">wcf1_person</code> database table whose value can be set when creating or editing a person in the ACP.
843With this option, comments on individual people can be disabled.</p>
844
845<div class="bs-callout bs-callout-info">Liking comments is already built-in and only requires some extra code in the <code class="language-plaintext highlighter-rouge">PersonPage</code> class for showing the likes of pre-loaded comments.</div>
846
847<h2 id="person-page">Person Page</h2>
848
849<h3 id="personpage"><code class="language-plaintext highlighter-rouge">PersonPage</code></h3>
850
851<figure class="highlight"><pre><code class="language-php" data-lang="php"><span class="cp">&lt;?php</span>
852<span class="kn">namespace</span> <span class="nn">wcf\page</span><span class="p">;</span>
853<span class="kn">use</span> <span class="nn">wcf\data\person\Person</span><span class="p">;</span>
854<span class="kn">use</span> <span class="nn">wcf\system\comment\CommentHandler</span><span class="p">;</span>
855<span class="kn">use</span> <span class="nn">wcf\system\comment\manager\PersonCommentManager</span><span class="p">;</span>
856<span class="kn">use</span> <span class="nn">wcf\system\exception\IllegalLinkException</span><span class="p">;</span>
857<span class="kn">use</span> <span class="nn">wcf\system\WCF</span><span class="p">;</span>
858
859<span class="cd">/**
860 * Shows the details of a certain person.
861 *
862 * @author Matthias Schmidt
863 * @copyright 2001-2019 WoltLab GmbH
864 * @license GNU Lesser General Public License &lt;http://opensource.org/licenses/lgpl-license.php&gt;
865 * @package WoltLabSuite\Core\Page
866 */</span>
867<span class="kd">class</span> <span class="nc">PersonPage</span> <span class="k">extends</span> <span class="nx">AbstractPage</span> <span class="p">{</span>
868 <span class="cd">/**
869 * list of comments
870 * @var StructuredCommentList
871 */</span>
872 <span class="k">public</span> <span class="nv">$commentList</span><span class="p">;</span>
873
874 <span class="cd">/**
875 * person comment manager object
876 * @var PersonCommentManager
877 */</span>
878 <span class="k">public</span> <span class="nv">$commentManager</span><span class="p">;</span>
879
880 <span class="cd">/**
881 * id of the person comment object type
882 * @var integer
883 */</span>
884 <span class="k">public</span> <span class="nv">$commentObjectTypeID</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
885
886 <span class="cd">/**
887 * shown person
888 * @var Person
889 */</span>
890 <span class="k">public</span> <span class="nv">$person</span><span class="p">;</span>
891
892 <span class="cd">/**
893 * id of the shown person
894 * @var integer
895 */</span>
896 <span class="k">public</span> <span class="nv">$personID</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
897
898 <span class="cd">/**
899 * @inheritDoc
900 */</span>
901 <span class="k">public</span> <span class="k">function</span> <span class="nf">assignVariables</span><span class="p">()</span> <span class="p">{</span>
902 <span class="k">parent</span><span class="o">::</span><span class="na">assignVariables</span><span class="p">();</span>
903
904 <span class="nx">WCF</span><span class="o">::</span><span class="na">getTPL</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">assign</span><span class="p">([</span>
905 <span class="s1">'commentCanAdd'</span> <span class="o">=&gt;</span> <span class="nx">WCF</span><span class="o">::</span><span class="na">getSession</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">getPermission</span><span class="p">(</span><span class="s1">'user.person.canAddComment'</span><span class="p">),</span>
906 <span class="s1">'commentList'</span> <span class="o">=&gt;</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">commentList</span><span class="p">,</span>
907 <span class="s1">'commentObjectTypeID'</span> <span class="o">=&gt;</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">commentObjectTypeID</span><span class="p">,</span>
908 <span class="s1">'lastCommentTime'</span> <span class="o">=&gt;</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">commentList</span> <span class="o">?</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">commentList</span><span class="o">-&gt;</span><span class="na">getMinCommentTime</span><span class="p">()</span> <span class="o">:</span> <span class="mi">0</span><span class="p">,</span>
909 <span class="s1">'likeData'</span> <span class="o">=&gt;</span> <span class="p">(</span><span class="nx">MODULE_LIKE</span> <span class="o">&amp;&amp;</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">commentList</span><span class="p">)</span> <span class="o">?</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">commentList</span><span class="o">-&gt;</span><span class="na">getLikeData</span><span class="p">()</span> <span class="o">:</span> <span class="p">[],</span>
910 <span class="s1">'person'</span> <span class="o">=&gt;</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">person</span>
911 <span class="p">]);</span>
912 <span class="p">}</span>
913
914 <span class="cd">/**
915 * @inheritDoc
916 */</span>
917 <span class="k">public</span> <span class="k">function</span> <span class="nf">readData</span><span class="p">()</span> <span class="p">{</span>
918 <span class="k">parent</span><span class="o">::</span><span class="na">readData</span><span class="p">();</span>
919
920 <span class="k">if</span> <span class="p">(</span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">person</span><span class="o">-&gt;</span><span class="na">enableComments</span><span class="p">)</span> <span class="p">{</span>
921 <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">commentObjectTypeID</span> <span class="o">=</span> <span class="nx">CommentHandler</span><span class="o">::</span><span class="na">getInstance</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">getObjectTypeID</span><span class="p">(</span><span class="s1">'com.woltlab.wcf.person.personComment'</span><span class="p">);</span>
922 <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">commentManager</span> <span class="o">=</span> <span class="nx">CommentHandler</span><span class="o">::</span><span class="na">getInstance</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">getObjectType</span><span class="p">(</span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">commentObjectTypeID</span><span class="p">)</span><span class="o">-&gt;</span><span class="na">getProcessor</span><span class="p">();</span>
923 <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">commentList</span> <span class="o">=</span> <span class="nx">CommentHandler</span><span class="o">::</span><span class="na">getInstance</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">getCommentList</span><span class="p">(</span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">commentManager</span><span class="p">,</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">commentObjectTypeID</span><span class="p">,</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">person</span><span class="o">-&gt;</span><span class="na">personID</span><span class="p">);</span>
924 <span class="p">}</span>
925 <span class="p">}</span>
926
927 <span class="cd">/**
928 * @inheritDoc
929 */</span>
930 <span class="k">public</span> <span class="k">function</span> <span class="nf">readParameters</span><span class="p">()</span> <span class="p">{</span>
931 <span class="k">parent</span><span class="o">::</span><span class="na">readParameters</span><span class="p">();</span>
932
933 <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="nv">$this</span><span class="o">-&gt;</span><span class="na">personID</span> <span class="o">=</span> <span class="nb">intval</span><span class="p">(</span><span class="nv">$_REQUEST</span><span class="p">[</span><span class="s1">'id'</span><span class="p">]);</span>
934 <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">person</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Person</span><span class="p">(</span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">personID</span><span class="p">);</span>
935 <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">person</span><span class="o">-&gt;</span><span class="na">personID</span><span class="p">)</span> <span class="p">{</span>
936 <span class="k">throw</span> <span class="k">new</span> <span class="nx">IllegalLinkException</span><span class="p">();</span>
937 <span class="p">}</span>
938 <span class="p">}</span>
939<span class="p">}</span></code></pre></figure>
940
941<p>The <code class="language-plaintext highlighter-rouge">PersonPage</code> class is similar to the <code class="language-plaintext highlighter-rouge">PersonEditForm</code> in the ACP in that it reads the id of the requested person from the request data and validates the id in <code class="language-plaintext highlighter-rouge">readParameters()</code>.
942The rest of the code only handles fetching the list of comments on the requested person.
943In <code class="language-plaintext highlighter-rouge">readData()</code>, this list is fetched using <code class="language-plaintext highlighter-rouge">CommentHandler::getCommentList()</code> if comments are enabled for the person.
944The <code class="language-plaintext highlighter-rouge">assignVariables()</code> method assigns some additional template variables like <code class="language-plaintext highlighter-rouge">$commentCanAdd</code>, which is <code class="language-plaintext highlighter-rouge">1</code> if the active person can add comments and is <code class="language-plaintext highlighter-rouge">0</code> otherwise, <code class="language-plaintext highlighter-rouge">$lastCommentTime</code>, which contains the UNIX timestamp of the last comment, and <code class="language-plaintext highlighter-rouge">$likeData</code>, which contains data related to the likes for the disabled comments.</p>
945
946<h3 id="persontpl"><code class="language-plaintext highlighter-rouge">person.tpl</code></h3>
947
948<figure class="highlight"><pre><code class="language-tpl" data-lang="tpl">{capture assign='pageTitle'}{$person} - {lang}wcf.person.list{/lang}{/capture}
949
950{capture assign='contentTitle'}{$person}{/capture}
951
952{include file='header'}
953
954{if $person-&gt;enableComments}
955 {if $commentList|count || $commentCanAdd}
956 &lt;section id="comments" class="section sectionContainerList"&gt;
957 &lt;header class="sectionHeader"&gt;
958 &lt;h2 class="sectionTitle"&gt;{lang}wcf.person.comments{/lang}{if $person-&gt;comments} &lt;span class="badge"&gt;{#$person-&gt;comments}&lt;/span&gt;{/if}&lt;/h2&gt;
959 &lt;/header&gt;
960
961 {include file='__commentJavaScript' commentContainerID='personCommentList'}
962
963 &lt;div class="personComments"&gt;
964 &lt;ul id="personCommentList" class="commentList containerList"
965 data-can-add="{if $commentCanAdd}true{else}false{/if}"
966 data-object-id="{@$person-&gt;personID}"
967 data-object-type-id="{@$commentObjectTypeID}"
968 data-comments="{if $person-&gt;comments}{@$commentList-&gt;countObjects()}{else}0{/if}"
969 data-last-comment-time="{@$lastCommentTime}"
970 &gt;
971 {include file='commentListAddComment' wysiwygSelector='personCommentListAddComment'}
972 {include file='commentList'}
973 &lt;/ul&gt;
974 &lt;/div&gt;
975 &lt;/section&gt;
976 {/if}
977{/if}
978
979&lt;footer class="contentFooter"&gt;
980 {hascontent}
981 &lt;nav class="contentFooterNavigation"&gt;
982 &lt;ul&gt;
983 {content}{event name='contentFooterNavigation'}{/content}
984 &lt;/ul&gt;
985 &lt;/nav&gt;
986 {/hascontent}
987&lt;/footer&gt;
988
989{include file='footer'}</code></pre></figure>
990
991<p>For now, the <code class="language-plaintext highlighter-rouge">person</code> template is still very empty and only shows the comments in the content area.
992The template code shown for comments is very generic and used in this form in many locations as it only sets the header of the comment list and the container <code class="language-plaintext highlighter-rouge">ul#personCommentList</code> element for the comments shown by <code class="language-plaintext highlighter-rouge">commentList</code> template.
993The <code class="language-plaintext highlighter-rouge">ul#personCommentList</code> elements has five additional <code class="language-plaintext highlighter-rouge">data-</code> attributes required by the JavaScript API for comments for loading more comments or creating new ones.
994The <code class="language-plaintext highlighter-rouge">commentListAddComment</code> template adds the WYSIWYG support.
995The attribute <code class="language-plaintext highlighter-rouge">wysiwygSelector</code> should be the id of the comment list <code class="language-plaintext highlighter-rouge">personCommentList</code> with an additional <code class="language-plaintext highlighter-rouge">AddComment</code> suffix.</p>
996
997<h3 id="pagexml"><code class="language-plaintext highlighter-rouge">page.xml</code></h3>
998
999<figure class="highlight"><pre><code class="language-xml" data-lang="xml"><span class="cp">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span>
1000<span class="nt">&lt;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/tornado/page.xsd"</span><span class="nt">&gt;</span>
1001 <span class="nt">&lt;import&gt;</span>
1002 <span class="nt">&lt;page</span> <span class="na">identifier=</span><span class="s">"com.woltlab.wcf.people.PersonList"</span><span class="nt">&gt;</span>
1003 <span class="nt">&lt;pageType&gt;</span>system<span class="nt">&lt;/pageType&gt;</span>
1004 <span class="nt">&lt;controller&gt;</span>wcf\page\PersonListPage<span class="nt">&lt;/controller&gt;</span>
1005 <span class="nt">&lt;name</span> <span class="na">language=</span><span class="s">"de"</span><span class="nt">&gt;</span>Personen-Liste<span class="nt">&lt;/name&gt;</span>
1006 <span class="nt">&lt;name</span> <span class="na">language=</span><span class="s">"en"</span><span class="nt">&gt;</span>Person List<span class="nt">&lt;/name&gt;</span>
1007
1008 <span class="nt">&lt;content</span> <span class="na">language=</span><span class="s">"de"</span><span class="nt">&gt;</span>
1009 <span class="nt">&lt;title&gt;</span>Personen<span class="nt">&lt;/title&gt;</span>
1010 <span class="nt">&lt;/content&gt;</span>
1011 <span class="nt">&lt;content</span> <span class="na">language=</span><span class="s">"en"</span><span class="nt">&gt;</span>
1012 <span class="nt">&lt;title&gt;</span>People<span class="nt">&lt;/title&gt;</span>
1013 <span class="nt">&lt;/content&gt;</span>
1014 <span class="nt">&lt;/page&gt;</span>
1015 <span class="nt">&lt;page</span> <span class="na">identifier=</span><span class="s">"com.woltlab.wcf.people.Person"</span><span class="nt">&gt;</span>
1016 <span class="nt">&lt;pageType&gt;</span>system<span class="nt">&lt;/pageType&gt;</span>
1017 <span class="nt">&lt;controller&gt;</span>wcf\page\PersonPage<span class="nt">&lt;/controller&gt;</span>
1018 <span class="nt">&lt;handler&gt;</span>wcf\system\page\handler\PersonPageHandler<span class="nt">&lt;/handler&gt;</span>
1019 <span class="nt">&lt;name</span> <span class="na">language=</span><span class="s">"de"</span><span class="nt">&gt;</span>Person<span class="nt">&lt;/name&gt;</span>
1020 <span class="nt">&lt;name</span> <span class="na">language=</span><span class="s">"en"</span><span class="nt">&gt;</span>Person<span class="nt">&lt;/name&gt;</span>
1021 <span class="nt">&lt;requireObjectID&gt;</span>1<span class="nt">&lt;/requireObjectID&gt;</span>
1022 <span class="nt">&lt;parent&gt;</span>com.woltlab.wcf.people.PersonList<span class="nt">&lt;/parent&gt;</span>
1023 <span class="nt">&lt;/page&gt;</span>
1024 <span class="nt">&lt;/import&gt;</span>
1025<span class="nt">&lt;/data&gt;</span></code></pre></figure>
1026
1027<p>The <code class="language-plaintext highlighter-rouge">page.xml</code> file has been extended for the new person page with identifier <code class="language-plaintext highlighter-rouge">com.woltlab.wcf.people.Person</code>.
1028Compared to the pre-existing <code class="language-plaintext highlighter-rouge">com.woltlab.wcf.people.PersonList</code> page, there are four differences:</p>
1029
1030<ol>
1031 <li>It has a <code class="language-plaintext highlighter-rouge">&lt;handler&gt;</code> element with a class name as value.
1032This aspect will be discussed in more detail in the next section.</li>
1033 <li>There are no <code class="language-plaintext highlighter-rouge">&lt;content&gt;</code> elements because, both, the title and the content of the page are dynamically generated in the template.</li>
1034 <li>The <code class="language-plaintext highlighter-rouge">&lt;requireObjectID&gt;</code> tells the system that this page requires an object id to properly work, in this case a valid person id.</li>
1035 <li>This page has a <code class="language-plaintext highlighter-rouge">&lt;parent&gt;</code> page, the person list page.
1036In general, the details page for any type of object that is listed on a different page has the list page as its parent.</li>
1037</ol>
1038
1039<h3 id="personpagehandler"><code class="language-plaintext highlighter-rouge">PersonPageHandler</code></h3>
1040
1041<figure class="highlight"><pre><code class="language-php" data-lang="php"><span class="cp">&lt;?php</span>
1042<span class="kn">namespace</span> <span class="nn">wcf\system\page\handler</span><span class="p">;</span>
1043<span class="kn">use</span> <span class="nn">wcf\data\page\Page</span><span class="p">;</span>
1044<span class="kn">use</span> <span class="nn">wcf\data\person\PersonList</span><span class="p">;</span>
1045<span class="kn">use</span> <span class="nn">wcf\data\user\online\UserOnline</span><span class="p">;</span>
1046<span class="kn">use</span> <span class="nn">wcf\system\cache\runtime\PersonRuntimeCache</span><span class="p">;</span>
1047<span class="kn">use</span> <span class="nn">wcf\system\database\util\PreparedStatementConditionBuilder</span><span class="p">;</span>
1048<span class="kn">use</span> <span class="nn">wcf\system\WCF</span><span class="p">;</span>
1049
1050<span class="cd">/**
1051 * Page handler implementation for person page.
1052 *
1053 * @author Matthias Schmidt
1054 * @copyright 2001-2019 WoltLab GmbH
1055 * @license GNU Lesser General Public License &lt;http://opensource.org/licenses/lgpl-license.php&gt;
1056 * @package WoltLabSuite\Core\System\Page\Handler
1057 */</span>
1058<span class="kd">class</span> <span class="nc">PersonPageHandler</span> <span class="k">extends</span> <span class="nx">AbstractLookupPageHandler</span> <span class="k">implements</span> <span class="nx">IOnlineLocationPageHandler</span> <span class="p">{</span>
1059 <span class="kn">use</span> <span class="nn">TOnlineLocationPageHandler</span><span class="p">;</span>
1060
1061 <span class="cd">/**
1062 * @inheritDoc
1063 */</span>
1064 <span class="k">public</span> <span class="k">function</span> <span class="nf">getLink</span><span class="p">(</span><span class="nv">$objectID</span><span class="p">)</span> <span class="p">{</span>
1065 <span class="k">return</span> <span class="nx">PersonRuntimeCache</span><span class="o">::</span><span class="na">getInstance</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">getObject</span><span class="p">(</span><span class="nv">$objectID</span><span class="p">)</span><span class="o">-&gt;</span><span class="na">getLink</span><span class="p">();</span>
1066 <span class="p">}</span>
1067
1068 <span class="cd">/**
1069 * Returns the textual description if a user is currently online viewing this page.
1070 *
1071 * @see IOnlineLocationPageHandler::getOnlineLocation()
1072 *
1073 * @param Page $page visited page
1074 * @param UserOnline $user user online object with request data
1075 * @return string
1076 */</span>
1077 <span class="k">public</span> <span class="k">function</span> <span class="nf">getOnlineLocation</span><span class="p">(</span><span class="nx">Page</span> <span class="nv">$page</span><span class="p">,</span> <span class="nx">UserOnline</span> <span class="nv">$user</span><span class="p">)</span> <span class="p">{</span>
1078 <span class="k">if</span> <span class="p">(</span><span class="nv">$user</span><span class="o">-&gt;</span><span class="na">pageObjectID</span> <span class="o">===</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span>
1079 <span class="k">return</span> <span class="s1">''</span><span class="p">;</span>
1080 <span class="p">}</span>
1081
1082 <span class="nv">$person</span> <span class="o">=</span> <span class="nx">PersonRuntimeCache</span><span class="o">::</span><span class="na">getInstance</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">getObject</span><span class="p">(</span><span class="nv">$user</span><span class="o">-&gt;</span><span class="na">pageObjectID</span><span class="p">);</span>
1083 <span class="k">if</span> <span class="p">(</span><span class="nv">$person</span> <span class="o">===</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span>
1084 <span class="k">return</span> <span class="s1">''</span><span class="p">;</span>
1085 <span class="p">}</span>
1086
1087 <span class="k">return</span> <span class="nx">WCF</span><span class="o">::</span><span class="na">getLanguage</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">getDynamicVariable</span><span class="p">(</span><span class="s1">'wcf.page.onlineLocation.'</span><span class="o">.</span><span class="nv">$page</span><span class="o">-&gt;</span><span class="na">identifier</span><span class="p">,</span> <span class="p">[</span><span class="s1">'person'</span> <span class="o">=&gt;</span> <span class="nv">$person</span><span class="p">]);</span>
1088 <span class="p">}</span>
1089
1090 <span class="cd">/**
1091 * @inheritDoc
1092 */</span>
1093 <span class="k">public</span> <span class="k">function</span> <span class="nf">isValid</span><span class="p">(</span><span class="nv">$objectID</span> <span class="o">=</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span>
1094 <span class="k">return</span> <span class="nx">PersonRuntimeCache</span><span class="o">::</span><span class="na">getInstance</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">getObject</span><span class="p">(</span><span class="nv">$objectID</span><span class="p">)</span> <span class="o">!==</span> <span class="kc">null</span><span class="p">;</span>
1095 <span class="p">}</span>
1096
1097 <span class="cd">/**
1098 * @inheritDoc
1099 */</span>
1100 <span class="k">public</span> <span class="k">function</span> <span class="nf">lookup</span><span class="p">(</span><span class="nv">$searchString</span><span class="p">)</span> <span class="p">{</span>
1101 <span class="nv">$conditionBuilder</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">PreparedStatementConditionBuilder</span><span class="p">(</span><span class="kc">false</span><span class="p">,</span> <span class="s1">'OR'</span><span class="p">);</span>
1102 <span class="nv">$conditionBuilder</span><span class="o">-&gt;</span><span class="na">add</span><span class="p">(</span><span class="s1">'person.firstName LIKE ?'</span><span class="p">,</span> <span class="p">[</span><span class="s1">'%'</span> <span class="o">.</span> <span class="nv">$searchString</span> <span class="o">.</span> <span class="s1">'%'</span><span class="p">]);</span>
1103 <span class="nv">$conditionBuilder</span><span class="o">-&gt;</span><span class="na">add</span><span class="p">(</span><span class="s1">'person.lastName LIKE ?'</span><span class="p">,</span> <span class="p">[</span><span class="s1">'%'</span> <span class="o">.</span> <span class="nv">$searchString</span> <span class="o">.</span> <span class="s1">'%'</span><span class="p">]);</span>
1104
1105 <span class="nv">$personList</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">PersonList</span><span class="p">();</span>
1106 <span class="nv">$personList</span><span class="o">-&gt;</span><span class="na">getConditionBuilder</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">add</span><span class="p">(</span><span class="nv">$conditionBuilder</span><span class="p">,</span> <span class="nv">$conditionBuilder</span><span class="o">-&gt;</span><span class="na">getParameters</span><span class="p">());</span>
1107 <span class="nv">$personList</span><span class="o">-&gt;</span><span class="na">readObjects</span><span class="p">();</span>
1108
1109 <span class="nv">$results</span> <span class="o">=</span> <span class="p">[];</span>
1110 <span class="k">foreach</span> <span class="p">(</span><span class="nv">$personList</span> <span class="k">as</span> <span class="nv">$person</span><span class="p">)</span> <span class="p">{</span>
1111 <span class="nv">$results</span><span class="p">[]</span> <span class="o">=</span> <span class="p">[</span>
1112 <span class="s1">'image'</span> <span class="o">=&gt;</span> <span class="s1">'fa-user'</span><span class="p">,</span>
1113 <span class="s1">'link'</span> <span class="o">=&gt;</span> <span class="nv">$person</span><span class="o">-&gt;</span><span class="na">getLink</span><span class="p">(),</span>
1114 <span class="s1">'objectID'</span> <span class="o">=&gt;</span> <span class="nv">$person</span><span class="o">-&gt;</span><span class="na">personID</span><span class="p">,</span>
1115 <span class="s1">'title'</span> <span class="o">=&gt;</span> <span class="nv">$person</span><span class="o">-&gt;</span><span class="na">getTitle</span><span class="p">()</span>
1116 <span class="p">];</span>
1117 <span class="p">}</span>
1118
1119 <span class="k">return</span> <span class="nv">$results</span><span class="p">;</span>
1120 <span class="p">}</span>
1121
1122 <span class="cd">/**
1123 * Prepares fetching all necessary data for the textual description if a user is currently online
1124 * viewing this page.
1125 *
1126 * @see IOnlineLocationPageHandler::prepareOnlineLocation()
1127 *
1128 * @param Page $page visited page
1129 * @param UserOnline $user user online object with request data
1130 */</span>
1131 <span class="k">public</span> <span class="k">function</span> <span class="nf">prepareOnlineLocation</span><span class="p">(</span><span class="cd">/** @noinspection PhpUnusedParameterInspection */</span><span class="nx">Page</span> <span class="nv">$page</span><span class="p">,</span> <span class="nx">UserOnline</span> <span class="nv">$user</span><span class="p">)</span> <span class="p">{</span>
1132 <span class="k">if</span> <span class="p">(</span><span class="nv">$user</span><span class="o">-&gt;</span><span class="na">pageObjectID</span> <span class="o">!==</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span>
1133 <span class="nx">PersonRuntimeCache</span><span class="o">::</span><span class="na">getInstance</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">cacheObjectID</span><span class="p">(</span><span class="nv">$user</span><span class="o">-&gt;</span><span class="na">pageObjectID</span><span class="p">);</span>
1134 <span class="p">}</span>
1135 <span class="p">}</span>
1136<span class="p">}</span></code></pre></figure>
1137
1138<p>Like any page handler, the <code class="language-plaintext highlighter-rouge">PersonPageHandler</code> class has to implement the <a href="https://github.com/WoltLab/WCF/blob/master/wcfsetup/install/files/lib/system/page/handler/IMenuPageHandler.class.php">IMenuPageHandler</a> interface, which should be done by extending the <a href="https://github.com/WoltLab/WCF/blob/master/wcfsetup/install/files/lib/system/page/handler/AbstractMenuPageHandler.class.php">AbstractMenuPageHandler</a> class.
1139As we want administrators to link to specific people in menus, for example, we have to also implement the <a href="https://github.com/WoltLab/WCF/blob/master/wcfsetup/install/files/lib/system/page/handler/ILookupPageHandler.class.php">ILookupPageHandler</a> interface by extending the <a href="https://github.com/WoltLab/WCF/blob/master/wcfsetup/install/files/lib/system/page/handler/AbstractLookupPageHandler.class.php">AbstractLookupPageHandler</a> class.</p>
1140
1141<p>For the <code class="language-plaintext highlighter-rouge">ILookupPageHandler</code> interface, we need to implement three methods:</p>
1142
1143<ol>
1144 <li><code class="language-plaintext highlighter-rouge">getLink($objectID)</code> returns the link to the person page with the given id.
1145In this case, we simply delegate this method call to the <code class="language-plaintext highlighter-rouge">Person</code> object returned by <code class="language-plaintext highlighter-rouge">PersonRuntimeCache::getObject()</code>.</li>
1146 <li><code class="language-plaintext highlighter-rouge">isValid($objectID)</code> returns <code class="language-plaintext highlighter-rouge">true</code> if the person with the given id exists, otherwise <code class="language-plaintext highlighter-rouge">false</code>.
1147Here, we use <code class="language-plaintext highlighter-rouge">PersonRuntimeCache::getObject()</code> again and check if the return value is <code class="language-plaintext highlighter-rouge">null</code>, which is the case for non-existing people.</li>
1148 <li><code class="language-plaintext highlighter-rouge">lookup($searchString)</code> is used when setting up an internal link and when searching for the linked person.
1149This method simply searches the first and last name of the people and returns an array with the person data.
1150While the <code class="language-plaintext highlighter-rouge">link</code>, the <code class="language-plaintext highlighter-rouge">objectID</code>, and the <code class="language-plaintext highlighter-rouge">title</code> element are self-explanatory, the <code class="language-plaintext highlighter-rouge">image</code> element can either contain an HTML <code class="language-plaintext highlighter-rouge">&lt;img&gt;</code> tag, which is displayed next to the search result (WoltLab Suite uses an image tag for users showing their avatar, for example), or a FontAwesome icon class (starting with <code class="language-plaintext highlighter-rouge">fa-</code>).</li>
1151</ol>
1152
1153<p>Additionally, the class also implements <a href="https://github.com/WoltLab/WCF/blob/master/wcfsetup/install/files/lib/system/page/handler/IOnlineLocationPageHandler.class.php">IOnlineLocationPageHandler</a> which is used to determine the online location of users.
1154To ensure upwards-compatibility if the <code class="language-plaintext highlighter-rouge">IOnlineLocationPageHandler</code> interface changes, the <a href="https://github.com/WoltLab/WCF/blob/master/wcfsetup/install/files/lib/system/page/handler/TOnlineLocationPageHandler.class.php">TOnlineLocationPageHandler</a> trait is used.
1155The <code class="language-plaintext highlighter-rouge">IOnlineLocationPageHandler</code> interface requires two methods to be implemented:</p>
1156
1157<ol>
1158 <li><code class="language-plaintext highlighter-rouge">getOnlineLocation(Page $page, UserOnline $user)</code> returns the textual description of the online location.
1159The language item for the user online locations should use the pattern <code class="language-plaintext highlighter-rouge">wcf.page.onlineLocation.{page identifier}</code>.</li>
1160 <li><code class="language-plaintext highlighter-rouge">prepareOnlineLocation(Page $page, UserOnline $user)</code> is called for each user online before the <code class="language-plaintext highlighter-rouge">getOnlineLocation()</code> calls.
1161In this case, calling <code class="language-plaintext highlighter-rouge">prepareOnlineLocation()</code> first enables us to add all relevant person ids to the person runtime cache so that for all <code class="language-plaintext highlighter-rouge">getOnlineLocation()</code> calls combined, only one database query is necessary to fetch all person objects.</li>
1162</ol>
1163
1164<hr />
1165
1166<p>This concludes the third part of our tutorial series after which each person has a dedicated page on which people can comment on the person.</p>
1167
1168<p>The complete source code of this part can be found on <a href="https://github.com/WoltLab/woltlab.github.io/tree/master/_includes/tutorial/tutorial-series/part-3">GitHub</a>.</p>
1169
1170
1171
1172 <div class="tags">
1173
1174 </div>
1175
1176
1177
1178</div>
1179
1180 </div>
1181 </div>
1182 </div>
1183
1184 <div class="footerBox">
1185 <div class="container">
1186 <div class="footerBoxLeft">
1187
1188 <a target="_blank" href="https://github.com/woltlab/woltlab.github.io/blob/master/pages/tutorial/tutorial-series/tutorial_tutorial-series_part-3-person-page-and-comments.md" class="btn btn-default githubEditButton no_icon" role="button"><i class="fa fa-github fa-lg"></i> Edit on GitHub</a>
e2f8eee7 1189 <p>Site last generated: Mar 5, 2021</p>
d9cdc0cc
TD
1190 </div>
1191 <div class="footerBoxRight">
e2f8eee7 1192 <a class="no_icon" href="https://www.woltlab.com"><img src="https://docs.woltlab.com/5.3/images/woltlab-black.png" srcset="https://docs.woltlab.com/5.3/images/woltlab-black@2x.png 2x" height="40" width="204" alt=""></a>
d9cdc0cc
TD
1193 </div>
1194 </div>
1195 </div>
1196
1197 <div class="pageFooter">
1198 <div class="container">
1199 &copy; 2001 ‐ 2021 <a class="no_icon" href="https://www.woltlab.com">WoltLab GmbH</a>. All rights reserved. | <a class="no_icon" href="https://www.woltlab.com/legal-notice/">Legal Notice</a> | <a class="no_icon" href="https://www.woltlab.com/privacy-policy/">Privacy Policy</a>
1200 </div>
1201 </div>
1202</body>
1203
1204</html>