This is an automated email from the ASF dual-hosted git repository.

danhaywood pushed a commit to branch CAUSEWAY-2873
in repository https://gitbox.apache.org/repos/asf/causeway.git

commit ebb1786b320dbcb542adf69e9a0e882d9f9632f3
Author: Dan Haywood <[email protected]>
AuthorDate: Sat May 25 14:46:45 2024 +0100

    CAUSEWAY-2873: 03-09
---
 .../petclinic/pages/030-petowner-entity.adoc       | 83 ++++++++++++++++------
 .../modules/petclinic/pages/100-todo.adoc          |  3 +
 2 files changed, 65 insertions(+), 21 deletions(-)

diff --git 
a/antora/components/tutorials/modules/petclinic/pages/030-petowner-entity.adoc 
b/antora/components/tutorials/modules/petclinic/pages/030-petowner-entity.adoc
index 383149ad87..529472a39d 100644
--- 
a/antora/components/tutorials/modules/petclinic/pages/030-petowner-entity.adoc
+++ 
b/antora/components/tutorials/modules/petclinic/pages/030-petowner-entity.adoc
@@ -517,11 +517,10 @@ public PetOwner updateName( ... ) { ... }
 Confirm that prompt is still inline.
 
 * Using a configuration property we can change the default for object actions 
to use a dialog rather than inline.
-+
-using the Spring boot profile trick from before:
+We'll use the "dev" profile introduced earlier:
 +
 [source,yaml]
-.application-custom.yaml
+.application-dev.yaml
 ----
 causeway:
   viewer:
@@ -529,7 +528,7 @@ causeway:
       prompt-style: dialog
 ----
 +
-Remember to activate this new profile (`-Dspring.profiles.active=dev,custom`) 
and confirm that the `updateName` prompt now uses a sidebar dialog.
+Remember to activate this new profile (`-Dspring.profiles.active=dev`) and 
confirm that the `updateName` prompt now uses a sidebar dialog.
 
 * We can overide the default dialog style for both service and object actions 
using further configuration properties.
 +
@@ -567,27 +566,21 @@ causeway:
 
 
 
-[#exercise-3-7-derived-name-property]
-== Ex 3.7: Derived name property
-
-The ``PetOwner``'s `firstName` and `lastName` properties are updated using the 
`updateName` action, but when the action's button is invoked, it only 
"replaces" the `lastName` property:
-
-image::Owner-updateName-prompt.png[width="400px"]
-
-In this exercise we'll improve the UI by introducing a derived `name` property 
and then hiding the `firstName` and `lastName`:
+[#exercise-3-9-derived-days-since-last-visit-property]
+== Ex 3.9: Derived 'days since last visit' property
 
-image::Owner-name.png[width="400px"]
+Not every property has to persisted, nor editable (indeed most properties are 
not editable).
 
-When `PetOwner#updateName` is invoked, the prompt we'll want see is:
+For example, it might be useful to calculate the number of days since the pet 
owner last visited; perhaps for marketing purposes.
 
-image::Owner-name-updated.png[width="400px"]
+In this exercise we'll see how easy it is to create such a derived property.
 
 
 === Solution
 
 [source,bash]
 ----
-git checkout tags/03-07-derived-PetOwner-name
+git checkout tags/03-09-derived-days-since-last-visit-property
 mvn clean install
 mvn -pl spring-boot:run
 ----
@@ -595,18 +588,66 @@ mvn -pl spring-boot:run
 
 === Tasks
 
+Locate the `PetOwner` class:
+
+* inject an instance of 
xref:refguide:applib:index/services/clock/ClockService.adoc[]:
++
+[source,java]
+.PetOwner.java
+----
+@Inject
+@Transient                  // <.>
+ClockService clockService;
+----
+<.> instructs JPA that this field is not persisted
++
+Note that Apache Causeway allows services to be injected into entities 
(actually, into pretty much any domain object)
 
-* Add `getName()` as the derived `name` property:
+* implement `getDaysSinceLastVisit()` method, calculating the number of days 
since "today".
 +
 [source,java]
 .PetOwner.java
 ----
-@Transient
-@PropertyLayout(fieldSetId = "name", sequence = "1")
-public String getName() {
-    return getFirstName() + " " + getLastName();
+@Property
+@PropertyLayout(fieldSetId = LayoutConstants.FieldSetId.DETAILS, sequence = 
"3.1")  // <.>
+public long getDaysSinceLastVisit() {
+    return Math.abs(ChronoUnit.DAYS.between(getLastVisit(), 
clockService.getClock().nowAsLocalDate()));
 }
 ----
+<.> positioned just after the `lastVisit` property
+
+*  update `PetOwner.columnOrder.txt` to indicate whether this new property 
should be rendered in standalone tables (returned from finder actions):
++
+[source,text]
+.PetOwner.columnOrder.txt
+----
+name
+telephoneNumber
+emailAddress
+daysSinceLastVisit
+#lastVisit
+#knownAs
+#attachment
+#notes
+#version
+----
+
+*  similarly, update `HomePageViewModel#petOwners.columnOrder.txt` to indicate 
whether this new property should be rendered on the home page:
++
+[source,text]
+.HomePageViewModel#petOwners.columnOrder.txt
+----
+name
+telephoneNumber
+emailAddress
+daysSinceLastVisit
+#lastVisit
+#knownAs
+#attachment
+#notes
+#version
+----
+
 
 * Hide the `lastName` and `firstName` properties, using 
`@Property(hidden=...)`.
 We can also remove the `@PropertyLayout` annotation.
diff --git a/antora/components/tutorials/modules/petclinic/pages/100-todo.adoc 
b/antora/components/tutorials/modules/petclinic/pages/100-todo.adoc
index b8603a2c3b..66bd2a3312 100644
--- a/antora/components/tutorials/modules/petclinic/pages/100-todo.adoc
+++ b/antora/components/tutorials/modules/petclinic/pages/100-todo.adoc
@@ -5,3 +5,6 @@ TODO: ideas for future steps:
 
 
 add validation for telephone number and email address.
+
+
+PetOwner#daysSinceLastVisit could be made into a mixin - eg if these marketing 
analytics were the responsibility of some other module.

Reply via email to