Show last authors
1 {{box cssClass="floatinginfobox" title="**Contents**"}}
2 {{toc/}}
3 {{/box}}
4
5 This tutorial will show you how to build a Person Manager application.  It's very similar to the [[Documentation.DevGuide.Tutorials.FAQTutorial.FAQTutorialManual]] tutorial. One difference is that the FAQ tutorial involves a very trivial object: a FAQ object contains just two things: a "question" and an "answer", while this example uses a Person object that has more properties ("name", "age", "sex", etc.) .This is a very simple application that makes use of XWiki's [[classes, properties, and objects>>platform:DevGuide.DataModel||anchor="HXWikiClasses2CObjects2CandProperties"]]. It also uses a technique that you may frequently use as the basis for several different kinds of applications.
6
7 Also, this tutorial explains things a little differently than the [[FAQ Tutorial>>Documentation.DevGuide.Tutorials.FAQTutorial.FAQTutorialManual]]. Here, we gloss over a few things like Templates, and cover other things in more detail, like properties. Also, this page sometimes shows other ways to do things: using SOLR instead of XWQL, using a template instead of a custom form, using custom code rather than a livetable. If something here doesn't make sense to you, try going through the FAQ tutorial and maybe it will make more sense.
8
9 = Prerequisites for following the tutorial =
10
11 You should have [[installed XWiki>>platform:AdminGuide.Installation]] and have a [[basic understanding of how to use it>>platform:Features.WebHome]].
12
13 All through this tutorial you should refer to the [[XWiki Data Model>>platform:DevGuide.DataModel]] for information on XWiki's data model. You might also use the [[XWiki Scripting Guide>>platform:DevGuide.Scripting]] to get you started with scripting in XWiki and manipulating XWiki objects. In addition, this tutorial will introduce the concepts of Authoring Templates and Page Design Sheets, patterns that you will find particularly useful in creating XWiki applications. Completing this tutorial is a recommended prerequisite for anyone who wants to build custom applications on the XWiki engine. And by "custom application", we really mean any non-trivial, non-static web application. You should be able to build anything from a simple one-page form to accept online orders for your pizza parlor to your own competitor to TurboTax. The focus here, of course, is to build just the "front-end" of the website, and we don't cover "server-side" things like how to get that tax information sent to the IRS.
14
15 {{warning}}
16 Make sure that your user is an [[Advanced user>>platform:Features.PageEditing||anchor="HAdvancedMode"]] before following this tutorial since you'll need for example to use the wiki editor (##Wiki > Edit## menu).
17 {{/warning}}
18
19 = Application Overview =
20
21 The Person Manager application will allow users to create a "Person object" by entering data (name, age, sex, etc) into a simple form and then submitting the form. Let's sketch out what roughly what those two pages should look like on a "napkin", using [[Balsamiq>>https://balsamiq.com/]]:
22
23 {{image reference="personDialog.PNG" width="650px" caption="A Page For Creating a Person"/}}
24
25 Our page won't look exactly like that, but the point is that a website user can create a Person by filling out a "form" page like this.
26
27 Note all the various types of "widgets" shown here:
28
29 * "name" is a single-line text field
30 * "email" is also a single-line text field, but we'd like it to be validated (e.g. give an error if it doesn't have a "@" in it)
31 * "address" is a multi-line text field
32 * "phone" is a single-line text field (perhaps some validation here, too)
33 * "sex" is a drop-down list
34 * "married" is a checkbox: the only allowed values are "true" and "false"
35 * "image" is actually the name of some image file, but we actually display the image itself. Nice!
36 * "age" is Number field, which looks like a single-line text field, but has validation.
37 * "related people" is one more more links to other web pages. Very nice!
38
39 The Person then appears in a table with all other Person objects that have been previously created. Users can click on the Person in the table to see all the information about the Person. He may also edit that information or delete the Person. The table might look something like this:
40
41 {{image reference="personTable.PNG" width="650px" caption="A Page With a Table of Person Objects"/}}
42
43 When the user clicks on a row in the table, he will get a page that shows the information about the Person, which will look similar to the "Create Person" page, but without the ability to change anything.
44
45 == Objects Overview And Terminology ==
46
47 Next, let's summarize the terminology for "Objects". For full details, see [[Data Model>>https://www.xwiki.org/xwiki/bin/view/Documentation/DevGuide/DataModel/#HXWikiClasses2CObjects2CandProperties]]. There is nothing fancy happening here, but it's important to get our terminology straight.
48
49 A Person is an example of some "Object" or "**class**". We will use XWiki to define the "**properties**" in a "Person" class. For example, we will say that there's a property called "name" of type "String". There's also a property called "age" of type "Number", and an "address" property that's type "TextArea" (a string that can be multiple lines).
50
51 When a user creates a new Person, we call that an "**instance**" of the "class". So we might say something like "I've created an instance of the Person class, with name 'Joe Smith'". And we would say that our table shows all the instances of the Person class. And instances can not only be created, but also edited or deleted.
52
53 We, the creators of the website, define the "Person" class. We define that once, and we're done. Our users use our website to create, edit, and delete instances of our Person class.
54
55 == Overview Of What We Will Do ==
56
57 In this tutorial, we'll do the following steps:
58
59 * Define our Person class, using the XWiki "Data Types" page.
60 * Specify the properties of our Person class, using the XWiki "Class Editor" page.
61 * Define how a Person instance should be displayed, by creating a "Person Sheet" page.
62 * Create a Template and a Template Provider (whatever they are) for our Person class.
63 * Create a web page that displays a table of Person instances.
64 * Create several example pages, each containing a Person instance.
65
66 Note that we don't need to define a page for creating or editing a Person, just a page for *displaying* a Person. XWiki will automatically do that for us!
67
68 Once we are done with these steps, our application will be finished. A user of our website can see a page containing the table of Person objects, view the page for an existing Person, add a new Person, edit an existing Person, or delete a Person.
69
70 = Go to the Special "Data Types" Page =
71
72 The "Data Types" page is a special XWiki page that lets us define classes like "Person". This page is actually hidden by default. To be "unhide" it, go to your profile page, select the Preferences tab, edit the page and choose to view Hidden Documents.
73
74 To find the "Data Types" page, enter "D" in the "Search" field. This should return a document titled "Data Types".
75
76 = Create the Person Class =
77
78 * On the "Data Types" page, under the heading "Create a new data type", in the "Title" field, enter ##Person##:(((
79 {{image reference="personClass.PNG" width="650px"/}}
80 )))
81 * As you can see in the Breadcrumb below the new page will be created at location ##XWiki > Person##. In practice the "Data Types" page will automatically prefix the page name with ##Class## (you could also enter ##PersonClass## as the page name directly).
82 * Now it would be nice to have it created in a new location such as ##PersonSpace > Person Class##. Since the ##PersonSpace## parent doesn't exist we cannot use the Tree picker button. Thus click the Pencil button as shown in the following image and replace ##XWiki## by ##PersonSpace##.(((
83 {{image reference="personLocation.PNG" width="650px"/}}
84 )))
85 * XWiki has now created a "**space**" called PersonSpace. A "space" is a directory (or "folder") where pages live. All of our pages will go in this space.
86 * In technical terms you're creating a page named ##PersonClass## (with a title of "Person Class") located in a space called ##PersonSpace## and thus the technical reference for the page is ##PersonSpace.PersonClass##.
87 * Click the "Create this Class" button. You should then see a page with the following content:(((
88 {{code language="none"}}
89 called
90 {{velocity}}
91 ## Replace the default space with the space where you want your documents to be created.
92 ## Replace the default parent with the one of your choice and save the document.
93 ##
94 #set($defaultSpace = $doc.space)
95 #set($defaultParent = $doc.fullName)
96 {{/velocity}}
97 {{/code}}
98 )))
99
100 In this code, change "$doc.space" to the name of the space where you want your pages to be created: "PersonSpace".
101 The line of code should look like this:
102
103 {{code language="none"}}
104 #set($defaultSpace = 'PersonSpace')
105 {{/code}}
106
107 You can also change the default parent of the new Person documents that are going to be created. To do so, replace the "$defaultParent" variable with the name of your document.
108 The line of code should look like this:
109
110 {{code language="none"}}
111 #set($defaultParent = 'PersonSpace.WebHome')
112 {{/code}}
113
114 The ".WebHome" here is the XWiki naming convention for a "non-terminal" page (a page with children).
115 Click the "Save & View" button. The class is now created and you should be looking at a page titled "Person Class" that looks like this:
116
117 {{image reference="newPersonClass.PNG" width="650px"/}}
118
119 = Add Properties to the Class =
120
121 Under the page title, you should see the words "The class does not have any properties yet. You can use the //__class editor__// to define them." Click on that link.
122 Now, we need to specify all the properties of a Person. Let's have the following properties:
123
124 (% style="width:50%" %)
125 |=Property Name|=Property Type
126 |name|String
127 |email|EMail
128 |address|TextArea
129 |phone|String
130 |sex|static list
131 |married|Boolean
132 |image|Image
133 |age|Number
134 |relatedPeople|Page (Multiple)
135
136 Follow these steps to define our properties of the Person class:
137
138 * Enter the text //name// in the "name" field
139 * Choose "String" for the type of the property and then click on "Add". By using a String type, when a user goes to enter the //name// of a new Person, he will be prompted with a single-line text field.(((
140 {{image reference="name.PNG" width="650px"/}}
141 )))
142 * Click on the "+" icon to expand the options for the newly created property
143 * Change the value of the "Pretty Name" field to "Name"(capital N). With this done, the user sees the label "Name" rather than "name" when prompted for the name of a Person. This doesn't make a huge difference for this property, but when it comes to the property with the name "relatedPeople", it's nice to show the user something a little more friendy like "Related People". Also, you could later decide to change that label without actually renaming the property (and thereby probably breaking something).
144 * Now repeat this to add each of the properties shown in the table above.
145 ** Note that the "EMail" type is like a String, except that it has a "Validation Expression" (e.g. to make sure it has an "@" character).
146 ** If we wanted to, we could add a "Validation Expression" to the "phone" property to make sure it's in a particular format.
147 ** For the "sex" property, in the "Display Type" field, enter "Select". This will cause the user to see a drop-down menu.
148 ** As we define the "sex" property as type "static list", we specify the values for the field like this:(((
149 {{image reference="staticList.PNG" width="650px"/}}
150 )))
151 ** Note that there is no "Image" type. That's unfortunate. Let's just define it as a String here, and deal with that later.
152 ** Note that the "size" of our "age" field is 30 digits. People rarely live longer than 999 years, so feel free to change that to 3.
153 ** For our "relatedPeople" property, we want to allow multiple values, not just one. So find the "Multi Select" checkbox and check it.
154 * When you are done, you should see all your properties like this:(((
155 {{image reference="properties.PNG" width="650px"/}}
156 )))
157 * When you are done adding the properties, click the "Save & View" button
158
159 = Create the Page Design Sheet =
160
161 Next, we will create a "Page Design Sheet" to specify what a Person should look like when displayed on a page.
162
163 * After the previous step you are now on the PersonClass page which should look like this:(((
164 {{image reference="personClass2.PNG" width="650px"/}}
165 )))
166 * Click the first button ("Create the document sheet") to create the document sheet (the Page Design Sheet).
167 * You should see a warning message with the text "The sheet is not bound to the class so it won't be applied automatically when a page that has an object of this class is displayed". Click the "Bind the sheet to the class" link that appears after the text. Basically, this ties the Person Class to the Person Sheet.
168 * Now click on "View the sheet document". This takes you to the ##PersonSpace.PersonSheet## page which you can edit in wiki mode and see its default content. This content is Velocity code which simply goes through all the Person properties and displays each one. For example, it will see that our Person class has a "married" property of type "Boolean", and will show a checkbox with a label of "married" (or perhaps "Married" if we specified that as our "pretty name" for the property). See [[Documentation.DevGuide.Tutorials.FAQTutorial.FAQTutorialManual]] for more details about this code. This code is actually very close to working as-is. The only thing that would be ugly is that our "image" property would display as just a String, whereas we probably want to display the image itself, not some URL.
169
170 * This code is fine for now, so click "Save & View"
171
172 = Create the Authoring Template =
173
174 * Navigate back to the ##PersonSpace.PersonClass## document (you can use the arrows in the breadcrumb to do so).
175 * Click on the "Create the document template" button. The Authoring Template will be automatically created.
176
177 Now we need to associate the prototype object with this document to turn it into a true authoring template:
178
179 * If you're on the template page, navigate back to the ##PersonSpace.PersonClass## document.
180 * At the bottom of the page, look for the following warning message: "The template does not contain an object of type PersonClass. Add a Person object to the template »."
181 * Click on "Add a Person object to the template »":(((
182 {{image reference="personClass3.PNG" width="650px"/}}
183 )))
184
185 Next, we want to remove the title for the newly created template:
186
187 * Navigate to the ##PersonSpace.PersonTemplate## document (you can click on the "View the template page (PersonSpace / Person Template)" link for doing that for example.
188 * Edit this document in Wiki mode
189 * Inside the Title field you have "Person Template" written -> delete this text
190 * Save & View
191
192 This step is needed so that all of our future entries don't have "Person Template" as their title.
193
194 Congratulations: you just created an Authoring Template! You're almost done now.
195
196 = Create the Template Provider =
197
198 After the template was created and the object was added, a new section appears with a button to create a template provider to use the existing template. Click that button.
199
200 (((
201 {{image reference="personClass4.PNG" width="650px"/}}
202 )))
203
204 = Create a Home Page for the Person Manager application =
205
206 Whew! Take a deep breath, grab a cup of coffee, and pat yourself on the back. We are now finished defining our Person class and all its properties, and those mysterious Templates. Now it's time to create some web pages. Recall that we only have two pages to create:
207
208 * A "main" page that contains a table of Person objects.
209 * A "Person" page that displays a single Person
210 * (We don't need to create a "form" page for creating a new Person or edit an existing person - XWiki does that for us)
211
212 Our "main" page will be the ##PersonSpace.WebHome## page.
213
214 * Click on "PersonSpace" in the breadcrumb to navigate to ##PersonSpace.WebHome## and notice that the page doesn't exist yet:
215 {{image reference="pageDoesntExist.PNG" width="650px"/}}
216 * Edit it in wiki mode by clicking on the "edit this page" link.
217 * Type in the title "People". Note that a page's **title** (what the user sees, e.g. "People") does not have to match the page's **name** (the unique id of the page, part of the URL e.g. "PersonSpace.WebHome")
218
219 == Displaying Existing Person Entries In a Table ==
220
221 You have 2 main options when it comes to displaying existing Person entries:
222
223 1. Use the livetable component
224 1. Write custom code in order to display them in a table
225
226 We will only cover the "custom code" option here, because it's actually very easy to write a little code to display the table the way we want to. See the "Using the Livetable component" section of the [[Documentation.DevGuide.Tutorials.FAQTutorial.FAQTutorialManual]] page for instructions to use a "livetable" instead.
227
228 To create our table, we need to think about Objects, not web pages. As people use our application, they create new instances of our Person class - they create Object instances. Let's say there have been three "Person" instances created so far. That means there will be three rows in our table. But how do we write code for this table? We will need to "query the XWiki database" - essentially tell XWiki "get me all the instances of the PersonClass that exist". XWiki provides [[several different ways>>https://extensions.xwiki.org/xwiki/bin/view/Extension/Query%20Module]] to do this query:
229
230 * XWiki Query Language (XWQL)
231 * Hibernate Query Language (HQL)
232 * Solr Query Language (SOLR)
233
234 The [[Documentation.DevGuide.Tutorials.FAQTutorial.FAQTutorialManual]] page tells you how to use XWQL, but here, let's use [[SOLR>>https://lucene.apache.org/solr/]]. Why is SOLR "better" than XWQL? It's a bit of a standard, it's very well documented, very flexible and fast. It's also pretty simple.
235
236 Regardless of which of these techniques we use to query, we will be writing code in the [[Velocity Template Language>>https://velocity.apache.org/engine/1.7/user-guide.html]].
237
238 === Using custom code ===
239
240 We will need to write code to do the following:
241
242 * Display a header above the table that says "People"
243 * Perform a SOLR query to get all documents (i.e. pages) containing an instance of PersonClass, with a "name" property of any value.
244 * Let's limit the number of results to 1000 because the default for SOLR is 10 and that's too low.
245 * Let's use XWiki syntax to create a table with three columns: Name, Email, and Phone (note that we don't bother to show all properties of a Person as columns in our table, but we could if we wanted to).
246 * The query will return multiple Documents. Each Document contains all the data on the web page. It's similar to the **[[DOM>>https://en.wikipedia.org/wiki/Document_Object_Model]]** that many developers know about. Loop through each Document, doing the following:
247 ** find the PersonClass instance on the page. Set a variable called $object to that.
248 ** get the "name" property from the instance and display that in the first column of the table.
249 ** get the "email" property from the instance and display that in the second column of the table.
250 ** get the "phone" property from the instance and display that in the third column of the table.
251
252 Here is the resulting code:
253
254 {{code language="none"}}
255 {{velocity}}
256 = People =
257 #set ($className = 'PersonSpace.PersonClass')
258 #set ($attr = 'name')
259 #set ($queryStatement = "property.$className.$attr:*")
260 #set ($query = $services.query.createQuery($queryStatement, 'solr'))
261 #set ($discard = $query.bindValue('rows', '1000'))
262 #set ($searchResponse = $query.execute()[0])
263 |=Name|=Email|=Phone
264 #foreach ($searchResult in $searchResponse.results)
265 #set ($documentReference = $services.solr.resolveDocument($searchResult))
266 #set ($d = $xwiki.getDocument($documentReference))
267 #set ($object = $d.getObject("$className"))
268 #if ($object.getProperty('name').getValue() != '')
269 |$object.getProperty('name').getValue()##
270 |$object.getProperty('email').getValue()##
271 |$object.getProperty('phone').getValue()
272 #end
273 #end
274 {{/velocity}}
275 {{/code}}
276
277 Some things to note about this code:
278
279 * The lines starting with "#" are Velocity
280 * Once all of this is processed by the XWiki engine, the result will be XWiki syntax for a table like this:(((
281 ~= People =
282 ~|=Name|=Email|=Phone
283 ~|Joe Smith|joe@gmail.com|999-555-1212
284 )))
285 * The "~#~#" characters at the end of the lines showing rows in the table are required because XWiki wants all table data for a row to be on a single line.
286
287 You may be thinking "How on earth would I possibly know to write that code? What is all that stuff?" Great questions! We'll cover that in the next section, but for now:
288
289 * Copy this code and paste it as Wiki content inside ##PersonSpace.WebHome##
290 * Click "Save & View"
291 * New Person entries will now be displayed on the page once you create them.
292
293 At this point, your ##PersonSpace.WebHome## page will just display as an empty table because no instances of PersonClass have been created yet.
294
295 == Overview of XWiki Scripting ==
296
297 In this section, we'll get you started on scripting in XWiki by explaining some of the code shown in the previous section. If you don't care about these details and just want to see something on your Person Table, just skip this section.
298
299 For details about writing scripts like this, see [[this guide>>https://www.xwiki.org/xwiki/bin/view/Documentation/DevGuide/Scripting/APIGuide]].
300
301 Let's look closely at the code in the previous section. This line:
302 ~{~{velocity}}
303 is simply telling XWiki that everything here is part of a Velocity script. As such, we can just put in some any text we want (we want [[XWiki Syntax>>Documentation.UserGuide.Features.XWikiSyntax.WebHome]]). But we can also have lines of Velocity that start with "#".
304
305 This line...
306
307 >= People=
308
309 ...is just XWiki syntax saying "Give show me some "header" text with a big, bold font, that says "People".
310
311 These lines...
312
313 >
314
315 (((
316 #set ($className = 'PersonSpace.PersonClass')
317 #set ($attr = 'name')
318 #set ($queryStatement = "property.$className.$attr:*"
319 )))
320
321 ...are just Velocity code setting some variables. Plain text in single quotes, double quotes needed when the text contains references to variables.
322
323 Now we come to this line:
324
325 >#set ($query = $services.query.createQuery($queryStatement, 'solr'))
326
327 We are calling some "createQuery()" method (or "function") on some "$services.query" variable. That's odd, because this script never set any variable called "$services.query". This is a "special variable" that's automatically set for you by XWiki. The right side of [[XWiki Scripting API Reference>>https://www.xwiki.org/xwiki/bin/view/ScriptingDocumentation/]] contains a list of all these "special variables" that XWiki has set for us. Scroll down in that list and find "$services.query", and click on it. You'll come to a "javadoc" page that shows information about "Class QueryManagerScriptService", including a method called "createQuery()". This method takes two parameters: a "statement" and a "language". We passed in 'solr' for the "language", and that "you just have to know" that that's how XWiki has set things up.
328
329 Where can you learn about how to create a "SOLR statement"? I haven't found any good documentation. The [[SOLR Tuturial>>https://lucene.apache.org/solr/guide/8_5/solr-tutorial.html]] is way too complicated.
330 The XWiki-specific [[SOLR Schema>>https://design.xwiki.org/xwiki/bin/view/Design/SolrSchema]] page is very much for XWiki developers, not users, but I found it useful. The main thing here is to understand that we can use this SOLR statement...
331
332 > property.PersonSpace.PersonClass.name:*
333
334 ..to query for all the instances of PersonClass in the PersonSpace space that have a "name" property set to anything.
335
336 With this line...
337
338 >#set ($discard = $query.bindValue('rows', '1000'))
339
340 ...we add to our SOLR query the fact that we only want to get a maximum of 1000 results. We save the value returned in a variable called "$discard", but never use that value. Then why save it? Because Velocity syntax does not have a way to simply "execute a statement", you have to "set a variable". Annoying, I know.
341
342 Next, we execute the SOLR query, get a list of returned values, but only care about the first returned value, and save that in a variable called "$searchResponse":
343
344 >#set ($searchResponse = $query.execute()[0])
345
346 ...but now what? The javadoc page for [[Query>>https://www.xwiki.org/xwiki/bin/view/ScriptingDocumentation/?url=http:%2F%2Fnexus.xwiki.org%2Fnexus%2Fservice%2Flocal%2Frepositories%2Fpublic%2Farchive%2Forg%2Fxwiki%2Fplatform%2Fxwiki-platform-query-manager%2F11.10.2%2Fxwiki-platform-query-manager-11.10.2-javadoc.jar%2F!%2Forg%2Fxwiki%2Fquery%2FQuery.html]] shows the execute() method returns a List of "<T>", but what are the details of T? What fields does this object have? Again, the SOLR documentation is not helpful, and the XWiki documentation on it is sparse. But [[this page>>https://extensions.xwiki.org/xwiki/bin/view/Extension/Solr%20Search%20Query%20API]] at least shows us that there is a "results" field, which we can loop through. So we do:
347
348 (((
349 #foreach ($searchResult in $searchResponse.results)
350 #set ($documentReference = $services.solr.resolveDocument($searchResult))
351 #set ($d = $xwiki.getDocument($documentReference))
352 )))
353
354 We call "resolveDocument()" on a "special" #services.solr variable to get a [[DocumentReference>>https://www.xwiki.org/xwiki/bin/view/ScriptingDocumentation/?url=http:%2F%2Fnexus.xwiki.org%2Fnexus%2Fservice%2Flocal%2Frepositories%2Fpublic%2Farchive%2Forg%2Fxwiki%2Fplatform%2Fxwiki-platform-model%2F11.10.2%2Fxwiki-platform-model-11.10.2-javadoc.jar%2F!%2Forg%2Fxwiki%2Fmodel%2Freference%2FDocumentReference.html]] object, and call getDocument() on that to get a[[Document>>https://www.xwiki.org/xwiki/bin/view/ScriptingDocumentation/?url=http:%2F%2Fnexus.xwiki.org%2Fnexus%2Fservice%2Flocal%2Frepositories%2Fpublic%2Farchive%2Forg%2Fxwiki%2Fplatform%2Fxwiki-platform-oldcore%2F11.10.2%2Fxwiki-platform-oldcore-11.10.2-javadoc.jar%2F!%2Fcom%2Fxpn%2Fxwiki%2Fapi%2FDocument.html]] object.
355
356 We did some hand-waving here, but at least now we know we're looping through the Document for each web page. We have this massive Document object that has what seems like hundreds of methods to choose from. For example, we can call the getTitle() method to get the title of the page. So this is very powerful. But in our case, all we care about is the Person instance on the page. We store that in a variable:
357
358 > #set ($object = $d.getObject("$className"))
359
360 And then we get the "name", "email", and "phone" properties of that object, and display them as columns in our table:
361
362 (((
363 |$object.getProperty('name').getValue()
364 |$object.getProperty('email').getValue()
365 |$object.getProperty('phone').getValue()
366 )))
367
368 In summary, our page uses Velocity code to create the XWiki syntax for a table. We do a SOLR query for all pages that have a Person instance that has a "name" property with any value. We execute the query and get back something that contains a list of results. We loop through those results, extracting first a DocumentReference (whatever that is), get a Document (like a DOM) from that, and then get the instance of PersonClass from that. We then output XWiki table syntax to display the "name", "email", and "phone" properties of that Person instance as the columns in a table.
369
370 We've learned a little XWiki syntax, Velocity syntax, SOLR syntax, learned to navigate through some XWiki javadoc pages. It wasn't easy or pretty, but we did it.
371
372 Finally, let's create a few Person instances so we can see them in our table.
373
374 == Creating new Person instances ==
375
376 There are 2 ways for you to let your users create new instances of our PersonClass:
377
378 1. Declare the Person as a template
379 1. Add a custom creation form
380
381 The [[Documentation.DevGuide.Tutorials.FAQTutorial.FAQTutorialManual]] page describes how to create a custom form if you want to do that. But the simpler way is to use a template, and so that's what we'll do. Remember earlier, on the Person Class page, we clicked on a button to create a template, and clicked on another button to create a "Template Provider"? That's all we needed to do! 
382
383 With that done, let's go ahead and create an instance of PersonClass. To be specific, we'll create a new page and add an instance of PersonClass to that page. Go to your PersonSpace.WebHome page (the one with the table), and click the "Create" button to create a child page. You will be prompted for a page title and page type. In the list of Types, under "Template" you should see "Person":
384 {{image reference="createPerson.PNG" width="650px"/}}
385
386 Fill in the person's name as the page title, choose the "Person" type, and click "Create."
387 You will then be prompted for all the information about your the Person instance that you want to create:
388 {{image reference="createPerson2.PNG" width="650px"/}}
389
390 Fill in all the values and press "Save & View".
391
392 Now go back to the PersonSpace.WebHome page, refresh your browser, and you should see your new instance as a row in the table.
393
394 Create a few more pages, each with a Person instance, and see them in the table, like this:
395 {{image reference="personTable3.PNG" width="650px"/}}
396
397 == Finishing Up The Table ==
398
399 Had we chosen to use the "livetable" feature, we'd be done. Clicking on a row in the table would take us to that user's page, an the table would also allow us to edit or delete a Person. But we chose to write "custom code" using Velocity and XWiki syntax to show our table. So now we need to make it so that clicking on the user's name in the table takes us to that user's page.
400
401 Go back to the PersonSpace.WebHome page and click "Edit" to modify it. Change the line that shows the Person's name to this:
402
403 ~|~[~[PersonSpace.$object.getProperty('name').getValue()]]
404
405 All we've done here is change the first column in our table to display a link rather than simple text. Press "Save & View" and verify that the links work.
406
407 TODO:
408
409 * Display the image
410 * get the "Related People" links working.
411
412 = Conclusion =
413
414 You've done something very special here, taking advantage of the [[Power Of XWiki>>https://propaganda-tactics.com/xwiki/bin/view/About/The%20Power%20of%20XWiki/]] by using data-driven web pages.
415
416 If you had "gone cheap" and naively created a static HTML (or Wiki) page for each Person, you would have had to "hard-code" the table, containing links to them all. And maintaining that table would be a nightmare, needing to update it each time a new Person is added or each time any of the data that it displays is changed on the other page. In addition, if you wanted to change the look of all those pages, you would likely have to change every one of them (even if they share common CSS).
417
418 On the other end of the spectrum, if you had decided on a typical three-tier high-end architecture, you'd have hired a whole team or even several teams. A "client" team would build pages using Javascript-plus-some-framework. And a "server" team would handle requests from the client to the server to store and retrieve the data. You'd have a database guy (or whole team) store the data in some relational database. Lots of time and energy would go into defining the (perhaps REST) API that the server provides and the client would use. And lots of effort would go into defining the database schema, database creation, and code (perhaps Hibernate or some other ORM tool) to get the data from the database into the server code and back again. All of this is easily 100x the amount of work that you need by using XWiki and doing what you just did.
419
420 Using XWiki in this way, the pages *are* the database, because they don't contain static HTML - they contain Objects - data. And those pages can be queried easily and flexibly. The client side here written in XWiki syntax, which is simpler than HTML, but you could also use HTML and CSS (and even Javascript) if you need more flexibility. The client also contains some simple Velocity code to do things like produce a table. There is no comparison between the simple Velocity code we've just seen and the equivalent Javascript-plus-the-latest-JS-framework code. And even this Velocity code can often be replaced by something even simpler (like "livetable").
421
422 Also note that what you've built is an *application*, not just a wiki. Your client side can get nearly as complex as you want. If you do, someday, want some shiny bells and whistles offered by the latest Javascript+framework, you can incorporate that later without too much pain.
423
424 In short, by using XWiki this way, you get nearly the flexibility and maintainability of a full three-tier architecture, while only investing nearly the same small effort needed to build the whole thing in static HTML.

Get Connected