Show last authors
1 {{box cssClass="floatinginfobox" title="**Contents**"}}
2 {{toc/}}
3 {{/box}}
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.
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.
9 = Prerequisites for following the tutorial =
11 You should have [[installed XWiki>>platform:AdminGuide.Installation]] and have a [[basic understanding of how to use it>>platform:Features.WebHome]].
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.
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}}
19 = Application Overview =
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>>]]:
23 {{image reference="personDialog.PNG" width="650px" caption="A Page For Creating a Person"/}}
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.
27 Note all the various types of "widgets" shown here:
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!
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:
41 {{image reference="personTable.PNG" width="650px" caption="A Page With a Table of Person Objects"/}}
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.
45 == Objects Overview And Terminology ==
47 Next, let's summarize the terminology for "Objects". For full details, see [[Data Model>>]]. There is nothing fancy happening here, but it's important to get our terminology straight.
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).
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.
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.
55 == Overview Of What We Will Do ==
57 In this tutorial, we'll do the following steps:
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.
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!
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.
70 = Go to the Special "Data Types" Page =
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.
74 To find the "Data Types" page, enter "D" in the "Search" field. This should return a document titled "Data Types".
76 = Create the Person Class =
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 = $
95 #set($defaultParent = $doc.fullName)
96 {{/velocity}}
97 {{/code}}
98 )))
100 In this code, change "$" to the name of the space where you want your pages to be created: "PersonSpace".
101 The line of code should look like this:
103 {{code language="none"}}
104 #set($defaultSpace = 'PersonSpace')
105 {{/code}}
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:
110 {{code language="none"}}
111 #set($defaultParent = 'PersonSpace.WebHome')
112 {{/code}}
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:
117 {{image reference="newPersonClass.PNG" width="650px"/}}
119 = Add Properties to the Class =
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:
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)
136 Follow these steps to define our properties of the Person class:
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
159 = Create the Page Design Sheet =
161 Next, we will create a "Page Design Sheet" to specify what a Person should look like when displayed on a page.
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.
170 * This code is fine for now, so click "Save & View"
172 = Create the Authoring Template =
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.
177 Now we need to associate the prototype object with this document to turn it into a true authoring template:
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 )))
185 Next, we want to remove the title for the newly created template:
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
192 This step is needed so that all of our future entries don't have "Person Template" as their title.
194 Congratulations: you just created an Authoring Template! You're almost done now.
196 = Create the Template Provider =
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.
200 (((
201 {{image reference="personClass4.PNG" width="650px"/}}
202 )))
204 = Create a Home Page for the Person Manager application =
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:
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)
212 Our "main" page will be the ##PersonSpace.WebHome## page.
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")
219 == Displaying Existing Person Entries In a Table ==
221 You have 2 main options when it comes to displaying existing Person entries:
223 1. Use the livetable component
224 1. Write custom code in order to display them in a table
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.
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>>]] to do this query:
230 * XWiki Query Language (XWQL)
231 * Hibernate Query Language (HQL)
232 * Solr Query Language (SOLR)
234 The [[Documentation.DevGuide.Tutorials.FAQTutorial.FAQTutorialManual]] page tells you how to use XWQL, but here, let's use [[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.
236 Regardless of which of these techniques we use to query, we will be writing code in the [[Velocity Template Language>>]].
238 === Using custom code ===
240 We will need to write code to do the following:
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>>]]** 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.
252 Here is the resulting code:
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}}
277 Some things to note about this code:
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||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.
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:
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.
293 At this point, your ##PersonSpace.WebHome## page will just display as an empty table because no instances of PersonClass have been created yet.
295 == Overview of XWiki Scripting ==
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.
299 For details about writing scripts like this, see [[this guide>>]].
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 "#".
305 This line...
307 >= People=
309 just XWiki syntax saying "Give show me some "header" text with a big, bold font, that says "People".
311 These lines...
313 >
315 (((
316 #set ($className = 'PersonSpace.PersonClass')
317 #set ($attr = 'name')
318 #set ($queryStatement = "property.$className.$attr:*"
319 )))
321 ...are just Velocity code setting some variables. Plain text in single quotes, double quotes needed when the text contains references to variables.
323 Now we come to this line:
325 >#set ($query = $services.query.createQuery($queryStatement, 'solr'))
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>>]] 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.
329 Where can you learn about how to create a "SOLR statement"? I haven't found any good documentation. The [[SOLR Tuturial>>]] is way too complicated.
330 The XWiki-specific [[SOLR Schema>>]] 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...
332 >*
334 query for all the instances of PersonClass in the PersonSpace space that have a "name" property set to anything.
336 With this line...
338 >#set ($discard = $query.bindValue('rows', '1000'))
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.
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":
344 >#set ($searchResponse = $query.execute()[0])
346 ...but now what? The javadoc page for [[Query>>!%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>>]] at least shows us that there is a "results" field, which we can loop through. So we do:
348 (((
349 #foreach ($searchResult in $searchResponse.results)
350 #set ($documentReference = $services.solr.resolveDocument($searchResult))
351 #set ($d = $xwiki.getDocument($documentReference))
352 )))
354 We call "resolveDocument()" on a "special" #services.solr variable to get a [[DocumentReference>>!%2Forg%2Fxwiki%2Fmodel%2Freference%2FDocumentReference.html]] object, and call getDocument() on that to get a[[Document>>!%2Fcom%2Fxpn%2Fxwiki%2Fapi%2FDocument.html]] object.
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:
358 > #set ($object = $d.getObject("$className"))
360 And then we get the "name", "email", and "phone" properties of that object, and display them as columns in our table:
362 (((
363 |$object.getProperty('name').getValue()
364 |$object.getProperty('email').getValue()
365 |$object.getProperty('phone').getValue()
366 )))
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.
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.
372 Finally, let's create a few Person instances so we can see them in our table.
374 == Creating new Person instances ==
376 There are 2 ways for you to let your users create new instances of our PersonClass:
378 1. Declare the Person as a template
379 1. Add a custom creation form
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! 
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"/}}
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"/}}
390 Fill in all the values and press "Save & View".
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.
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"/}}
397 == Finishing Up The Table ==
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.
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:
403 ~|~[~[PersonSpace.$object.getProperty('name').getValue()]]
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.
407 TODO:
409 * Display the image
410 * get the "Related People" links working.
412 = Conclusion =
414 You've done something very special here, taking advantage of the [[Power Of XWiki>>]] by using data-driven web pages.
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).
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.
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").
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.
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