Vous êtes sur la page 1sur 290

PeopleSoft PeopleCode

Rel 8.50

Volume II - Student Guide

D60581GC10
1.0
September 2009
D62734
Copyright 2009, Oracle and/or its affiliates. All rights reserved.
This document contains proprietary information and is protected by copyright and other intellectual property laws. You may copy and
print this document solely for your own use in an Oracle training course. The document may not be modified or altered in any way.
Except where your use constitutes "fair use" under copyright law, you may not use, share, download, upload, copy, print, display,
perform, reproduce, publish, license, post, transmit, or distribute this document in whole or in part without the express authorization of
Oracle.
The information contained in this document is subject to change without notice. If you find any problems in the document, please report
them in writing to: Oracle University, 500 Oracle Parkway, Redwood Shores, California 94065 USA. This document is not warranted to
be error-free.
If this documentation is delivered to the United States Government or anyone using the documentation on behalf of the United States
Government, the following notice is applicable:
U.S. GOVERNMENT RIGHTS
The U.S. Government's rights to use, modify, reproduce, release, perform, display, or disclose these training materials are restricted by
the terms of the applicable Oracle license agreement and/or the applicable U.S. Government contract.
Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners.
Contents

Volume I
Lesson 1
Course Overview ............................................................................................................................................. 1
Agenda ............................................................................................................................................................... 2

Lesson 2
Technology Overview ...................................................................................................................................... 7
Describing PeopleCode ..................................................................................................................................... 8
Describing How PeopleCode is Used ............................................................................................................... 9
Describing Where PeopleCode is Used ........................................................................................................... 10
Finding Information About PeopleCode in PeopleBooks ............................................................................... 15
Describing PeopleCode Syntax Conventions .................................................................................................. 22

Lesson 3
Using PeopleCode Development Tools ........................................................................................................ 25
Describing the PeopleSoft Application Development Steps ........................................................................... 26
Activity 1: Reviewing the Application Development Process ........................................................................ 34
Locating PeopleCode Programs ...................................................................................................................... 39
Using the PeopleCode Editor .......................................................................................................................... 45
Activity 2: Using the PeopleCode Editor ........................................................................................................ 47
Using the PeopleCode Debugger .................................................................................................................... 52
Activity 3: Debugging a PeopleCode Program ............................................................................................... 53
Describing Additional Development Tools ..................................................................................................... 58

Lesson 4
Describing the Component Processor .......................................................................................................... 75
Tracing the Component Processor Flow ......................................................................................................... 77
Defining PeopleCode Events ........................................................................................................................... 86
Identifying PeopleCode Search Events .......................................................................................................... 89
Activity 4: Placing WinMessages in Search Events ....................................................................................... 90
Identifying PeopleCode Component Build Events ........................................................................................ 93
Activity 5: Placing WinMessages in Component Build Events ...................................................................... 95
Identifying Field Action Events ...................................................................................................................... 98
Identifying PeopleCode Row Action Events ................................................................................................... 99
Activity 6: Placing WinMessages in Row Action Events ............................................................................. 100
Identifying PeopleCode Save Action Events ................................................................................................ 103
Activity 7: Placing WinMessages in Save Action Events ............................................................................. 104
Describing Add Mode Processing ................................................................................................................. 107

iii
Contents

Describing Deferred Processing .................................................................................................................... 109


Activity 8: Examining Deferred Processing .................................................................................................. 113
Activity 9: Selecting the Correct Events ....................................................................................................... 117

Lesson 5
Writing PeopleCode Programs .................................................................................................................. 123
Writing PeopleCode Statements .................................................................................................................... 124
Explaining Conditional Statements ............................................................................................................... 130
Explaining Looping Statements .................................................................................................................... 141

Lesson 6
Understanding PeopleCode Events ............................................................................................................ 147
Describing Search Events .............................................................................................................................. 148
Activity 10: Using SearchInit to Control the Search Page ........................................................................... 154
Describing Component Build and Page Display Events ............................................................................... 157
Describing Field Action Events .................................................................................................................... 169
Describing Row Action Events ..................................................................................................................... 175
Describing Save Action Events ..................................................................................................................... 180
Activity 11: Synchronizing the Student Table with the Customer Table ...................................................... 189

Lesson 7
Using PeopleCode Variables ....................................................................................................................... 197
Creating User-Defined PeopleCode Variables .............................................................................................. 198
Using System Variables ................................................................................................................................ 205
Incorporating Derived/Work Fields into PeopleSoft Applications ............................................................... 207
Activity 12: Using Derived Work Fields ..................................................................................................... 217
Describing Variable Prompt Tables .............................................................................................................. 222
Activity 13: Setting Up a Variable Prompt Table Edit ................................................................................. 224

Lesson 8
Using Built-In Functions ............................................................................................................................. 229
Listing the Types of Built-In Functions ........................................................................................................ 230
Explaining Message Catalog Functions ........................................................................................................ 232
Describing All, None, and PriorValue Functions .......................................................................................... 236
Explaining String Functions .......................................................................................................................... 238
Identifying Other Built-In Functions ............................................................................................................. 240
Explaining Reserved Words .......................................................................................................................... 242
Activity 14: Using Built-In Functions ........................................................................................................... 245

iv
Contents

Lesson 9
Writing PeopleCode Functions .................................................................................................................. 251
Writing External PeopleCode Functions ....................................................................................................... 252
Declaring PeopleCode Functions .................................................................................................................. 255
Calling PeopleCode Functions ...................................................................................................................... 257
Writing Functions Using Parameters ............................................................................................................ 258
Writing Functions Using the Returns Argument ........................................................................................... 260
Activity 15: Writing Functions ...................................................................................................................... 263

Volume II
Lesson 10
Explaining the Component Buffer ............................................................................................................. 269
Reviewing Occurs Levels ............................................................................................................................. 270
Determining Buffer Allocation ..................................................................................................................... 274
Determining the Order of Execution of PeopleCode Programs .................................................................... 276
Activity 16: Determining the Contents of the Component Buffer ................................................................ 278

Lesson 11
Accessing Data in the Component Buffer ................................................................................................. 283
Processing Rows in the Component Buffer Using Loops ............................................................................. 284
Using Built-In Functions FetchValue and UpdateValue ............................................................................... 286
Accessing Data with Multiple Occurs Levels ............................................................................................... 288

Lesson 12
Programming With Object-Oriented PeopleCode ................................................................................... 295
Defining Object-Oriented Terms ................................................................................................................... 296
Instantiating Objects ...................................................................................................................................... 297
Referencing Object Properties by Using Dot Notation ................................................................................. 301
Calling Object Methods by Using Dot Notation ........................................................................................... 302
Discussing Passing by Reference .................................................................................................................. 306
Using Object-Oriented Methods and Properties .......................................................................................... 307
Activity 17: Using Object-Oriented Methods and Properties ....................................................................... 313
Discussing Arrays .......................................................................................................................................... 317

Lesson 13
Referencing Data in the Component Buffer ............................................................................................. 333
Defining the Data Buffer Classes .................................................................................................................. 334
Instantiating the Buffer Access Classes ........................................................................................................ 335
Explaining Current Context ........................................................................................................................... 338
Traversing the Data Buffer ............................................................................................................................ 339

v
Contents

Activity 18: Stepping Through the Data Buffer ............................................................................................ 345


Using Shorthand Dot Notation ...................................................................................................................... 354
Activity 19: Traversing the Data Buffer ........................................................................................................ 357
Traversing the Data Buffer with Multiple Scroll Levels ............................................................................... 360
Activity 20: Accessing Multiple Occurs Levels ............................................................................................ 363

Lesson 14
Creating Custom Objects with Application Classes ................................................................................ 369
Describing Application Classes ..................................................................................................................... 370
Organizing Application Classes Using Application Packages ...................................................................... 373
Using the Application Package Editor .......................................................................................................... 375
Activity 21: Writing an Application Class .................................................................................................... 376
Describing Application Class Structure ........................................................................................................ 379
Calling Application Classes .......................................................................................................................... 387
Passing Parameters to Application Classes .................................................................................................. 390
Activity 22: Calling Hello World .................................................................................................................. 391
Activity 23: Using Application Classes ........................................................................................................ 394

Lesson 15
Using Data Buffer Methods ........................................................................................................................ 399
Using the Sort Method .................................................................................................................................. 400
Using the Select Method ............................................................................................................................... 402
Activity 24: Using Select to Refresh Get Enrollments .................................................................................. 403
Using the Flush Method ................................................................................................................................ 410
Activity 25: Adding the Flush Method .......................................................................................................... 411
Working with Standalone Rowsets ............................................................................................................... 415
Using Other Buffer Methods ......................................................................................................................... 419

Lesson 16
Executing SQL in PeopleCode ................................................................................................................... 423
Writing SQLExec Statements ....................................................................................................................... 424
Activity 26: Updating Effort Spent with a SQLExec Statement ................................................................... 431
Creating SQL Definitions .............................................................................................................................. 434
Activity 27: Creating a SQL Definition ........................................................................................................ 436
Using the SQL Class ..................................................................................................................................... 439
Activity 28: Using a SQL Object .................................................................................................................. 444
Executing SQL Using Record Objects .......................................................................................................... 447
Incorporating Meta-SQL in PeopleCode and SQL ....................................................................................... 451
Activity 29: Choosing the Best SQL Option ................................................................................................. 456
Searching PeopleCode for Potential SQL Injection ...................................................................................... 461
Activity 30: Executing SQL in PeopleCode .................................................................................................. 462

vi
Contents

Lesson 17
Charting ....................................................................................................................................................... 467
Describing the Charting Classes .................................................................................................................... 468
Describing the Chart Class ............................................................................................................................ 471
Describing the Gantt Class, OrgChart Class, and RatingBoxChart Class ..................................................... 497
Activity 31: Creating a Bar Chart .................................................................................................................. 503

Lesson 18
Course Workshop ........................................................................................................................................ 509
Activity 32: Using a Standalone Rowset to Track Overtime Hours ............................................................. 510

Lesson 19
Course Review ............................................................................................................................................. 513
Describing PeopleCode ................................................................................................................................. 514
Using the PeopleCode Development Tools ................................................................................................... 515
Writing PeopleCode Programs and Choosing Events ................................................................................... 517
Manipulating Data in the Component Buffer ................................................................................................ 521
Programing with Object-Oriented PeopleCode ............................................................................................. 522
Manipulating Data in the Data Buffers and in SQL Tables .......................................................................... 523

Appendix A
Course Workshop Solution ......................................................................................................................... 525
Using a Standalone Rowset to Track Overtime Hours .................................................................................. 525

Appendix B
Component Processor Flow ........................................................................................................................ 527
Flow Chart and Table of Events .................................................................................................................... 527
Component Processor Flow Chart with PeopleCode Events ........................................................................ 527
Table of PeopleCode Events ......................................................................................................................... 529

Appendix C
Buffer Access Classes and SQL Class Quick Reference .......................................................................... 533
Rowset Class ................................................................................................................................................. 533
Row Class ...................................................................................................................................................... 535
Record Class .................................................................................................................................................. 536
Field Class ..................................................................................................................................................... 538
SQL Class ...................................................................................................................................................... 542

vii
Contents

Appendix D
Alternate Solutions and Additional Activities .......................................................................................... 545

viii
Lesson 10

Explaining the Component Buffer

Objectives
By the end of this lesson, you will be able to:

Review occurs levels.

Determine buffer allocation.

Determine the order of execution of PeopleCode programs.

Slide 165

269
Explaining the Component Buffer Lesson 10

Reviewing Occurs Levels

Occurs Levels
Scroll occurs levels maintain common key information for child record definitions.

Component Level 0:

The search key and other fields from the search record are at level 0.

Only one row of data can exist for each level 0 record definition.
Occurs Levels 13

The record associated with the first field beneath a scroll in the page field order determines the primary
record definition for that occurs level.

PeopleSoft allows only one primary record definition per scroll.

There can be more than one scroll on any level.

Slide 166

Student Notes

Example: Page with Two Occurs Levels


The PSU_EMP_REVIEW page is an example of a page definition with three levels, level 0 and two occurs
levels:

270
Lesson 10 Explaining the Component Buffer

Component Level 0
Every component has at least one level 0 record definition. The search key and other fields from the same
record definition all have a level of 0. Each level 0 record definition can have only one row of data because
scrolls begin at occurs level 1.

Occurs Level 1
Scrolls allow you to insert, delete, and navigate through multiple rows of data. The keys of the occurs level 1
record definition must include the same search keys as level 0, with at least one additional key. The additional
key fields allows multiple rows of data to be inserted with unique key values on level 1.

The first field beneath a scroll in the page field order identifies the primary record definition for that occurs
level. It should be a key on the primary record definition. These fields are sometimes called scroll keys. If
PeopleCode programs can be attached to any field on a record definition, they may be attached to the scroll
key since it is the first unique key field on the level.

PeopleSoft allows only one primary record definition per scroll. Fields from other record definitions may
appear on a level as related display or as derived/work. Related-display fields are always display-only, and
most derived/work fields are also display-only since they do not store data on the database. The purpose of a
scroll is to control input into a single SQL table. Nested scrolls maintain referential integrity.

Level 1 can have more than one scroll. Each scroll has its own primary record definition. The rows of data
within one scroll are completely independent from the rows of data within another scroll at level 1. The keys
of both primary record definitions must include the search keys from level 0 and at least one additional key
field to uniquely identify each row.

271
Explaining the Component Buffer Lesson 10

Reviewing Occurs Levels (continued)

Occurs Levels Rules


Occurs levels follow these rules:

A PeopleSoft page may have up to four levels: one level 0 and up to three occurs levels.

PeopleSoft allows multiple scrolls or grids at occurs level 2 and 3, but each scroll requires its own primary
record definition.

A page cannot have an occurs level 2 without an occurs level 1, or an occurs level 3 without an occurs level
2.

A child occurs level must have the same key fields as the parent, plus at least one additional key field.

Slide 167

Student Notes

Example: Page with Three Occurs Levels


The Review Factors page is an example of a page with three occurs levels:

272
Lesson 10 Explaining the Component Buffer

273
Explaining the Component Buffer Lesson 10

Determining Buffer Allocation

Buffer Allocation Rules


The following rules apply to Level 0:

For search keys and alternate search keys, only those fields are loaded.

For any other field from the level 0 record (i.e. non-key fields), the entire row is loaded.
The following rules apply to all levels (03):

For related-display fields, - that field is loaded, plus fields referenced by PeopleCode in the same related
table are loaded.

For derived/work, only that field is allocated.


The following rule applies to scroll levels 13:

All fields from the primary record definition are retrieved into the component buffer.

Slide 168

Student Notes

Determining Buffer Contents


The Component Processor retrieves entire rows of data for primary records. The Component Processor
assumes that the fields on the record definition represent all columns for a row of data. If one field from a
primary record definition is placed on a page, then all of the fields from that record are loaded into the
component buffer. This is referred to as "Full Row" buffer allocation.

Other fields may also be retrieved:

274
Lesson 10 Explaining the Component Buffer

Search Page Field When a search page field (search keys and alternate search keys) is placed on a
page, the Component Processor retrieves only that specific field from the search
list buffer. If other fields are needed from the same record definition for reference
in a PeopleCode program, an additional non-key field from the record definition,
should be placed on the page. The field can be hidden if the user doesn't need to
see it. By placing the additional non-key field on the page, the Component
Processor will be forced to retrieve the entire row of data.

RelatedDisplay Field The Component Processor brings in just the related display field, plus any other
fields (from the related-display record) referenced by the PeopleCode programs
that are loaded into the component buffer.

Derived/Work Field The Component Processor will not retrieve any data if a derived/work field is
placed on page, as there is none to retrieve. Other fields from the record are not
brought into the component buffer. Derived/work fields are placed on a page to
allocate space in memory for working storage.

Translate Table Field The Component Processor does not allocate an entire row of data from the
Translate table in order to retrieve their values. The fields on the Translate table
are brought into the server as cache files, like any other object, when the
component is retrieved. Only translate fields associated with page controls are
available in the Component buffer.

Question Answer

What is the general rule for building component buffers One field on the page for a primary record brings in the
(from Tools II)? entire row.

The exceptions for fields are:

Search page loads only the search keys and alternate search keys.

These fields load with the search page, so no further SQL Select is needed to load them into the component
buffer.

The presence of a non-key field from the search record at level 0 would load the entire row.

Related display loads only the field.

Derived/work loads only the field.

275
Explaining the Component Buffer Lesson 10

Determining the Order of Execution of PeopleCode Programs

PeopleCode Available for Execution


Based on the buffers that were created, you can determine which PeopleCode programs will be executed in
the component based on these rules:

If an entire row of data was brought into the buffers, any PeopleCode on that record definition may execute.

If derived/work fields are brought into the buffers, any PeopleCode on that specific derived/work field may
be performed.

PeopleCode on related-display fields are not performed. PeopleCode written on the Component,
Component Record, or Component Record Field definition will always be available to execute.

Slide 169

Student Notes

Order of Execution
If a search key is enabled at level 0, then you will encounter two problems.

First, the entire row of data from the search record will be loaded into the component buffer.

Second, if a user changes the high-level key and saves the page, the associated child data is orphaned. The
row of data with the original key will be overwritten with the new key and will then be updated to the table.
Any existing child records with the original key won't be updated, and data integrity will be lost. For
example, if you allow users to change the Course on PSU_COURSE_TBL, and 1001 is changed to 1101, then
the system will allow this action. However, the Course Sessions (on PSU_CRS_SESSN) with Course 1001 as
part of the key will be orphaned.

276
Lesson 10 Explaining the Component Buffer

Determining the Order of Execution of PeopleCode Programs


(continued)

Order of Execution
The order of PeopleCode execution is determined as follows:

1. By PeopleCode event.

2. Within an event, by level order as determined by the buffer allocation order.

3. For a given field, by first record PeopleCode, and then component PeopleCode.

Slide 170

277
Explaining the Component Buffer Lesson 10

Activity 16: Determining the Contents of the Component


Buffer
In this activity, you will review the activity overview and determine what fields and what PeopleCode
programs are loaded into the component buffer for the Course Enrollment component.

Slide 171

278
Lesson 10 Explaining the Component Buffer

Activity Overview
In this activity, you will look at the record definition and page definition for the Course Enrollment
component and apply the rules of component buffer allocation to determine what fields and what PeopleCode
programs will be loaded into the buffer.

279
Explaining the Component Buffer Lesson 10

Activity Detailed Steps


Perform the detailed steps to complete the activity.

Determining the Contents of the Component Buffer


To determine the contents of the component buffer:

1. In the browser, select Courses, Course Enrollment.

2. Answer the following question:

Question Answer

What fields are on the search page?


1.
2.
3.
4.

3. In Application Designer, open the record definition PSU_CRS_SESSN.

4. Answer the following questions:

Question Answer

Which fields are search keys?


1.
2.

Which fields are alternate search keys?


1.
2.

5. In Application Designer, open the page definition PSU_CRS_ENROLL.

6. Select the Order tab.

7. Answer the following questions:

Question Answer

What is the primary record definition for level 0?

What is the primary record definition for level 1?

8. Refer to the page definition to complete the following table:

Level Record Field Type What loads? PC?

280
Lesson 10 Explaining the Component Buffer

This concludes the activity. Please do not continue.

281
Explaining the Component Buffer Lesson 10

Review
In this lesson, you learned that:

PeopleSoft uses occurs levels to maintain data relationships and data integrity.

The Component Processor allocates buffers for the data it retrieves into a component.

You can determine the exact order in which PeopleCode will be executed based on occurs levels and buffer
allocation.

Slide 172

Student Notes

Additional Resources
This table lists additional resources that provide more details about the topics that we discussed in this lesson:

Topic Cross-Reference

Occurs levels PeopleTools 8.50 PeopleBook: PeopleSoft Application


Designer "Using Page Controls"

The Component Processor PeopleTools 8.50 PeopleBook: PeopleCode Developers


Guide, "PeopleCode and the Component Processor"

282
Lesson 11

Accessing Data in the Component Buffer

Objectives
By the end of this lesson, you will be able to:

Process rows in the component buffer using loops.

Use built-in functions FetchValue and UpdateValue.

Access data across multiple occurs levels.

Slide 174

283
Accessing Data in the Component Buffer Lesson 11

Processing Rows in the Component Buffer Using Loops

Loops
Sometimes PeopleCode programs cannot rely on the natural flow of the Component Processor to loop
through rows of data.

For example, a PeopleCode program attached to a field on level 0 might need to loop through all of the rows
of data on level 1.

These situations require a PeopleCode looping statement, generally a For loop:


For count = expression1 To expression2 [Step i];
statement_list
End-for

Slide 175

Student Notes

Loops
Normally, PeopleCode can loop through the rows of data at a specific occurs level by letting the Component
Processor naturally perform PeopleCode from the top of the buffers down. However, times may occur when
PeopleCode programs cannot rely on the natural flow of the Component Processor to loop through rows of
data. For example, a PeopleCode program attached to a field on level 0 may need to loop through all of the
rows of data on level 1. These situations require a PeopleCode looping statement.

As you saw in lesson 5, three different types of looping statements are in PeopleCode: While loops, Repeat-
Until loops, and For loops. This lesson will focus on the For loop.

For example, assume you have code on PSU_TASK_RESOURCE on level 1 (PSU_TASK_RSRC) and need
to add up all the associated PSU_TASK_EFFORT.EFFORT_AMT at level 2.

To do this, use a looping statement. Some relevant situations include:

Performing a calculation involving looking down a level.

Processing multiple rows on the same level.

Searching for a specific value (which could be down a level or on a different row at the same level).

FOR Loop
count can be any variable. &i is a common convention from FORTRAN.

Expression1 (start value) can be any value, but remember row numbers begin with 1.

Step value is optional (because +1 is assumed), but can be any positive or negative integer. If negative,
remember to make start greater than end.

284
Lesson 11 Accessing Data in the Component Buffer

Processing Rows in the Component Buffer Using Loops (continued)

ActiveRowCount
To loop through the rows on an occurs level, you need to know the number of rows. ActiveRowCount returns
the number of active rows in a scroll.
ActiveRowCount(SCROLL.primaryrecordname)

Slide 176

Student Notes

Example: ActiveRowCount
Here is an example of using ActiveRowCount in a For loop:
If PSU_CRS_SESSN.COMPLETED_FLAG = "Y" Then
For &i = 1 To ActiveRowCount(Scroll.PSU_STU_ENROLL)
statement;
statement;
End-For;
End-If;

Explaining ActiveRowCount
To loop through the rows on an occurs level, you need to know the number of rows. ActiveRowCount returns
the number of active rows in a scroll.
ActiveRowCount(SCROLL.primaryrecordname)

ActiveRowCount takes as its argument the name of the primary record definition at the occurs level where the
number of rows should be counted.

You will typically use ActiveRowCount to set the upper limit of your For loop.

For example, suppose you put a check box, COMPLETED_FLAG, on the Course Session table at level 0. If
COMPLETED_FLAG is selected, then anyone who was enrolled in the course ( ENROLL_STATUS =
"ENR") should have his or her attendance status changed to completed (ENROLL_STATUS = "CMP"). To
accomplish this task, you would need to loop through all the rows in the PSU_STU_ENROLL scroll. You
will use ActiveRowCount to set the upper limit for the loop.
If PSU_CRS_SESSN.COMPLETED_FLAG = "Y" Then
For &i = 1 To ActiveRowCount(Scroll.PSU_STU_ENROLL)
statement;
statement;
End-For;
End-If;

285
Accessing Data in the Component Buffer Lesson 11

Using Built-In Functions FetchValue and UpdateValue

FetchValue and UpdateValue


To reference the value of a field within a looping statement, you can use the FetchValue and UpdateValue
built-in functions.

FetchValue retrieves the value of a specific field, on a specific row.


FetchValue(SCROLL.record_name, target_row, [recordname.]fieldname)

UpdateValue changes the value of a specific field, on a specific row.


UpdateValue(SCROLL.record_name, target_row, [recordname.]fieldname,
value)

Slide 177

Student Notes

Example: UpdateValue and FetchValue


Here is an example of using UpdateValue and FetchValue to access rows in the component buffer:
If PSU_CRS_SESSN.COMPLETED_FLAG = "Y" Then
For &I = 1 To ActiveRowCount(Scroll.PSU_STU_ENROLL)
&status = FetchValue(Scroll.PSU_STU_ENROLL, &I,
PSU_STU_ENROLL.ENROLL_STATUS);
If &status = "ENR" Then
UpdateValue(Scroll.PSU_STU_ENROLL, &I,
PSU_STU_ENROLL.ENROLL_STATUS, "CMP");
End-if;
End-For;
End-If;

Explaining FetchValue and UpdateValue.


When you use looping statements to navigate through the multiple rows of data on an occurs level, the value
of a field can no longer be referenced by just using the record.field name. The same field exists on every row
of data within the occurs level. PeopleCode needs to know which row to use. To reference the value of a field
within a looping statement, you can use the FetchValue and UpdateValue built-in functions.

FetchValue retrieves the value of a specific field, on a specific row.


FetchValue(SCROLL.record_name, target_row, [recordname.]fieldname)

286
Lesson 11 Accessing Data in the Component Buffer

UpdateValue has the same basic syntax as FetchValue, with one additional parameter. In addition to passing
the function a field and row number, the new value of the field also must be provided. The value can be in the
form of a field name, variable, or literal.
UpdateValue(SCROLL.record_name, target_row, [recordname.]fieldname,
value)

When the For loop works through the rows in the scroll, the variable &I will contain the row number, so you
can use &I for the row number in the FetchValue and UpdateValue functions.

We are showing the old functions to contrast them with the new object-oriented code so that you are familiar
with their use when you encounter them in existing code.

287
Accessing Data in the Component Buffer Lesson 11

Accessing Data with Multiple Occurs Levels

Task Resources and Efforts Component Buffer


For the Task Resource page, the drawing shown in this diagram describes sample buffers that the Component
Processor could create for a task with two different resources.

Slide 178

Student Notes

Example: Component Buffer Allocation for PSU_TASK_RESOURCES


The Task Resources page includes data at level 0, level 1, and level 2.

288
Lesson 11 Accessing Data in the Component Buffer

Buffer Allocation
You now understand buffer allocation and the syntax for built-in functions for a page with a single-occurs
level. Quite often, however, you will encounter a page with more than one occurs level.

You're going to extend what you have learned to encompass more complex pages with multiple-occurs levels.
You will look at the buffer allocation process again and at the syntax you will use for multiple-occurs level
pages.

Consider putting some code on PSU_TASK_RSRC (level 1), which looks down at PSU_TASK_EFFORT
(level 2).

If you just use the code below, a problem exists.


&hours = FetchValue(Scroll.PSU_TASK_EFFORT,
&I,PSU_TASK_EFFORT.EFFORT_AMT);

Assume that &I=1. PeopleCode doesn't know whether your code wants to reference EFFORT_AMT(1,1) or
EFFORT_AMT(2,1). So you're going to use scroll path syntax to identify which PSU_TASK_RSRC parent
row you're using to reference the child row through.

Think of the data buffers as an array. When data is referenced in a multiple-occurs level component,
PeopleCode must know exactly where in the buffers the data resides. If you are using built-in functions, you
pass a complete set of subscript numbers to the functions as parameters.

289
Accessing Data in the Component Buffer Lesson 11

Accessing Data with Multiple Occurs Levels (continued)

Looking Down in the Buffer


With functions that require a field argument, you must specify the parent/child path if the PeopleCode
program is using a loop to look down in the buffers at a level 2 or level 3.
Function(SCROLL.level_1_recordName, level_1_row,
SCROLL.level_2_recordName, level_2_row,
SCROLL.level_3_recordName, level_3_row,
level_3_recordName.fieldName)

For example, looking down in buffer:


Gray/Hide(SCROLL.PSU_TASK_RSRC, CurrentRowNumber(1),
SCROLL.PSU_TASK_EFFORT, &I, PSU_TASK_EFFORT.EFFORT_AMT);

Slide 179

290
Lesson 11 Accessing Data in the Component Buffer

Accessing Data with Multiple Occurs Levels (continued)

Parent/Child Path
Functions that require a record argument must specify the parent/child path.
Function(SCROLL.level_1_recordName, level_1_row,
SCROLL.level_2_recordName, level_2_row,
SCROLL.level_3_recordName)

For example:
ActiveRowCount(SCROLL.PSU_TASK_RSRC, CurrentRowNumber(1),
SCROLL.PSU_TASK_EFFORT);

Slide 180

Student Notes

Functions in a Loop
Syntax requirements within a loop depend on the relative location of the PeopleCode program to the field and
record in its argument. If the PeopleCode program is located on the same level as its argument, the syntax is
controlled by the function parameter requirements.

If the PeopleCode program is located above its argument, you must specify the parent/child path.
Function(SCROLL.<level_1_recordName>, <level_1_row>,
SCROLL.<level_2_recordName>, <level_2_row>,
SCROLL.<level_3 recordName>, <level_3_row>, <record.field>)

For instance:
/* To access Level 2 from Level 1 */
FetchValue(SCROLL.PSU_TASK_RSRC, CurrentRowNumber(1),
SCROLL.PSU_TASK_EFFORT, &I, PSU_TASK_EFFORT.EFFORT_DT);

291
Accessing Data in the Component Buffer Lesson 11

Accessing Data with Multiple Occurs Levels (continued)

General Advice
For the best performance and the most straightforward code, place your PeopleCode at the lowest level
possible, unless it is forced up a level due to operator action.

Code that looks to the same level can reference fields directly.

Slide 181

Student Notes

Example: Code at Level 2


Here is an example of code that could be placed at level 2
.[PSU_TASK_RESOURCE.GBL.PSU_TASK_EFFORT ROWINIT]
If PSU_TASK_RSRC.COMPLETED_FLAG = "Y" Then
If All(PSU_TASK_EFFORT.EFFORT_AMT) Then
DERIVED_TRAIN.COUNTER = DERIVED_TRAIN.COUNTER + 1;
End-If;
End-If;

On the other hand, to access PSU_TASK_EFFORT.EFFORT_AMT at level 2, you need to use a loop when
the code is attached at level 1. [PSU_TASK_RESOURCE.GBL.PSU_TASK_RSRC.COMPLETED_FLAG
FIELDCHANGE]
If PSU_TASK_RSRC.COMPLETED_FLAG = "Y" Then
For &I = 1 to ActiveRowCount(SCROLL.PSU_TASK_RSRC,
CurrentRowNumber(1), SCROLL.PSU_TASK_EFFORT)
&EFFORT_AMT=FetchValue(SCROLL.PSU_TASK_RSRC,CurrentRowNumber(1),
SCROLL.PSU_TASK_EFFORT, &I, PSU_TASK_EFFORT.EFFORT_AMT);
If All(&EFFORT_AMT) Then
DERIVED_TRAIN.Counter =DERIVED_TRAIN.Counter +1;
End-If;
End-For;
Else
SetDefault(DERIVED_TRAIN.Counter);
End-If;

292
Lesson 11 Accessing Data in the Component Buffer

Review
In this lesson, you learned that:

You use a looping construct to process rows in the component buffer.

You access data in the component buffer using the built-in functions FetchValue and UpdateValue.

You access data across multiple occurs levels using extended syntax to specify the parent/child path.

Slide 182

Student Notes

Additional Resources
This table lists additional resources that provide more details about the topics that we discussed in this lesson:

Topic Cross-Reference

Processing rows in the component buffer. PeopleTools 8.50 PeopleBook: PeopleCode Developers
Guide, "Understanding the PeopleCode Language"

Using FetchValue and UpdateValue. PeopleSoft 8.50 PeopleTools PeopleBook: PeopleCode


Language Reference, "PeopleCode Built-In Functions"

Accessing data across multiple occurs levels. PeopleTools 8.50 PeopleBook: PeopleCode Developers
Guide, "Accessing the Data Buffer"

293
Lesson 12

Programming With Object-Oriented


PeopleCode

Objectives
By the end of this lesson, you will be able to:

Define object-oriented terms.

Instantiate objects.

Reference object properties by using dot notation.

Call object methods by using dot notation.

Disuss passing by reference.

Use object-oriented methods and properties.

Discuss arrays

Slide 184

295
Programming With Object-Oriented PeopleCode Lesson 12

Defining Object-Oriented Terms

Definitions
To discuss object-oriented programming, you should understand these terms:

Class The formal definition of an object.

Object A data structure in memory, created from its class.

Instance An object is an instance, a unique runtime copy of a class in memory.

Instantiate To create an instance of an object in memory by using a function or method.

Property An attribute or characteristic of an object.

Method The functionality associated with a given object.

Dot Notation The means by which you access the properties of an object or execute its
methods.

Slide 185

Student Notes

Objects
An object contains data and code. Up to this point, you have handled data and code separately. You have
created and changed data contained in fields and variables, and you have run code, in the form of various
types of functions. Objects contain, or encapsulate, both data and code, in the form of properties and methods.

296
Lesson 12 Programming With Object-Oriented PeopleCode

Instantiating Objects

Three Ways to Instantiate


The three ways to instantiate an object are:

Createxxx built-in functions. Create an unpopulated object.

Getxxx built-in functions. Create an object that references data that already exists in some form.

Getxxx methods. Typically, create a data structure that references a subset of the data structure that created
it.

Slide 186

Student Notes

Instantiating Objects
The three ways to instantiate an object are:

Createxxx built-in functions. Create an unpopulated object. For component buffer objects, you create an
empty object. For example, CreateRecord(Record.xxx) creates a record object that is not associated with
any data in the component buffer. It is empty until you set the values of various fields in it.

Getxxx built-in functions. Create an object that references data that already exists in some form. For
component buffer objects, you create an object that is associated with data that already exists in the
component buffer. For example, GetField(Field.xxx) creates a field object that references field data for
some field in the component buffer.

Getxxx methods. These are like Getxxx functions. They can create a data structure that references a subset
of the data structure that created it. In other words, they can create a child object of the parent object that is
running the method.

297
Programming With Object-Oriented PeopleCode Lesson 12

Instantiating Objects (continued)

Declaring an Object
Declare an object before you instantiate it:
Local Record &Rec; /* Declare the object */

This example instantiates a freestanding record object that does not contain any data:
&Rec = CreateRecord(RECORD.PSU_COURSE_TBL) /* Instantiate the object */

This example returns a record object pointing to the PSU_TASK_TBL record in the component buffer, along
with its associated data:
&Rec = GetRecord(RECORD.PSU_TASK_TBL);

If you leave out the argument, PeopleCode uses the current record:
&Rec = GetRecord(); /* Current context */

Slide 187

Student Notes

Introducing the Data Buffer Hierarchy


The most commonly used classes, and the ones that you will work with in this course, are the data buffer
access classes: rowset, row, record, and field.

Rowset A rowset object is a data structure that is used to describe hierarchical data. It is
made up of a collection of rows. A component scroll is a rowset. You can also
have a level 0 rowset.

Row A row object, which is instantiated from the Row class, is a single row of data that
consists of 1 to n records of data. A single row in a component scroll is a row. A
row can have 0 to n child rowsets. For example, a row in a level 2 scroll can have
n level 3 child rowsets.

Record A record object, which is instantiated from the Record class, is a single instance of
data within a row. It is based on a record definition. A record object consists of 1
to n fields.

Field A field object, which is instantiated from the Field class, is a single instance of
data in a record.

For now, focus on the functions and methods for one class, Record. We will look at all of the ways to
instantiate data buffer classes in detail in a later lesson.

298
Lesson 12 Programming With Object-Oriented PeopleCode

&Rec = CreateRecord(RECORD.PSU_COURSE_TBL);
Unpopulated. Standalone. Structure
based on record definition.

&Rec = GetRecord(RECORD.PSU_TASK_RSRC);
Reference to record in component
buffer.

&Rec = GetRecord();
Current record = the record the code is
on at runtime.

&Rec = &Row.GetRecord(RECORD.PSU_COURSE_TBL);
Method returns a reference to record in
&Rec = &Row.PSU_COURSE_TBL; a row object.

299
Programming With Object-Oriented PeopleCode Lesson 12

Instantiating Objects (continued)

Instantiating from Other Objects


Objects can be instantiated from other objects in the data buffer based on their position in the data buffer
hierarchy.

Rowsets contain rows.

Rows contain records (and child rowsets).

Records contain fields.

A record object that is instantiated with a GetRecord row method has the same result as the GetRecord
function,so the following two statements are equivalent in their results.
&REC2 = &Row.GetRecord(RECORD.PSU_TASK_TBL);

Slide 188

300
Lesson 12 Programming With Object-Oriented PeopleCode

Referencing Object Properties by Using Dot Notation

Referencing Properties
You access the properties of an object by using dot notation:
Variable = Object.Property;
Object.Property = Value;

This example uses the Visible property to hide the &ld field:
&Fld.Visible = False;

This example assigns the Value property of the &Fld field object to the &X variable:
&X = &Fld.Value;

This example uses a property as the test for a condition:


If &Fld.OriginalValue = &Fld.Value Then

Slide 189

301
Programming With Object-Oriented PeopleCode Lesson 12

Calling Object Methods by Using Dot Notation

Calling Object Methods


You also use dot notation to execute methods:
Object.method();

You can string methods and property values together into one statement:
If &REC_BASE.GetField(&R).Name = &REC_RELLANG.GetField(&J).Name Then

Some methods return a Boolean value: True if the method ran successfully; False if it did not.

This method returns True if all like-named fields have the same value:
If &MyRecord.CompareFields(&OtherRecord) Then

This method instantiates a row object and returns a reference to a row in a rowset:
&MyRow = &MyRowset.GetCurrEffRow();

Slide 190

Student Notes

Object Methods
A function is a generic ID or subroutine that acts on non-objects or instantiates objects. For example:
Gettime()
Getdate()
Getlevel0()

A method acts on objects; it is built into an object as part of the behavior of the object. Methods are like
functions that are specific to an object. It can be helpful to think of properties as attributes of objects and
methods as behaviors of objects.

Dot Notation
You also use dot notation to run methods. Methods can be easily identified by the parentheses that appear
immediately following the method name. To run a method, you follow the reference to an object by a period
and the method name. Place any parameters required by the method in its parentheses. The format is
generally:
Object.method();

You can string methods and property values together into one statement. The following example strings
together the GetField() method with the Name property:
If &REC_BASE.GetField(&R).Name = &REC_RELLANG.GetField(&J).Name Then

302
Lesson 12 Programming With Object-Oriented PeopleCode

Some methods return a Boolean value: True if the method ran successfully; False if it did not. The following
method compares all like-named fields of the current record object with the specified record. This method
returns True if all like-named fields have the same value:
If &MyRecord.CompareFields(&OtherRecord) Then

Other methods instantiate an object. This method returns a row object:


&MyRow = &MyRowset.GetCurrEffRow();

Some methods do not return anything at all. Refer to PeopleBooks for the method that you want to use to
determine what it returns.

303
Programming With Object-Oriented PeopleCode Lesson 12

Calling Object Methods by Using Dot Notation (continued)

Default Methods
Many objects have default methods associated with them:

Instead of entering the name of the method explicitly, you can use just the parameters for the method.

Objects that have default methods are composite objects; that is, they contain additional objects within
them.

The default method is generally the method that you use to get a lower-level object.

Slide 191

304
Lesson 12 Programming With Object-Oriented PeopleCode

Calling Object Methods by Using Dot Notation (continued)

GetField Method
A good example of a default method is the GetField method for a record object:

Record definitions are made up of field definitions.

Therefore, the default method for the Record class is GetField.


The following lines of code are equivalent:
&FIELD = &RECORD.GetField(FIELD.EMPLID);
&FIELD = &RECORD.EMPLID;

Slide 192

305
Programming With Object-Oriented PeopleCode Lesson 12

Discussing Passing by Reference

Passing by Reference
PeopleCode objects are passed by reference.

If an object is passed to a function, the function works on the actual object, not on a copy of the object.

All PeopleCode objects can be passed as function parameters, enabling the application developer to pass
complex data structures between PeopleCode functions.

In this example, a reference to the visible property is passed, not the value of Visible, which allows
MyPeopleCodeFunction to either get or set the value of Visible:
MyPeopleCodeFunction(&MyField.Visible);

Slide 193

Student Notes

Example: Passing by Reference


In this example, the Process_Rowset function loops through every row and record in the rowset that is passed
to it, and it runs an Update statement on each record in the rowset. This function could be called from any
PeopleCode program and could process any rowset that is passed to it:
Local Rowset &RS, &RS_Task_Effort;
Local Record &REC;
Function Process_RowSet(&ROWSET as Rowset);
For &I = 1 To &ROWSET.Rowcount
Local Row &ThisRow = &ROWSET(&I);
For &J = 1 To &ThisRow.Recordcount
&REC =&ThisRow.GetRecord(&J);
&REC.Update();
End-For;
End-For;
End-Function;
/* Instantiate and populate a standalone rowset*/
&RS_TaskEffort = CreateRowSet(RECORD.PSU_TASK_EFFORT);
&NRows = &RS_TaskEffort.Fill("Where TASK = :1 and CHARGE_BACK = 'Y' ",
PSU_TASK_TBL.TASK);
...
...
/* After making changes to the Rowset object, send it the Process_Rowset
function to update the database. */
Process_RowSet(&RS_TaskEffort);

306
Lesson 12 Programming With Object-Oriented PeopleCode

Using Object-Oriented Methods and Properties

Object-Oriented Equivalents of Common Functions


These common functions have object-oriented equivalents:

Built-In Function Object-Oriented Method or Property

Gray(Recordname.Fieldname) &Field.Enabled=False

UnGray(Recordname.Fieldname) &Field.Enabled=True

Hide(Recordname.Fieldname) &Field.Visible=False

UnHide(Recordname.Fieldname) &Field.Visible=True

SetDefault(Recordname.Fieldname) &Field.SetDefault()

Slide 194

307
Programming With Object-Oriented PeopleCode Lesson 12

Using Object-Oriented Methods and Properties (continued)

IsChanged, IsNew, and IsDeleted


The IsChanged, IsNew, and IsDeleted properties return a Boolean value and are commonly used in If
statements.
&Field.IsChanged
&Record.IsChanged
&Record.IsDeleted
&Row.IsNew
&Row.IsChanged
&Row.IsDeleted

Slide 195

Student Notes

Example: IsChanged
Here is an example of using IsChanged in a SavePreChange program:
[PSPSWDHINT.GBL.SavePreChange]
Local Rowset &PswdHints;
&PswdHints = GetLevel0()(1).GetRowset(Scroll.PSPSWDHINT);
For &i = 1 To &PswdHints.ActiveRowCount
If &PswdHints(&i).IsChanged Then
&PswdHints(&i).PSPSWDHINT.LASTUPDDTTM.Value = %Datetime;
&PswdHints(&i).PSPSWDHINT.LASTUPDOPRID.Value = %UserId;
End-If;
End-For;

Explaining the IsChanged, IsNew, and IsDeleted Properties


These properties allow us to check these special conditions:

308
Lesson 12 Programming With Object-Oriented PeopleCode

&Field.IsChanged Determine user changes. Emphasize not to use in the FieldChange event, because
the condition is already True.

&Row.IsNew Check for new row.

&Record.IsDeleted Select the deleted row flag. Works only in SPr, SPo, and WorkFlow.

&Record.IsChanged Determine user changes. Also returns True for new rows.

Note. Be careful when using IsChanged. These are evaluated True if any user action on the field or row
enabled the Save, regardless of actual change to data. This definition is different from the definition of a field
change as discussed in Lesson 4, "Describing the Component Processor."

In some situations, you do not want to process every row.

For instance, suppose that you have SaveEdit code to issue a warning for PAY_TBL.BONUS > 10%. If a
manager gave a 12 percent bonus in year 1, a warning would appear. In year 2, the bonus is only 5 percent.
You might write this code:
If PAY_TBL.BONUS > 10 Then
Warning MsgGet(20001, 3, "MESSAGE NOT FOUND");
End-If;

Unfortunately, the warning would still appear in year 2 because all rows are processed. Therefore, you should
modify the first line:
If PAY_TBL.BONUS > 10 and &RS_PayTbl(&I).IsNew Then

Extending the previous example, suppose that a manager gave a 7 percent bonus, saved, but then decided to
increase the bonus to 15 percent. Would the warning appear? No, because the row is no longer new.
Therefore, using the record object IsChanged property is better because it catches both caseswhen the row
is new and when an existing row is modified.
If &RecTbl.IsChanged And PAY_TBL.BONUS > 10 Then

309
Programming With Object-Oriented PeopleCode Lesson 12

Using Object-Oriented Methods and Properties (continued)

RowNumber
The RowNumber property returns the number of the current row in the rowset,and is similar to the
CurrentRowNumber built-in function:
&N = &Row.RowNumber;

Slide 196

Student Notes

Example: RowNumber
Here is an example of using the RowNumber property to get the number of the current row:
[PORTAL_DEFINITIONS.GBL.PORTAL_DEFNDYVW.PORTAL_DEFN_DFLT.FieldChange]
Component string &DefaultPortalName;
Local Rowset &rsPortal;
Local Row &rowPortal;
REM Make sure all other checkboxes are unchecked;
If PORTAL_DEFNDYVW.PORTAL_DEFN_DFLT = "Y" Then
&rowPortal = GetRow();
&DefaultPortalName = &rowPortal.PORTAL_DEFNDYVW.PORTAL_NAME.Value;
&ThisRowNum = &rowPortal.RowNumber;
&rsPortal = GetLevel0().GetRow(1).GetRowset(Scroll.PORTAL_DEFNDYVW);
For &I = 1 To &rsPortal.ActiveRowCount
&CurrentRowNum = &rsPortal.GetRow(&I).RowNumber;
If &I <> &ThisRowNum Then
&rsPortal(&I).PORTAL_DEFNDYVW.PORTAL_DEFN_DFLT.Value = "N";
End-If;
End-For;
End-If;

310
Lesson 12 Programming With Object-Oriented PeopleCode

Using Object-Oriented Methods and Properties (continued)

SetCursorPos
You use the SetCursorPos method to set the focus to the field specified on a given page.

This method is typically used before an Error statement in SaveEdit PeopleCode to identify the page, row,
and field where the cursor should return.
/* Put the cursor on a specific page in a multi-page component */
&Field.SetCursorPos(PAGE.pagename)

or
/* Put the cursor on the current page */
&Field.SetCursorPos(%Page)

You can also use SetCursorPos in other PeopleCode events that cause the Component Processor to display
the page.

This method is not used in FieldEdit because the cursor is always returned to the field where the FieldEdit
program is attached.

Slide 197

Student Notes

Explaining SetCursorPos
SetCursorPos is typically used before an Error statement in SaveEdit PeopleCode.

The page name that is passed to the function must be within the current component. You can use either the
PAGE reserved word or the %Page system variable. The latter can be used only if you are sure that the user
is currently viewing the page to which you want to navigate.

Because SaveEdit processes all non-deleted rows, putting the cursor on the row or field that causes the error
is useful. Otherwise, the user would have to search for the culprit.

Do not use this method in FieldEdit because FieldEdit keeps the cursor on the current field.

Do not use this method in conjunction with Warning because processing continues and the cursor is moved
to its next destination.

Place this method before the Error statement because the error stops processing and the program is exited.
Note that if you placed this method after the Error statement, it would never run.


You can use this method without an Error statement to control field navigation for the user. In this case,
you would override the tab order specified in the page definition.

311
Programming With Object-Oriented PeopleCode Lesson 12

In SEd, if you detected an error in PSU_TASK_RSRC.PCT_AVAILABLE and wanted to put the cursor on
the proper place:
&Field = GetField(FIELD.PCT_AVAILABLE);

or
&Field = GetField(); /* Default is the current field */
&Field.SetCursorPos(%Page); /* Put the cursor on the current page
*/

Note. You should use a specific page reference for a parameter rather than %Page because you may need to
jump the cursor to another page within the component.

Watch out for current context. If you put this function on the component record, it is not field specific. If you
use &Field = GetField(); it positions the cursor on the correct page but cannot know which field.

312
Lesson 12 Programming With Object-Oriented PeopleCode

Activity 17: Using Object-Oriented Methods and Properties


In this activity, you will review the activity overview and use object-oriented PeopleCode to implement
enhancements to the Course Sessions and Task Resources applications.

Slide 198

313
Programming With Object-Oriented PeopleCode Lesson 12

Activity Overview
Use object-oriented PeopleCode to complete the following tasks:

1. On the Course Sessions page, PeopleCode issues an error if the start date is greater than the end date.
Enhance your program so that the cursor moves to the Start Date field when this error occurs. The
program is on the component PSU_CRS_SESSN.

To access the Course Sessions page, select Courses, Define, Course Sessions. Select Course Code 1001.

2. On the Task Resources page, ensure that the Instructor and Resource Name fields work properly together.
If the instructor changes, then the resource name should change also. If the Instructor field contains a
value, then disable the Resource Name field.

314
Lesson 12 Programming With Object-Oriented PeopleCode

Activity Detailed Steps


Perform the detailed steps to complete the activity.

Using Object-Oriented Methods and Properties


The PeopleCode for each task follows the task description.

1. On the Course Sessions page, PeopleCode issues an error if the start date is greater than the end date.
Enhance your program so that the cursor moves to the Start Date field when this error occurs. The
program is on the component PSU_CRS_SESSN.
[PSU_CRS_SESSN.GBL.PSU_CRS_SESSN-SaveEdit]
/* UniqueID------------------------------------*/
Local Field &StartDt, &EndDt;
&StartDt=GetField(PSU_CRS_SESSN.START_DATE);
&EndDt=GetField(PSU_CRS_SESSN.END_DATE);
If All(&StartDt.Value, &EndDt.Value) And
&StartDt.Value > &EndDt.Value Then
&StartDt.SetCursorPos(%Page);
Error MsgGet(1040, 3, "Message Not Found: Course Start Date must not
be later than End Date.", &StartDt.Value, &EndDt.Value)
End-If;

315
Programming With Object-Oriented PeopleCode Lesson 12

2. On the Task Resources page, ensure that the Instructor and Resource Name fields work properly together.
If the instructor changes, the resource name should change also. If the Instructor field contains a value,
disable the Resource Name field. Make the instructor field interative
[PSU_TASK_RESOURCES.GBL.PSU_TASK_RSRC-RowInit]
/* UniqueID------------------------------------*/
Local Field &Instr;
&Instr = getfield(PSU_TASK_RSRC.INSTRUCTOR);
If All(&Instr.Value) Then
Local Field &Resource;
&Resource = GetField(PSU_TASK_RSRC.RESOURCE_NAME);
&Resource.Enabled = False;
End-If;
[PSU_TASK_RESOURCES.GBL.PSU_TASK_RSRC.INSTRUCTOR-FieldChange]
/* UniqueID------------------------------------*/
Local Field &Resource, &Instr;
&Resource = GetField(PSU_TASK_RSRC.RESOURCE_NAME);
&Instr=GetField(PSU_TASK_RSRC.INSTRUCTOR);
&Resource.SetDefault();
If All(&Instr.Value) Then
&Resource.Enabled = False;
Else
&Resource.Enabled = True;
End-If;

This concludes the activity. Please do not continue.

316
Lesson 12 Programming With Object-Oriented PeopleCode

Discussing Arrays

Arrays
An array is a PeopleCode object that is instantiated from the Array class.

An array is a collection of data storage locations, each of which holds the same type of data.

Each storage location is called an element of the array.

Arrays can be composed of any valid PeopleCode data type, such as:

Conventional data types: string, number, date, any, and so on.

Object data types: rowset, row, record, field, array, and so on.

Slide 199

317
Programming With Object-Oriented PeopleCode Lesson 12

Discussing Arrays (continued)

Using an Array
To use an array, you:

1. Declare the array.

2. Instantiate the array.

3. Populate the array.

4. Reference values in the array.

Slide 200

Student Notes

Array Objects
Array objects can be used as another working storage method to process business rules within a component.
A one or multi-dimensional array (depending on the nature and relationship of the required data, the buffer
location of the field and row to be processed, and the complexity of the business rule) can be instantiated and
populated with data retrieved from the database or the component buffer.

An example of array usage could be password validation during creation or modification. A user would create
a new password or modify an existing one. An array could be instantiated and populated with all allowable
characters. The program would then loop through characters in the password and verify that they were present
in the array.

318
Lesson 12 Programming With Object-Oriented PeopleCode

Discussing Arrays (continued)

Declaring Arrays
Declare arrays by specifying the scope, the Array type name, optionally followed by the type of the elements,
and a name that begins with &.

Syntax:
<scope>Array [of <element type>] <arrayname>

Example:
Local Array of Number &MYARRAY;

If you omit the element type, the default is ANY.

Example:
Local Array &ARRAYANY;

Slide 201

Student Notes

Declaring Arrays

Note. You should declare every object you use in PeopleCode to provide syntax checking when you save
PeopleCode. It's better to find out that you misspelled the name of a method or property at design time, rather
than at runtime!

You don't have to declare the size of the array at declaration time. Arrays grow and shrink dynamically as you
add (or remove) data.

The size of an array is limited by the available memory.

Arrays can be multidimensional.

319
Programming With Object-Oriented PeopleCode Lesson 12

Discussing Arrays (continued)

Instantiating Arrays
Use one of the built-in array functions to instantiate an array and return an object reference to it:

CreateArray

CreateArrayAny

CreateArrayRept

Split

Slide 202

320
Lesson 12 Programming With Object-Oriented PeopleCode

Discussing Arrays (continued)

Array Syntax
CreateArray

Syntax:
CreateArray([param1] [, param2] ...)

Example:
Local Array of Number &AN;
&AN = CreateArray(6,&N);

CreateArrayAny

Syntax:
CreateArrayAny([param1] [, param2] ...)

Example:
&AS = CreateArrayAny(1, "1", "One", %Date);
&AAS = CreateArrayAny(&AS, CreateArray("Two", "2", 2));

Slide 203

Student Notes

CreateArray
The type of the first parameter determines the type of array that is built. For example, if the first parameter is
of type NUMBER, then an array of number is built. If no first parameter exists, then an empty array of ANY
is built.

The CreateArray function uses flattening and promotion as required to convert subsequent values into suitable
elements of the array.

CreateArrayAny
CreateArrayAny constructs an array whose elements are of data type ANY.

The CreateArrayAny function uses flattening and promotion as required to convert subsequent values into
suitable elements of the array.

If you do not specify any parameters with CreateArrayAny, then the result is the same as using the
CreateArray function without any parameters.

If you do not know how many values are needed in a SQL statement until runtime, then you can use an array
of any to supply the values.

321
Programming With Object-Oriented PeopleCode Lesson 12

Discussing Arrays (continued)

Array Syntax
CreateArrayRept

Syntax:
CreateArrayRept(val, count)

Example:
&MYARRAY = CreateArrayRept(1, 3);

Split

Syntax:
Split(string, separator)

Example:
&STR = "This is a simple example.";
&AS = Split(&STR);

Slide 204

Student Notes

CreateArrayRept
CreateArrayRept creates an array that contains count copies of val. If val is itself an array, the created array
has one higher dimension, and each element (sub-array) is the array reference val.

The type of the first parameter (val) determines the type of array that is built. If the first parameter is of type
NUMBER, then an array of number is built. If count is zero, then CreateArrayRept creates an empty array
using the val parameter for the type.

If you are making an array that is multidimensional, val will be the subarray used as the elements.

The example for CreateArrayRept produces an array with three elements, each containing the number 1.

Split
The Split function converts a string into an array of strings by looking for the string separator in the given
string.

Note. The Split function does not split an array.

If separator is omitted, then the system uses a blank. If separator is a null string (), then the string is split into
single characters.

322
Lesson 12 Programming With Object-Oriented PeopleCode

The example for Split produces an array with the elements (This, is, a, simple, example.).

323
Programming With Object-Oriented PeopleCode Lesson 12

Discussing Arrays (continued)

Declaring Arrays
You can declare, instantiate, and populate an array on a single line.
Local Array of Any &ArrayAny = CreateArrayAny(1, 2, "hi", "there");

A multidimensional array is an array of arrays.

Example:
Local Array of Array of Number &AAN;
Local Array of Number &AN;
&AAN = CreateArray(CreateArray(1, 2), CreateArray(3, 4), 5);
&AN = CreateArray(6, &AAN[1]);

Slide 205

Student Notes

Two-Dimensional Array
&AAN is a two-dimensional array with three elements:

A one-dimensional array with 1 and 2 as elements.

A one-dimensional array with 3 and 4 as elements.

A one-dimensional array with only the element 5.

324
Lesson 12 Programming With Object-Oriented PeopleCode

Discussing Arrays (continued)

Populating Arrays
You can populate arrays:

At the time of instantiation.

Using an assignment statement.

Using the Push method to add elements to the end of an array.

Using the Unshift method to add elements to the beginning of an array.

Slide 206

325
Programming With Object-Oriented PeopleCode Lesson 12

Discussing Arrays (continued)

Supplying Arguments
At the time of instantiation, you can supply arguments for elements of the array. For example:

Example Result

Local Array of Number &MYARRAY;

&MYARRAY = CreateArray(100, 200, 300);


[100] [200] [300]

Slide 207

326
Lesson 12 Programming With Object-Oriented PeopleCode

Discussing Arrays (continued)

Assigning Values
You can assign values to the elements of the array. For example:

Example Result

Local Array of Number &MYARRAY;

&MYARRAY = CreateArrayRept(0,3);
[0] [0] [0]

&MYARRAY[1] = 100;
[100] [0] [0]

&MYARRAY[2] = 200;
[100] [200] [0]

&MYARRAY[3] = 300;
[100] [200] [300]

Slide 208

327
Programming With Object-Oriented PeopleCode Lesson 12

Discussing Arrays (continued)

Using the Push Method


Use the Push method to add items to the end of the array. For example:

Example Result

Local Array of Number &MYARRAY;

&MYARRAY = CreateArray();

&MYARRAY.Push(100);
[100]

&MYARRAY.Push(200);
[100] [200]

&MYARRAY.Push(300);
[100] [200] [300]

Slide 209

328
Lesson 12 Programming With Object-Oriented PeopleCode

Discussing Arrays (continued)

Using the Unshift Method


Use the Unshift method to add items to the beginning of the array. For example:

Example Result

Local Array of Number &MYARRAY;

&MYARRAY = CreateArray();

&MYARRAY.Unshift(300);
[300]

&MYARRAY.Unshift(200);
[200] [300]

&MYARRAY.Unshift(100);
[100] [200] [300]

Slide 210

329
Programming With Object-Oriented PeopleCode Lesson 12

Discussing Arrays (continued)

Referencing Arrays
You specify the elements in an array by providing a bracketed subscript after the array object reference:

Examples:
&MyArray[1] = 123;
&temp = &memory[1][2];
/* Same as preceding line. */
&temp = &memory[1, 2];
SomeFunction(&MyArray[7]);

Slide 211

330
Lesson 12 Programming With Object-Oriented PeopleCode

Review
In this lesson, you learned that:

To discuss object-oriented programming, you need to know the definitions for the following terms: class,
object, instance, instantiate, property, method, and dot notation.

You instantiate objects from their respective classes.

You use dot notation to access and manipulate object properties.

You use dot notation to run object methods.

You pass objects by reference.

Many built-in functions have object-oriented equivalents.

Arrays add another powerful dimension to working storage in PeopleCode programs.

Slide 212

Student Notes

Additional Resources
This table lists additional resources that provide more details about the topics that we discussed in this lesson:

Topic Cross-Reference

Defining Object-Oriented Terms PeopleTools 8.50 PeopleBook: PeopleCode Developer's


Guide, "Understanding Objects and Classes in
PeopleCode"

Instantiating Objects PeopleTools 8.50 PeopleBook: PeopleCode Language


Reference, "PeopleCode Built-In Functions"
Lesson 13, "Referencing Data in the Component Buffer"

Referencing Object Properties by Using Dot Notation PeopleTools 8.50 PeopleBook: PeopleCode API
Reference, "Appendix: Quick Reference for PeopleCode
Classes"

331
Lesson 13

Referencing Data in the Component


Buffer

Objectives
By the end of this lesson, you will be able to:

Define the data buffer classes.

Instantiate the data buffer access classes.

Explain current context.

Traverse the data buffer.

Use shorthand dot notation.

Traverse the data buffer to reference multiple occurs levels.

Slide 214

333
Referencing Data in the Component Buffer Lesson 13

Defining the Data Buffer Classes

Data Buffer
The data buffer classes are:

Rowset A rowset object is a data structure made up of a collection


of rows. For component buffers, think of a rowset as a
scroll on a page that contains all of that scroll's data and
any subordinate data. A level 0 rowset contains all the
data for the entire component.

Row A row object represents a single row in a component


scroll.

Record A record object is a single instance of data within a row


and is based on a record definition.

Field A field object is a single instance of data within a record


and is based on a field definition.

Slide 215

334
Lesson 13 Referencing Data in the Component Buffer

Instantiating the Buffer Access Classes

Instantiating
The buffer access classes can be instantiated in one of three ways:

A Createxxx() function creates a standalone object.

A Getxxx() function creates an object that references the component buffer.

A Getxxx() method of a higher-level object.

Slide 216

335
Referencing Data in the Component Buffer Lesson 13

Instantiating the Buffer Access Classes (continued)

Getxxx() Method
Using the Getxxx() method of a higher-level object creates an object referencing a subset of the parent object:

A rowset object can be instantiated from a parent row object.

A row object can be instantiated from parent rowset object.

A record object can be instantiated from a row object.

A field object can be instantiated from a record object.

Slide 217

Student Notes

Syntax
The following table gives the syntax for instantiating the buffer access classes.

336
Lesson 13 Referencing Data in the Component Buffer

Object Function/Method Returns a reference to

CreateRowset(RECORD.recname)
Rowset Unpopulated, standalone rowset object.
CreateRowSet(&RowSet)

GetLevel0()
The entire component buffer.

GetRowset(SCROLL.recname)
The scroll with the primary record recname.

GetRowset()
Current scroll area.

&Row.GetRowSet(SCROLL.recname)
The child scroll with primary record recname.

GetRow()
Row Current row.

&RowSet.GetRow(N)&RowSet(N)
RowN of a rowset object.

CreateRecord(RECORD.recname)
Record Unpopulated, standalone record object with
structure based on recname.

GetRecord(RECORD.recname)
Record in component buffer named recname.

GetRecord()
Current record.

&Row.GetRecord(RECORD.recname)
Record named recname in a Row object.
&Row.recname

GetField(recname.fieldname)
Field Field in the component buffer named fieldname
in the record recname.

GetField()
Current field.

&Record.GetField(FIELD.fieldname)
Field named fieldname within a record object.
&Record.fieldname

337
Referencing Data in the Component Buffer Lesson 13

Explaining Current Context

Current Context
Very often current context is the simplest, clearest way to instantiate an object.

Using a Getxxx() built-in function with no arguments will instantiate a Rowset, Row, Record, or Field object
referencing the data buffer relative to the current location of the executing program.

The following examples illustrate current context:


&ThisRowset = GetRowset();
&ThisRow = GetRow();
&ThisRecord = GetRecord();
&ThisField = GetField();

Slide 218

338
Lesson 13 Referencing Data in the Component Buffer

Traversing the Data Buffer

Traversing
You can access a specific field in the data buffer by working your way through the hierarchy of data buffer
objects, traversing the data buffer.

You can traverse the data buffer from the top down, starting with the level 0 rowset.

Or you can instantiate an object at whatever level is most appropriate and work your way down to a specific
field.

Slide 219

339
Referencing Data in the Component Buffer Lesson 13

Traversing the Data Buffer (continued)

Steps
The steps to traverse the component buffer from level 0 to level 1 are:

Step 1. Declare data buffer objects.

Step 2. Get the level 0 rowset.

Step 3. Get the level 0 row.

Step 4. Get a level 1 rowset.

Step 5. Get a level 1 row.

Step 6. Get a level 1 record.

Step 7. Get a level 1 field.

Slide 220

340
Lesson 13 Referencing Data in the Component Buffer

Traversing the Data Buffer (continued)

Traversing the Rowset


Step 1. Declare data buffer objects:
Local Rowset &RS_Level0, &RS_Level1;
Local Row &Row_Level0, &Row_Level1;
Local Record &Rec_TaskRsrc;
Local Field &Fld_PctAvail;
Local Integer &iPCTAVAIL;

Step 2. Get the level 0 rowset:


&RS_Level0 = GetLevel0();

Step 3. Get the level 0 row:


&ROW_Level0 = &RS_Level0.GetRow(1);

Slide 221

341
Referencing Data in the Component Buffer Lesson 13

Traversing the Data Buffer (continued)

Traversing the Rowset (continued)


For &I to &rs_level1.activerowcount

If PSU_TASK_RSRC.COMPLETED_FLAG = "Y" then

Step 4. Get a level 1 rowset.


&RS_Level1 = &ROW_LEVEL0.GetRowSet(SCROLL.PSU_TASK_RSRC);

Step 5. Get a level 1 row.


&Row_Level1 = &RS_Level1.GetRow(&I);

Step 6. Get a level 1 record.


&Rec_TaskRsrc = &Row_Level1.GetRecord(RECORD.PSU_TASK_RSRC);

Step 7. Get a level 1 field.


&Fld_PctAvail = &Rec_TaskRsrc.GetField(FIELD.PCT_AVAILABLE);

Slide 222

Student Notes

Example: Traversing the Rowset


Here is an example of how traversing the component buffer could be used to access a field at level 1.

342
Lesson 13 Referencing Data in the Component Buffer

Local Rowset &RS_Level0, &RS_Level1;


Local Row &Row_Level0, &Row_Level1;
Local Record &Rec_TaskRsrc;
Local Field &Fld_PctAvail;
&RS_Level0 = GetLevel0();
&Row_Level0 = &RS_Level0.GetRow(1);
&RS_Level1 = &Row_Level0.GetRowset(Scroll.PSU_TASK_RSRC);
If PSU_TASK_RSRC.COMPLETED_FLAG = "Y" Then
For &I = 1 To &RS_Level1.ActiveRowCount /* Loop thru Level 1 Rows */
&Row_Level1 = &RS_Level1.GetRow(&I);
&Rec_TaskRsrc = &Row_Level1.GetRecord(Record.PSU_Task_RSRC);
&Fld_PctAvail = &Rec_TaskRsrc.GetField(Field.PCT_AVAILABLE);
&Pct = &Fld_PctAvail.Value;
WinMessage("Value is "| &Pct); /* Do something with the value */
/* Use WinMessage for testing only */
End-For;
End-If;

In lesson 11, you saw an example of using FetchValue and UpdateValue to change the values of fields at
level 1. Here is that same example using object-oriented code instead.

343
Referencing Data in the Component Buffer Lesson 13

Local Rowset &RS_Level0, &RS_Level1;


Declarations
Local Row &Row_Level0, &Row_Level1;
Local Record &REC_TRNENROLL, &REC_CRSESESSN;
Local Field &FLD_COMPLETED, &FLD_ATTENDANCE;

&RS_Level0 = GetLevel0();
Rowset

&ROW_Level0 = &RS_Level0(1);
Row

&REC_CRSESESSN = &ROW_Level0.GetRecord(RECORD.PSU_CRS_SESSN);
Record

&FLD_COMPLETED = &REC_CRSESESSN.GetField(FIELD.COMPLETED_FLAG);
Field

If &FLD_COMPLETED.Value = "Y" Then

&RS_Level1 = &ROW_Level0.GetRowSet(SCROLL.PSU_STU_Enroll);
Rowset

For &I = 1 to &RS_Level1.ActiveRowCount

&ROW_LEVEL1 = &RS_Level1.GetRow(&I);
Row

&REC_TRNENROLL = &Row_Level1.GetRecord(RECORD.PSU_STU_ENROLL);
Record

&FLD_ATTENDANCE = &REC_TRNENROLL.GetField(FIELD.ENROLL_STATUS);
Field

If &FLD_ATTENDANCE.Value = "ENR" then

&FLD_ATTENDANCE.Value = "CMP";

End-If;

End-For;

End-If;

344
Lesson 13 Referencing Data in the Component Buffer

Activity 18: Stepping Through the Data Buffer


In this activity, you will review the activity overview and step through the process of traversing the
component buffer from level 0 to level 1, identifying the data that is returned for each step.

Slide 223

345
Referencing Data in the Component Buffer Lesson 13

Activity Overview
In this activity you will review the seven steps to traverse a data buffer from level 0 to level 1 and answer
some questions.

346
Lesson 13 Referencing Data in the Component Buffer

Activity Detailed Steps


Perform the detailed steps to complete the activity.

Before you look at the detailed steps, on your workstation access the Task Resources page.

The seven steps are:

Step 1. Declare data buffer objects.

Step 2. Get the level 0 rowset.

Step 3. Get the level 0 row.

Step 4. Get a level 1 rowset.

Step 5. Get a level 1 row.

Step 6. Get a level 1 record.

Step 7. Get a level 1 field.

Accessing the Task Resources page


To access the Task Resources page:

1. Select Set Up Training, Training Tasks, Task Resources and Efforts.

2. Select Task 0001.

The table you will be working with in this exercise is a representation of the component buffer for the Task
Resources and Efforts component for Task 0001.

Step 1. Declaring data buffer objects


Declaring variables is always good practice and declaring objects is especially important.

Complete the object types in the following declaration statements.

Local &RS_Level0, &RS_Level1;

Local &Row_Level0, &Row_Level1;

Local &Rec_TaskRsrc;

Local &Fld_PctAvail;

Step 2. Getting the level 0 rowset


Using the GetLevel0 function, instantiate the level 0 rowset.
&RS_Level0 = GetLevel0();

347
Referencing Data in the Component Buffer Lesson 13

Draw a box around the cells in the following tablethat represent the level 0 rowset

PSU_TASK_ PSU_TASK_ DERIVED_ PSU_TASK_


TBL RSRC TRAIN EFFORT

Task Descr Resource Name Pct Avail Resource Effort Date Effort Amount
Status

0001 Tools I
Guide

Ed Kelly 50 Semi-
Dedicated

11/16/01 7.0

11/15/01 8.0

11/14/01 6.0

11/13/01 6.0

Jim Gutenkauf 100 Dedicated

01/08/02 9.5

01/07/02 10.0

01/05/02 12.0

Step 3. Getting the level 0 row


Using the level 0 rowset object with the GetRow method, instantiate the level 0 row. Exactly one row is at
level 0 of the component buffer, so the argument for GetRow is always 1 to get the level 0 row.
&Row_Level0 = &RS_Level0.GetRow(1);

Draw a box around the cells in the following table that represent the level 0 row.

348
Lesson 13 Referencing Data in the Component Buffer

PSU_TASK_ PSU_TASK_ DERIVED_ PSU_TASK_


TBL RSRC TRAIN EFFORT

Task Descr Resource Pct Avail Resource Status Effort Date Effort Amount
Name

0001 Tools I
Guide

Ed Kelly 50 Semi-
Dedicated

11/16/01 7.0

11/15/01 8.0

11/14/01 6.0

11/13/01 6.0

Jim Gutenkauf 100 Dedicated

01/08/02 9.5

01/07/02 10.0

01/05/02 12.0

Step 4. Getting a level 1 rowset


A row contains one or more records and zero or more child rowsets. In this case, the level 0 row contains one
level 1 rowset. Because more than one level 1 scroll could exist, you need to specify which scroll by name.

Using the level 0 row object with the GetRowSet method, specify the primary record of the scroll.
&RS_Level1 = &Row_Level0.GetRowSet(SCROLL.PSU_Task_RSRC);

Draw boxes around the cells in the following table that represent the level 1 PSU_Task_RSRC rowset.

349
Referencing Data in the Component Buffer Lesson 13

PSU_TASK_ PSU_TASK_ DERIVED_ PSU_TASK_


TBL RSRC TRAIN EFFORT

Task Descr Resource Pct Avail Resource Status Effort Date Effort Amount
Name

0001 Tools I
Guide

Ed Kelly 50 Semi-
Dedicated

11/16/01 7.0

11/15/01 8.0

11/14/01 6.0

11/13/01 6.0

Jim Gutenkauf 100 Dedicated

01/08/02 9.5

01/07/02 10.0

01/05/02 12.0

Step 5. Getting a level 1 row


A rowset contains one or more rows; this example has two. Usually, you won't know the specific row number
and will loop through the rowset using a variable, such as &I, to access each row.

Using the level 1 rowset object with the GetRow method, specify the row number.
&Row_Level1 = &RS_Level1.GetRow(2);

Draw a box around the cells in the following table that represent level 1, row 2.

350
Lesson 13 Referencing Data in the Component Buffer

PSU_TASK_ PSU_TASK_ DERIVED_ PSU_TASK_


TBL RSRC TRAIN EFFORT

Task Descr Resource Pct Avail Resource Status Effort Date Effort Amount
Name

0001 Tools I
Guide

Ed Kelly 50 Semi-
Dedicated

11/16/01 7.0

11/15/01 8.0

11/14/01 6.0

11/13/01 6.0

Jim Gutenkauf 100 Dedicated

01/08/02 9.5

01/07/02 10.0

01/05/02 12.0

Step 6. Getting a level 1 record


A row object contains one or more records and may contain child rowsets. In this example, you want to get a
record. Later, you will learn how to access the child rowset at level 2.

Using the level 1 row object with the GetRecord method, specify the record name.
&Rec_TaskRsrc = &Row_Level1.GetRecord(RECORD.PSU_TASK_RSRC);

Draw a box around the cells in the following table that represent the level 1, row 2 record.

351
Referencing Data in the Component Buffer Lesson 13

PSU_TASK_ PSU_TASK_ DERIVED_ PSU_TASK_


TBL RSRC TRAIN EFFORT

Task Descr Resource Pct Avail Resource Status Effort Date Effort Amount
Name

0001 Tools I
Guide

Ed Kelly 50 Semi-
Dedicated

11/16/01 7.0

11/15/01 8.0

11/14/01 6.0

11/13/01 6.0

Jim Gutenkauf 100 Dedicated

01/08/02 9.5

01/07/02 10.0

01/05/02 12.0

Step 7. Getting a level 1 field


A record contains one or more fields.

Using the level 1 record object with the GetField method, specify the field name.
&Fld_PctAvail = &Rec_TaskRsrc.GetField(FIELD.PCT_AVAILABLE);

The preceding code returns a reference to single field. Draw a box around the cells that represent that field .

352
Lesson 13 Referencing Data in the Component Buffer

PSU_TASK_ PSU_TASK_R DERIVED_ PSU_TASK_


TBL SRC TRAIN EFFORT

Task Descr Resource Pct Avail Resource Status Effort Date Effort Amount
Name

0001 Tools I
Guide

Ed Kelly 50 Semi- Dedicated

11/16/01 7.0

11/15/01 8.0

11/14/01 6.0

11/13/01 6.0

Jim Gutenkauf 100 Dedicated

01/08/02 9.5

01/07/02 10.0

01/05/02 12.0

This concludes the activity. Please do not continue.

353
Referencing Data in the Component Buffer Lesson 13

Using Shorthand Dot Notation

Default Methods
Here are the default methods for the rowset, row, and record classes.

Source Object Returns Default Method Shorthand Notation

Rowset Row &RowSet.GetRow(n) &RowSet(n)

Row Record &Row.GetRecord(RECORD.recname) &Row.recname

Row Rowset &Row.GetRowset(SCROLL.recname)(n) &Row.recname(n)

Record Field &Record.GetField(FIELD.fieldname) &Record.fieldname

Slide 224

Student Notes

Example: Shorthand Notation


Here is an example of traversing the data buffer to level 1 using the shorthand notation:

&RS_Level0 = GetLevel0();
Rowset

&Row_Level0 = &RS_Level0(1);
Row

&RS_Level1 = &ROW_Level0.GetRowSet(SCROLL.PSU_Task_RSRC);
Rowset

For &I = 1 to &RS_Level1.ActiveRowCount

&ROW_Level1 = &RS_Level1(&I);
Row

&Rec_TaskRsrc = &Row_Level1.PSU_Task_RSRC;
Record

&Fld_PctAvail = &REC_TaskRsrc.Pct_Available;
Field

&Pct = &Fld_PctAvail.Value;

End-For;

354
Lesson 13 Referencing Data in the Component Buffer

Using Shorthand Dot Notation (continued)

Combining Dot Notation


You can string together dot notation to form a single statement.

For instance, the following four lines


&Row_Level1 = &RS_Level1(&I);
&Rec_TaskRsrc = &Row_Level1.PSU_Task_RSRC;
&Fld_PctAvail = &Rec_TaskRsrc.Pct_Available;
&Pct = &Fld_PctAvail.Value;

can be combined into a single statement:


&Pct = &RS_Level1(&I).PSU_Task_RSRC.Pct_Available.Value;

Slide 225

355
Referencing Data in the Component Buffer Lesson 13

Using Shorthand Dot Notation (continued)

Another Example
Here is an extreme example of stringing together methods and properties using dot notation:

Variable Rowset(Row) Rowset(Row) Rowset(Row)

&Effort = GetLevel0()(1). PSU_TASK_RSRC(&I). PSU_TASK_EFFORT(&J).

Record Field Property

PSU_TASK_EFFORT. EFFORT_AMT. Value;

Slide 226

Student Notes

Example: Dot Notation


Here is the example from the slide as it would appear in a program:
&Effort = &RS_Level0(1).PSU_TASK_RSRC(&I).PSU_TASK_EFFORT(&J).
PSU_TASK_EFFORT.EFFORT_AMT.Value;

Here is our looping example again, stringing properties and methods together.

&RS_Level1 = GetLevel0()(1).GetRowset(Scroll.PSU_TASK_RSRC);
Rowset, Row, Rowset

For &I = 1 to &RS_Level1.ActiveRowCount

&Pct = &RS_Level1(&I).PSU_Task_RSRC.Pct_Available.Value;
Row, Record, Field

End-For;

356
Lesson 13 Referencing Data in the Component Buffer

Activity 19: Traversing the Data Buffer


In this activity, you will review the activity overview and traverse a Student Enrollment rowset to check for
the prerequisite to a course.

Slide 227

357
Referencing Data in the Component Buffer Lesson 13

Activity Overview
On the Student Enrollment component (PSU_STU_ENROLL), do not allow enrollment into a PeopleCode
class (course 1011) unless the student has enrolled in a PeopleTools II (course 1002) class at an earlier date.
Begin by simply checking for the prerequisite, regardless of date. Once that works, add the logic to check for
an earlier start date.

Course enrollment can occur on multiple pages. This activity uses Student Enrollment. Make sure to take this
into consideration.

Select Courses, Student Enrollment to access the Student Enrollment page.

358
Lesson 13 Referencing Data in the Component Buffer

Activity Detailed Steps


Perform the detailed steps to complete the activity.

Traversing the Data Buffer


Here is an example of PeopleCode that would work to traverse the data buffer to check for prerequisites. You
may find a different solution.
[PSU_STU_ENROLL.GBL.PSU_STU_ENROLL-SaveEdit]
If PSU_STU_ENROLL.COURSE = "1011" And
PSU_STU_ENROLL.ENROLL_STATUS = "ENR" Then
Local boolean &Completed = False;
Local Rowset &RS;
Local Record &RecStuEnroll;
Local Field &Course, &Status;
Local date &StartDate, &PreReqStart;

&RS = GetRowset();
&StartDate = GetField(PSU_CRS_SESSN.START_DATE).Value;
For &I = 1 To &RS.ActiveRowCount
&RecStuEnroll = &RS.GetRow(&I).GetRecord(Record.PSU_STU_ENROLL);
&Course = &RecStuEnroll.COURSE;
&Status = &RecStuEnroll.ENROLL_STATUS;
&PreReqStart=&RS.GetRow(&I).GetRecord(Record.PSU_CRS_SESSN)
.START_DATE.Value;
If &Course.Value = "1002" And
(&Status.Value = "ENR" Or
&Status.Value = "CMP") Then
If &PreReqStart < &StartDate Then
&Completed = True;
Break;
End-If;
End-If;
End-For;

If Not &Completed Then
Error MsgGet(30420, 4, "MESSAGE NOT FOUND: Gotta have the prereq");
End-If;
End-If;

This concludes the activity. Please do not continue.

359
Referencing Data in the Component Buffer Lesson 13

Traversing the Data Buffer with Multiple Scroll Levels

Multiple Scroll Levels


Traversing the data buffer to level 2 or level 3 uses the same method that you learned earlier, just extending
the sequence out further.

To extend another level, add another Rowset/Row pair:

Rowset Level 0
Row

Rowset Level 1
Row

Rowset Level 2
Row
Record
Field

Slide 228

Student Notes

Example: Multiple Scroll Levels


Here is an example that traverses the component buffer from level 0 to level 2:

360
Lesson 13 Referencing Data in the Component Buffer

Local Rowset &RS_Level0, &RS_Level1, &RS_Level2;


Declarations
Local Row &Row_Level0, &Row_Level1, &Row_Level2;
Local Record &Rec_TaskEfft;
Local Field &Fld_EffortAmt;

If PSU_TASK_RSRC.COMPLETED_FLAG = "Y" then

&RS_Level0 = GetLevel0();
Rowset

&Row_Level0 = &RS_Level0(1);
Row

&RS_Level1 = &Row_Level0.GetRowset(SCROLL.PSU_Task_RSRC);
Rowset

&Row_Level1 = &RS_Level1(CurrentRowNumber(1));
Row

&RS_Level2 = &Row_Level1.GetRowset(SCROLL.PSU_Task_Effort);
Rowset

For &I = 1 to &RS_Level2.ActiveRowCount

&Row_Level2 = &RS_Level2(&I);
Row

&Rec_TaskEfft = &Row_Level2.PSU_Task_Effort;
Record

&Fld_EffortAmt = &Rec_TaskEfft.Effort_Amt;
Field

If All(&Fld_EffortAmt.Value) then
DERIVED_TRAIN.Counter = DERIVED_TRAIN.Counter + 1;
End-If;
End-For;
Else
GetField(DERIVED_TRAIN.Counter).SetDefault();
End-If;

361
Referencing Data in the Component Buffer Lesson 13

Traversing the Data Buffer with Multiple Scroll Levels (continued)

Shorthand Dot Notation


Remember that you do not always need to start at level 0.

Using shorthand dot notation, you can write more compact object-oriented code.

Slide 229

Student Notes

Example: Starting at Level 2


Here is the same example again, starting at level 2 and using shorthand notation.

Local Rowset &RS_Level2;


Local Field &Fld_EffortAmt;

If PSU_TASK_RSRC.COMPLETED_FLAG = "Y" then

&RS_Level2 = GetRowset(SCROLL.PSU_Task_Effort);
Rowset

For &I = 1 to &RS_Level2.ActiveRowCount

&Fld_EffortAmt = &RS_Level2(&I).PSU_Task_Effort.Effort_Amt;
Field = Rowset.Row.
Record.Field

If All(&Fld_EffortAmt.Value) then
DERIVED_TRAIN.Counter = DERIVED_TRAIN.Counter + 1;
End-If;
End-For;
Else
GetField(DERIVED_TRAIN.Counter).SetDefault();
End-If;

362
Lesson 13 Referencing Data in the Component Buffer

Activity 20: Accessing Multiple Occurs Levels


In this activity, you will review the activity overview, then modify the Task Resources and Efforts component
to add up the effort amounts attributed to each resource and display the total for that resource on the page.
Then you will make all the Task Effort occurs level rows display-only when a task has been completed.

Slide 230

363
Referencing Data in the Component Buffer Lesson 13

Activity Overview
For this activity, make the following enhancements to the Task Resources component.

1. On the Task Resources page, add the effort amounts attributed to each resource and display the total for
that resource on the page.

If the effort for a date changes, recalculate the total by finding the prior value of effort, subtracting that
from the total, then adding the new effort to the total.

2. Once a resource has finished a task, make all the Task Effort rows display-only (occurs level two).

364
Lesson 13 Referencing Data in the Component Buffer

Activity Detailed Steps


Perform the detailed steps to complete the activity.

Accessing Multiple Occurs Levels


To access multiple occurs levels:

1. On the Task Resources page, add up the effort amounts attributed to each resource and display the total
for that resource on the page.

a. Create a new field, TOTAL_RES_HRS.

b. Add the field to the record definition DERIVED_TRAIN.

c. Add the field to the PSU_TASK_RESOURCES page at level 1.

d. Make the field display-only.

e. Add the following PeopleCode.


[PSU_TASK_RESOURCES.GBL.PSU_TASK_EFFORT-RowInit]
DERIVED_TRAIN.TOTAL_RES_HRS = DERIVED_TRAIN.TOTAL_RES_HRS +
PSU_TASK_EFFORT.EFFORT_AMT;
[PSU_TASK_RESOURCES.GBL.PSU_TASK_EFFORT-RowDelete]
DERIVED_TRAIN.TOTAL_RES_HRS = DERIVED_TRAIN.TOTAL_RES_HRS -
PSU_TASK_EFFORT.EFFORT_AMT;
[PSU_TASK_RESOURCES.GBL.PSU_TASK_EFFORT.EFFORT_AMT-FieldChange]
DERIVED_TRAIN.TOTAL_RES_HRS = DERIVED_TRAIN.TOTAL_RES_HRS +
EFFORT_AMT - PriorValue(PSU_TASK_EFFORT.EFFORT_AMT);

365
Referencing Data in the Component Buffer Lesson 13

2. Once a resource has finished a task, make all the Task Effort occurs level rows display-only (occurs level
two).

Add the following PeopleCode.


[PSU_TASK_RESOURCES.GBL.PSU_TASK_EFFORT-RowInit]
If PSU_TASK_RSRC.COMPLETED_FLAG = "Y" Then
&Rec_TaskEffort = GetRecord(); /* Current Context */
&Rec_TaskEffort.EFFORT_DT.Enabled = False;
&Rec_TaskEffort.EFFORT_AMT.Enabled = False;
&Rec_TaskEffort.CHARGE_BACK.Enabled = False;
End-If;
[PSU_TASK_RESOURCES.GBL.PSU_TASK_RSRC.COMPLETED_FLAG-FieldChange]
/* UniqueID------------------------------------*/
Local Rowset &RS_Level2;
Local Row &Row_Level1;
Local Record &Rec_TaskEffort;
/* Current Context - GetRow() assumes current row */
&Row_Level1 = GetRow();
&RS_Level2 = &Row_Level1.GetRowset(Scroll.PSU_TASK_EFFORT);
If PSU_TASK_RSRC.COMPLETED_FLAG = "Y" Then
For &I = 1 To &RS_Level2.ActiveRowCount
&Rec_TaskEffort = &RS_Level2(&I).PSU_TASK_EFFORT;
&Rec_TaskEffort.EFFORT_DT.Enabled = False;
&Rec_TaskEffort.EFFORT_AMT.Enabled = False;
&Rec_TaskEffort.CHARGE_BACK.Enabled = False;
End-For;
Else
For &I = 1 To &RS_Level2.ActiveRowCount
&Rec_TaskEffort = &RS_Level2(&I).PSU_TASK_EFFORT;
&Rec_TaskEffort.EFFORT_DT.Enabled = True;
&Rec_TaskEffort.EFFORT_AMT.Enabled = True;
&Rec_TaskEffort.CHARGE_BACK.Enabled = True;
End-For;
End-If;

This concludes the activity. Please do not continue.

366
Lesson 13 Referencing Data in the Component Buffer

Review
In this lesson, you learned that:

The data buffer classesRowset, Row, Record, Fieldare used to access the data buffers.

Three ways to instantiate the data buffer classes involve using a Create function, a Get function, or a Get
method.

Current context is a fast, efficient way to create a reference to the current position in the data hierarchy.

Traversing the data buffers is a method to retrieve and modify data in the component buffer using the data
buffer classes.

Using shorthand dot notation, you can drastically reduce the amount of object-oriented code that you need
to write to traverse the data buffers.

Traversing the data buffer to reference multiple occurs levels requires adding additional sets of rowset/row
pairs to specify the parent rows.

Slide 231

Student Notes

Additional Resources
This table lists additional resources that provide more details about the topics that we discussed in this lesson:

Topic Cross-Reference

Defining the Data Buffer Classes PeopleTools 8.50 PeopleBook: PeopleCode Language
Reference, "PeopleCode Built-In Functions"
PeopleTools 8.50 PeopleBook: PeopleCode API
Reference, "Appendix: Quick Reference for PeopleCode
Classes"

367
Lesson 14

Creating Custom Objects with Application


Classes

Objectives
By the end of this lesson, you will be able to:

Describe application classes.

Organize application classes using application packages.

Use the Application Package Editor to create and modify application classes.

Describe the structure of application classes.

Call an application class from an existing program.

Pass parameters to application classes.

Slide 233

369
Creating Custom Objects with Application Classes Lesson 14

Describing Application Classes

Using Application Classes


Application classes:

Provide true object-oriented programming.

Can extend general classes.

Save development time.

Are easy to maintain.

Are easy to reuse.

Are easy to organize.

Slide 234

370
Lesson 14 Creating Custom Objects with Application Classes

Describing Application Classes (continued)

When to Use Application Classes


You should use application classes:

To encapsulate complex data structures.

To do generic processing, when just the details are different.

To extend the general classes with subclasses.

To logically organize code.

Slide 235

371
Creating Custom Objects with Application Classes Lesson 14

Describing Application Classes (continued)

Benefits
The benefits include:

Reusability

Application-specific classes

Inheritance and extensibility

Encapsulation

Organization

Dynamic execution

Slide 236

372
Lesson 14 Creating Custom Objects with Application Classes

Organizing Application Classes Using Application Packages

Application Package Editor


Use the Application Package Editor to create application packages.

A package is a container for other packages or for application classes.

A subpackage is any package other than the primary packagethat is, the package defined as the parent
package in the current definition.

Application packages can contain classes, and possibly other packages, in a hierarchy of up to three levels
of packages.

The primary package is represented by a blue database symbol, while subpackages are represented with
yellow database symbols.

Classes are represented by scripts and are used to host related application classes. By right-clicking a
package, class or method name in the Application Package definition you can select from the following in
the context menu:

View Application Package

View Application Class

View Application Class Method

Slide 237

Student Notes

Example: Application Package


The primary application package EO contains one application class, EO:Presentation, and one subpackage,
ApplicationClass, which in turn contains five application classes, as shown in this example:

Use the following navigation path in Application Designer to access this definition:

373
Creating Custom Objects with Application Classes Lesson 14

Definition Name Navigation

EO File, Open, Definition: Application Package

Using the Application Package Editor


The PeopleCode Editor provides immediate access to application packages, application classes, and
application class method definitions.

Right-click the package, class, or method name and, depending on the context, select from:

View Application Package

View Application Class

View Application Class Method


The application package or a new PeopleCode Editor window containing the application class opens.

The next slide shows an example of the context menu for a fully-qualified application class name and the
context menu for a method.

The application class context menu is not available for methods that are called by indirection.

In this example, the method CallMe would not be available to view using the context menu:
Object0.GetObject().CallMe();

Accessing Methods in Derived Classes


A method that is defined only in the superclass is not available if you attempt to view it using View
Application Class Method with the derived class or subclass.

For example, in the following code, CCI_CRM extends CCI_BASE. The method Validate is not defined in
CCI_CRM; it is available to CCI_CRM by extension. The method Submit, however, is overridden in
CCI_CRM.

If you right-click Validate and select View Application Class Method, the cursor will be placed at the
beginning of the application class CCR_CRM, not at the method definition in CCI_BASE.

If you right-click Submit and select View Application Class Method, you will be taken to the method
definition for Submit in CCI_CRM.

Example:

Import EOCC:CCI_CRM;

&CCI = Create EOCC:CCI_CRM();

&CCI.Validate(&Card);

&CCI.Submit(&Card);

This method may be helpful when you need to know whether a method was overridden.

374
Lesson 14 Creating Custom Objects with Application Classes

Using the Application Package Editor

Application Package Editor


To access PeopleCode in the classes of a package, double-click the class name.

The Application Package editor is similar to the PeopleCode editor in these ways:

You can add, delete, and change text.

You can validate syntax.

When you save your application package, the code is automatically formatted.
Only one event is defined for an application class: OnExecute.

The drop-down list in the upper-left enables you to navigate to every class in the package. If you are working
with a derived class, you can only view the methods that have been implemented in that class.

Slide 238

Student Notes

Example: Application Package Editor Window


When you view PeopleCode on an application class, the Application Package Editor window opens.

375
Creating Custom Objects with Application Classes Lesson 14

Activity 21: Writing an Application Class


In this activity, you will review the activity overview and create an application class with a simple
PeopleCode program.

Slide 239

376
Lesson 14 Creating Custom Objects with Application Classes

Activity Overview
In this activity, you will create a new application containing a simple PeopleCode, the classic "Hello World."

377
Creating Custom Objects with Application Classes Lesson 14

Activity Detailed Steps


To write an application class you will:

1. Create a new application package.

2. Insert an application class.

3. Add PeopleCode to the application class.

Creating a New Application Package


To create a new application package:

1. In Application Designer, select File, New.

2. Select Application Package.

3. Name the application package PSU.

Inserting an Application Class


To insert an application class:

1. Right-click the application package you just created.

2. Select Insert App Class.

3. For Class Name, enter HelloWorld.

Adding PeopleCode to the Application Class


To add PeopleCode to an Application Class:

1. Enter the following PeopleCode in your application class.


class HelloWorld
method Greeting();
end-class;
method Greeting
WinMessage("Hello World", 0);
end-method;

2. Save.

You will test your application class in a later activity.

This concludes the activity. Please do not continue.

378
Lesson 14 Creating Custom Objects with Application Classes

Describing Application Class Structure

Structure
The structure of an application class consists of:

Import statements.

Class definition.

Public and private declarations.

Get and Set definitions.

Method definitions.

Slide 240

Student Notes

Example: Application Class Structure


Here is an example of an application class, RO_Utilities:RO_RowSet, from CRM.

379
Creating Custom Objects with Application Classes Lesson 14

class RO_ROWSET extends Rowset


Class definition, with
extension

property integer FilledRowCount get;


Public property

method RO_ROWSET(&strRecName As string, &strDataFld As


Public methods
string, &strGetOrCreate As string);
(RO_ROWSET is the method InsertRow(&iRow As integer) Returns boolean;
constructor method) /*override of %super*/

Private
Begin private
declarations

instance string &m_strFieldID;


Private instance
variables instance string &m_strRecID;

Constant &cGET = GET;


Private constants
Constant &cCREATE = CREATE;
Constant &cSCROLL = Scroll.;
Constant &cRECORD = Record.;
Constant &cFIELD = Field.;

method EvaluateFilled() Returns boolean;


Private method

end-class;
End-class

get FilledRowCount
Get definition
/+ Returns Number(Integer) +/
If %This.EvaluateFilled() Then
Return %This.ActiveRowCount;
Else
Return 0;
End-If;
end-get;

380
Lesson 14 Creating Custom Objects with Application Classes

method RO_ROWSET
Method definitions
/+ &strRecName as String, +/
RO_Rowset is the
/+ &strDataFld as String, +/
constructor method
/+ &strGetOrCreate as String +/
Evaluate Upper(&strGetOrCreate)
When = &cGET
%Super = GetRowset(@(&cSCROLL | &strRecName));
Break;
When = &cCREATE
%Super = CreateRowset(@(&cRECORD | &strRecName));
Break;
When-Other;
/*not supported*/
Break;
End-Evaluate;
If %This <> Null Then
/*finish initialize*/
&m_strFieldID = &cFIELD | &strDataFld;
&m_strRecID = &cRECORD | &strRecName;
End-If;
end-method;
method InsertRow
/+ &iRow as Number(Integer) +/
/+ Returns Bool +/
If %This.EvaluateFilled() Then
Return %Super.InsertRow(&iRow);
Else
Return True;
End-If;
end-method;
/*private method*/
method EvaluateFilled
/+ Returns Bool +/
If All(%This.GetRow(%This.ActiveRowCount).GetRecord
(@(&m_strRecID)).GetField(@(&m_strFieldID)).Value) Then
Return True;
Else
Return False;
End-If;
end-method;

381
Creating Custom Objects with Application Classes Lesson 14

Describing Application Class Structure (continued)

Class Definition
Import any classes that will be used by a class, including the superclass this class extends.
Import PackageName[:SubpackageName[:SubsubpackageName]]:Superclassname

A class is defined using the Class construct:


Class ClassName [Extends SuperClassName]
[Method_declarations]
[Property_declarations]
[Private
[Method_declarations]
[Instance_declarations]
[Constant_declarations]]
End-Class

Slide 241

Student Notes

Extension
Extension represents the is-a relationship. For example, if you extend the Grid class your class is a
specialized form of the Grid class. When a class extends another class, it is called a subclass of that class.
Conversely, the class being extended is called a superclass of that subclass.

A subclass inherits all of the public methods and properties (collectively called members) of the class it
extends. These members can be overridden by declarations of methods and properties in the subclass.

Note. In our example, it was not necessary to import the Rowset class in order to extend it because delivered
classes are always available.

Notice the use of %Super and %This in the example code.

%Super refers to the superclass. %This refers to the current class.

382
Lesson 14 Creating Custom Objects with Application Classes

Describing Application Class Structure (continued)

Class Declarations
Public and private declarations follow the class definition.

The first set of declarations is the properties and methods that are part of the public, external interface.
Property datatype PropertyName [get] [set]
Method MethodName ([parameter_list])

The private instance variables, constants, and methods are declared following the keyword Private.
Private
Instance DataType &InstanceName;
Constant &Constant = {Number | String | True | False | Null}

The keyword end-class follows the declarations of properties, methods, instances, and constants.

Slide 242

Student Notes

Class Declaration
The public part of a class declaration specifies the methods and properties that the class provides to other
PeopleCode programs. These methods and properties are dynamically bound, that is, the actual method that is
called depends on the actual class of the object, as it might be an overridden method or property from a
subclass.

The value of a public property is available to external programs to read or change. If a property is declared
with the read-only parameter, it cannot be changed.

Properties can optionally be specified as Get, Set, or both.

A Get property will return a value to the calling program and requires a corresponding Get method.

A Set property can be changed by the calling program and requires a corresponding Set method.

If Set is not specified (and the property is not read-only), then the property is available to be changed
directly, without calling a Set method.

Similarly, if Get is not specified, then the property is available to be read directly, without calling a Get
method.

Note. Within a class, each member name must be unique. Different classes can have members with the same
name.

The private part of a class declaration gives the declaration of any private methods, instance variables, and
private class constants. Private methods cannot be overridden by subclasses, because they are completely
private to the declaring class. Likewise, the instance variables cannot be overridden.

383
Creating Custom Objects with Application Classes Lesson 14

Any method that is declared before the keyword Private in the initial class declaration is public. Any method
declared after the keyword Private is private.

Properties are only declared as public. Instances and constants are only declared as private.

384
Lesson 14 Creating Custom Objects with Application Classes

Describing Application Class Structure (continued)

Get and Set Definitions


After the end-class keyword and before get and set definitions or method definitions, declare any variables
and functions that will be used by the methods.

Get and set methods correspond to properties declared with the get and set keywords.

Use a get method definition to execute PeopleCode that will return a value:
get PropertyName
Return &Value
end-get

Use a set method definition to execute PeopleCode that will change a value:
set PropertyName
&PropertyName = &NewValue;
end-set

Slide 243

385
Creating Custom Objects with Application Classes Lesson 14

Describing Application Class Structure (continued)

Method Definitions
Method definitions are similar to function definitions.
method MethodName
statements
end-method

A special case of a method definition is the constructor.

A constructor has the same name as the class and will always run when the class is instantiated.

A class that does not extend some other class does not need a constructor.

A class that extends another class must have a constructor, and in the constructor, it must initialize its
superclass.

Slide 244

Student Notes

Constructors
A class that does not extend some other class does not need a constructor, but may include one to initialise
internal values.

A class that extends another class must have a constructor. The constructor must have the same name as the
class. The constructor method must include code to initialize its superclass.

To initialize a superobject, an instance of the superclass is assigned to the keyword %Super in the
constructor for the subclass. This assignment is allowed only in the constructor for the subclass.

The following example shows this type of assignment:


class Example extends ExampleBase
method Example();
...
end-class;
Global string &CurrentBaseString;
method Example
%Super = create ExampleBase();
&BaseString = &CurrentBaseString;
&SlashString = &BaseString;
&ImportantDate = Date(19970322);
end-method;

386
Lesson 14 Creating Custom Objects with Application Classes

Calling Application Classes

Using an Application Class


To use an application class in a PeopleCode program, you must:

1. Import the class.

2. Declare the class.

3. Instantiate the class.

4. Use the instance of the class.

Slide 245

387
Creating Custom Objects with Application Classes Lesson 14

Calling Application Classes (continued)

Importing an Application Class


To import an application class, use the Import statement:
Import PackageName[SubpackageName[:SubsubpackageName]]:ClassName;

Be sure to include the full path, if appropriate:


Import PackageName:SubPackageName:SubPackageName:ClassName

You can import all the classes in a package or subpackage using the * wildcard:
Import PackageName:*

Slide 246

Student Notes

Import PackageName:* Versus Import PackageName:ClassName


Just importing a class does not create much overhead; only when the class is will the details of the class be
looked up and recorded in the compiler's memory. Using Import Package:* is cost-effective because it only
finds the names of the classes in a package; most of the work for this task is done when you import even a
single class from the package.

One advantage to importing single classes is the avoidance of ambiguities: by not introducing more names,
you will not introduce any duplicates.

Another advantage is that explicit naming of imported classes is self-documenting. The classes that will be
used in the program are clearly shown.

388
Lesson 14 Creating Custom Objects with Application Classes

Calling Application Classes (continued)

Declaring, Instantiating, and Using an Object


To declare a class:

Declare the class:


Component PackageName:[SubPackage:]ClassName &NewObject;

Instantiate the object using the Create function:


&NewObject = Create ClassName();

Create takes as its argument any parameters needed by the constructor method. The constructor method
will be automatically called by the Create function.

Use the new object like any other object, by calling a method or accessing a property:
If &NewObject.Name = &ID then
&NewObject.GetName(&ID);
End-if;

Slide 247

Student Notes

Calling an Application Class


Instantiate new objects of an application class by using the Create function. This function takes the name of
the class and any parameters needed for the constructor method.

If the short class name is unambiguous, that is, only one class by that short name was imported, then you can
use just the short class name. If the class name may not be unique, then you must use the full class name.

389
Creating Custom Objects with Application Classes Lesson 14

Passing Parameters to Application Classes

Passing a Parameter by Reference


Application class programs generally pass parameters by value, which is according to the industry standard.
This is not the same as for existing functions.

Use the out specifier to pass a parameter by reference.

Example:
/* argument passed by value */
method increment(&value as number);
/* argument passed by reference */
method increment(&value as number out);

Object data types are passed by reference.

Slide 248

390
Lesson 14 Creating Custom Objects with Application Classes

Activity 22: Calling Hello World


In this activity, you will review the activity overview and write a PeopleCode program that calls the
HelloWorld class you created earlier.

Slide 249

391
Creating Custom Objects with Application Classes Lesson 14

Activity Overview
In this activity, you will write a simple PeopleCode that calls the HelloWorld class you created in the last
activity.

392
Lesson 14 Creating Custom Objects with Application Classes

Activity Detailed Steps


Perform the detailed steps to complete the activity.

Calling Hello World


For convenience, you will add your code to FieldEdit on the Get Enrollments Refresh button.

To call hello world:

1. In Application Designer, open the component definition PSU_GET_ENROLL.

2. Access the FieldEdit event for DERIVED_ED_SVCS.REFRESH_BTN.

You are using FieldEdit because in a later activity you will add code in FieldChange.

3. Add the following PeopleCode:


[PSU_GET_ENROLL.GBL.DERIVED_ED_SVCS.REFRESH_BTN.FieldEdit]
/* Import the class */
import PSU:HelloWorld;
/* Declare an object using the class */
Local HelloWorld &Hi;
/* Instantiate an object using the class */
&Hi = create HelloWorld();
/* Use the object */
&Hi.Greeting();

4. Test by selecting, in the browser, Set Up Training, Training Tasks, Get Enrollments. Select the Refresh
button.

You should see a message saying "Hello World."

5. Remove or comment out the PeopleCode in PSU_GET_ENROLL.

You will use this component again in a future activity.

This concludes the activity. Please do not continue.

393
Creating Custom Objects with Application Classes Lesson 14

Activity 23: Using Application Classes


In this activity, you will review the activity overview and then create and use a class called Order_Number to
create a new purchase number.

Slide 250

394
Lesson 14 Creating Custom Objects with Application Classes

Activity Overview
Earlier, you saw an example of a function that could be called to create a new purchase order number.
Borrowing code from that function, you will create an application class to accomplish the same task, and you
will modify the PeopleCode that calls the function to call the application class instead.

You will insert a new application class called Order_Number in the application package PSU.

After you open the PeopleCode program, use the function assign_order_number() on
FUNCLIB_ED_SVCS.Order_NBR.FieldFormula as the basis for your new application class.

Remember to:

Declare the class.

Declare properties and methods.

Declare private constants, instance variables, and methods.

Define methods.

Define Get and Set properties, if appropriate.


Modify the PeopleCode in PSU_PO_HDR.ORDER_NBR.SavePreChange to call the application class instead
of the function.

Remember to:

Import the class.

Declare an object.

Instantiate the object.

Call the method.


Finally, you will test by:

Selecting Purchasing, Maintain Purchase Orders, Add a New Value.

Accepting the defaults and selecting Add.

Saving.

Verifying that a new order number was assigned correctly.

395
Creating Custom Objects with Application Classes Lesson 14

Activity Detailed Steps


Perform the detailed steps to complete the activity.

Creating and Using Application Classes


To create and use a new application class:

1. Open the application package PSU.

2. Insert a new application class called Order_Number.

3. Open the PeopleCode program FUNCLIB_ED_SVCS.Order_NBR.FieldFormula.

4. Use the function assign_order_number() as the basis for your new application class:
[PSU.Order_Number.OnExecute]
/* Assign Order Number. Assumes 8 character id. */
class Order_Number;
method Assign_Order_Number(&ORDER_NBR As string) Returns string;

private
Constant &LENGTH = 8;
instance string &CHECK;
instance string &PAD;
instance number &NBR;
end-class;
method Assign_Order_Number
/+ &ORDER_NBR as String +/
/+ Returns String +/
Local string &Last_Order;
&CHECK = Rept("9", &LENGTH);
SQLExec("Select order_last From PS_INSTALLATION_TR", &Last_Order);
If Value(&Last_Order) + 1 > Value(&CHECK) Then
Error MsgGet(10001, 4, "MESSAGE NOT FOUND.", &CHECK);
Else
&NBR = Value(&Last_Order) + 1;
&PAD = Rept("0", 8 - Len(String(&NBR)));
&Order_Nbr = String(&PAD|&NBR);
SQLExec("Update PS_INSTALLATION_TR Set
ORDER_LAST = :1", &ORDER_NBR);
Return &ORDER_NBR;
End-If;
end-method;

396
Lesson 14 Creating Custom Objects with Application Classes

5. Modify the PeopleCode in PSU_PO_HDR.ORDER_NBR.SavePreChange to call the application class


instead of the function:
[PSU_PO_HDR.ORDER_NBR.SavePreChange]
import PSU:Order_Number;
Local Order_Number &NewOrder;
If PSU_PO_HDR.ORDER_NBR = "NEW" And
%Mode = "A" Then
/* assign order number */
&NewOrder = create Order_Number();
PSU_PO_HDR.ORDER_NBR =
&NewOrder.Assign_Order_Number(PSU_PO_HDR.ORDER_NBR);
End-If;

This concludes the activity. Please do not continue.

397
Creating Custom Objects with Application Classes Lesson 14

Review
In this lesson, you learned that:

Application classes are customizable PeopleCode classes.

You can use application packages to organize application classes.

You can create and modify application classes using the Application Class Editor.

The structure of an application class defines the public and private portions of the class.

Application class are called from PeopleCode programs.

Conventional variables and fields are passed to an application class method by value.

Slide 251

Student Notes

Additional Resources
This table lists additional resources that provide more details about the topics that we discussed in this lesson:

Topic Cross-Reference

Organizing Application Classes Using Application PeopleTools 8.50 PeopleBook: PeopleCode Developer's
Packages Guide, "Introducing Application Packages."

398
Lesson 15

Using Data Buffer Methods

Objectives
By the end of this lesson, you will be able to:

Use the Sort method.

Use the Select method.

Use the Flush method.

Work with standalone rowsets.

Explain other buffer methods.

Slide 253

399
Using Data Buffer Methods Lesson 15

Using the Sort Method

Sort
The Sort rowset method enables you to sort the rows of data within a scroll based on custom criteria.
&RowSet.Sort(Fieldname, "A|D"[, Fieldname, "A|D"]);

Slide 254

Student Notes

Example: Page That Uses the Sort Method


Use the following navigation path to access this page:

Page Name Navigation

Roles PeopleTools, Security, User Profiles, User Profiles, Roles

The Roles page on the User Profiles component uses the Sort method to control the sort order of the grid.

Here is the PeopleCode that controls the sorting on the Roles page:

400
Lesson 15 Using Data Buffer Methods

[USERMAINT.GBL.PostBuild]
PanelGroup Boolean &SaveNoWarn;
PanelGroup Boolean &tested;
PanelGroup Boolean &executed;
PanelGroup Boolean &first_run;
Local Rowset &level1;
&SaveNoWarn = False;
rem sort roles scroll;
&level1 = GetLevel0()(1).GetRowset(Scroll.PSROLEUSER_VW);
&level1.Sort(PSROLEUSER_VW.DYNAMIC_SW, "A", PSROLEUSER_VW.ROLENAME, "A");

Using the Sort Method


Usually, PeopleSoft controls the sorting of the rows of data within a scroll. This order is based on the keys of
the primary record definition for the occurs level. But what if you wanted to use different or multiple criteria
to sort the rows of data? You can use the Sort method.
&RowSet.Sort(Fieldname, "A|D"[, Fieldname, "A|D"]);

The primary sort field is listed first, followed by the value "A" for Ascending or "D" for Descending, within
quotes. If secondary sort fields exist, they should be referenced next in order. All sort fields must be located
within the scroll.

Users can sort grids by clicking the column heading, so why do we need sort?

Using Sort enables the developer to take control over initial page data presentation.

The developer can create an interface that enables the user to dynamically sort the data.

The Sort method enables sorting on multiple columns.

The Sort method sorts any scroll area or grid page control.

401
Using Data Buffer Methods Lesson 15

Using the Select Method

Select
Select enables you to restrict the rows and columns that are selected into a row or rowset object.

You use a Where clause to restrict the rows.

By specifying a view as the select record, you can restrict the columns that are selected into the object.
[&Rows = ] &Rowset.Select(RECORD.selrecord,
"Where ..." [, bind_variables]);

Slide 255

Student Notes

Using the Select Method


The Select method selects the fields defined in the select record, uses the Where clause to restrict the rows
being selected from the select record, and then populates the scroll referenced by the rowset calling the
method. The select record may be a view of the primary record of the scroll to limit the columns that are
returned.

The Select method is used only with rowsets that reference the Component buffers, instantiated using a
GetRowset method or function. You can't use this method with standalone rowsets created using the
CreateRowset function (use the Fill method instead, discussed later in this lesson.)

402
Lesson 15 Using Data Buffer Methods

Activity 24: Using Select to Refresh Get Enrollments


In this activity, you will review the activity overview and add PeopleCode to the Get Enrollments page to
enable it to select students enrolled in a specified course session.

Slide 256

403
Using Data Buffer Methods Lesson 15

Activity Overview
The purpose of the Get Enrollments page is to enable a user to get enrollment information for course sessions
without having to go through the search page for each session. The idea is to enter a course and session
number, complete the fields, click the Refresh push button, and retrieve all the students who are enrolled.

In this activity, you will look at the elements of the Get Enrollments component and add some PeopleCode to
select the appropriate data to populate the scroll.

404
Lesson 15 Using Data Buffer Methods

Activity Detailed Steps


Perform the detailed steps to complete the activity.

Using Select to Refresh Get Enrollments


In this activity, you will:

1. Use Select to refresh Get Enrollments.

2. Try the Get Enrollments page.

3. Examine the Get Enrollments page definition.

4. Examine the Get Enrollments component.

5. Add PeopleCode to select rows to populate the Get Enrollments scroll.

6. Test the PeopleCode.

Trying the Get Enrollments Page


To try the Get Enrollments page:

1. Select Set Up Training, Training Tasks, Get Enrollments.

2. For Course Code, enter 1001.

3. For Session Number, enter 287.

4. Select the Refresh push button.

5. Answer the following questions:

Question Answer

What did the search page look like?

Why was the page blank when it appeared?

Why were no rows retrieved when you pushed the


Refresh button?

Examining the Get Enrollments Page Definition


To examine the Get Enrollments page definition:

1. In Application Designer, open the page definition PSU_GET_ENROLL.

405
Using Data Buffer Methods Lesson 15

2. Look at the page field properties for Course Code, Session Number, and the Refresh button.

Question Answer

With what record definition are they associated?

Why a derived/work record?

This is one case in which derived/work fields are enabled and have prompt table edits.

3. Look at the grid properties.

Double-click the grid to open the properties dialog box.

Select the Use tab.

Notice that the No Auto Select check box is selected.


The scroll or grid referenced by the rowset object should have the No Auto Select check box selected to
prevent the Component Processor from automatically selecting rows to populate the scroll. You will take
control of that with PeopleCode.

Examining the Get Enrollments Component


To examine the Get Enrollments component:

1. In Application Designer, open the component definition PSU_GET_ENROLL. Look at the Component
Properties, Use tab. (Leave the page definition open.)

2. Answer the following questions:

Question Answer

What is the search record?

Why?

3. Select the page definition again.

Look at the grid properties, Use tab. Notice that No Auto Select is selected. That explains why the page
was initially blank. We don't want any rows selected for the buffer until the user selects Refresh.

4. Notice that the grid is set to display-only. If it were enabled, the user would be able to save changes to the
database.

5. If the component processor doesn't load the rows, how do they get loaded? PeopleCode.

406
Lesson 15 Using Data Buffer Methods

6. Answer the following questions:

Question Answer

Where would PeopleCode be?

Would it be on the record or the component?

Adding PeopleCode to Select Rows to Populate the Get Enrollments Scroll


To add PeopleCode to select rows to populate the Get Enrollments scroll:

1. Select the component definition again.

2. Select the Structure tab.

3. Open the PeopleCode for REFRESH_BTN, FieldEdit.

In a previous activity, you put code in the FieldEdit event. Verify that the code is commented out so that it
does not interfere with testing of this and subsequent activities.

4. Add the following code in REFRESH_BTN,FieldChange:


Local Rowset &Rowset;
&Rowset = GetRowset(SCROLL.PSU_STU_ENROLL);
&Rowset.Select(RECORD.PSU_STU_ENROLL, "Where COURSE = :1 and
SESSION_NBR = :2", DERIVED_ED_SVCS.COURSE,
DERIVED_ED_SVCS.SESSION_NBR);

Testing the PeopleCode


To test the PeopleCode:

1. Test using the following course sessions:

Course 1001, Session 4.

Course 1002, Session 32.


2. Select View All.

Notice that all the students from the first select are still present, along with all the students from the
second select.

Why?

3. Compare your Get Enrollments page with the following results:

Results

These are the enrollments for Course 1001, Session 4 and Course 1002, Session 32.

407
Using Data Buffer Methods Lesson 15

408
Lesson 15 Using Data Buffer Methods

This concludes the activity. Please do not continue.

409
Using Data Buffer Methods Lesson 15

Using the Flush Method

Flush
The Flush method can be used to remove rows from the buffer before you use a Select to bring new rows in.

Flush clears all the buffers for the rows of data within the rowset, without deleting them from the database.
&Rowset.Flush();

Slide 257

Student Notes

Example: Flush
The following example first flushes the rowset object, then selects into it based on a field on the page.
&RS1H.Flush();
&RS1H.Select(RECORD.CHECKLIST_ITEM, "where Checklist_CD = :1 and EffDt =
(Select Max(EffDt) from PS_CHECKLIST_ITEM Where CheckList_CD = :2)",
CHECKLIST_CD, CHECKLIST_CD);

Explaining the Flush Method


Data buffer methods also have the flexibility to clear the contents of a rowset. This assumes that you will later
load the same rowset buffer using Select.

Without Flush, subsequent calls to Select will append the data to what is currently contained in the buffer.

410
Lesson 15 Using Data Buffer Methods

Activity 25: Adding the Flush Method


In this activity, you will review the activity overview and add a Flush statement to your PeopleCode program
on the Get Enrollments component.

Slide 258

411
Using Data Buffer Methods Lesson 15

Activity Overview
In this activity, you will add a Flush statement to your PeopleCode program on the Get Enrollments
component.

412
Lesson 15 Using Data Buffer Methods

Activity Detailed Steps


In this activity, you will:

1. Add a Flush statement.

2. Test the statement.

Adding a Flush Statement


Add the following statement to the PeopleCode program that you wrote for the PSU_GET_ENROLL
component in the last activity:
&Rowset.Flush();

Your completed program should look like this.


Local Rowset &Rowset;
&Rowset = GetRowset(SCROLL.PSU_STU_ENROLL);
&Rowset.Flush();
&Rowset.Select(RECORD.PSU_STU_ENROLL, "Where COURSE = :1 and SESSION_NBR
= :2", DERIVED_ED_SVCS.COURSE, DERIVED_ED_SVCS.SESSION_NBR);

Testing
To test the Flush statement:

1. Test using the following course sessions:

Course 1001, Session 4.

Course 1002, Session 32.


2. Select View All.

Notice that only the students from the second select are displayed.

3. Compare your Get Enrollments page with the following results:

Results:

These are the enrollments for Course 1002, Session 32.

413
Using Data Buffer Methods Lesson 15

This concludes the activity. Please do not continue.

414
Lesson 15 Using Data Buffer Methods

Working with Standalone Rowsets

ScrollSelect
Before PeopleSoft 8, to access data from a table that was not shown on the page, a developer had to place a
work scroll on the page and make it invisible.

The developer then used ScrollSelect to populate the scroll from the target table.

Those rows became part of the component buffer and accessible to PeopleCode.
ScrollSelect(Level,Scroll.Recname1,
[Scroll.Recname2, [Scroll.Recname3,]]
Record.selectRecname,
"Where...,BindVariables [, true]);

Slide 259

Student Notes

Example: ScrollSelect
Here is an example of using ScrollSelect to select rows from PSU_TASK_EFFORT:
ScrollSelect (1,Scroll.PSU_TASK_EFFORT, Record.PSU_TASK_EFFORT, "where
TASK= :1 and CHARGE_BACK = 'Y'", PSU_TASK_TBL.TASK, true);

Discussing ScrollSelect
You have seen how to instantiate a rowset that represents the component buffer. You can also create a rowset
that is not tied to a component buffer. This is particularly useful when you need to access data that is on
another table.

Before looking at standalone rowsets on the next page, you should understand how developers used work
scrolls before they had the object-oriented rowsets to work with.

Before PeopleSoft 8, to access data from a table that was not shown on the page, a developer had to place
what is known as a work scroll on the page and make it invisible. The developer then used the ScrollSelect
function to populate the scroll from the target table, using the keys from the current component to select the
rows. Those rows then became part of the component buffer and therefore accessible to PeopleCode.
ScrollSelect (<Level>, Scroll.<RecName1>,
[Scroll.<RecName2>, [Scroll.<RecName3>,]]
Record.<selectRecordName>,
"Where...", <BindVariables> [, true]);

The ScrollSelect function requires the level number and the primary record definition name corresponding to
the scroll or grid that will contain the rows of data selected. It also requires the select record definition name.
The select record definition defines the fields that will be selected for the buffers.

415
Using Data Buffer Methods Lesson 15

The Where clause specifies the criteria to use to restrict the rows of data being selected to populate the scroll
or grid. Think of the ScrollSelect function as generating a SQL Select statement based on the parameters that
it is passed. The fields on the SelectRecordName will be the columns to select, the SelectRecordName will be
the name of the table or view to use in the From clause, and whatever is included in quotes will be the Where
clause attached to the end.

Here is an example of using ScrollSelect to select rows from PSU_TASK_EFFORT:


ScrollSelect (1,Scroll.PSU_TASK_EFFORT, Record.PSU_TASK_EFFORT, "where
TASK= :1 and CHARGE_BACK = 'Y'", PSU_TASK_TBL.TASK, true);

This code uses a bind variable to select rows from the PSU_TASK_EFFORT record that match the value in
PSU_TASK_TBL.TASK to populate the work scroll. The true at the end enables turbo mode, which enables
a more efficient select.

416
Lesson 15 Using Data Buffer Methods

Working with Standalone Rowsets (continued)

Standalone Rowset
Instead of creating a work scroll, you can use a standalone rowset.

To use a standalone rowset:

Declare a rowset object.

Instantiate it using a CreateRowset function.

Populate the rowset using either the Fill method or the CopyTo method.
[&Rows = ]&Rowset.Fill("Where ...",BindVariables)

Fill optionally uses a Where clause to selectively populate the rowset object from a database table.

Slide 260

Student Notes

Using the Fill Method


Standalone rowsets are a powerful alternative to work scrolls. Instead of creating a work scroll, declare a
rowset object, instantiate it using a CreateRowset function, and then populate the rowset using either the Fill
method or the CopyTo method.
&Rowset.Fill("Where ...", BindVariables)

The Fill method optionally uses a Where clause to selectively populate the rowset object from a database
table.

Important! Fill is used with standalone rowsets, which do not reference the component buffer. Select is used
with rowsets that reference scrolls in the component buffer.

Here is an example of using a rowset to perform the same select that you saw in the last example.
/* First instantiate a rowset object that is not tied to the component
buffer, is associated with PSU_TASK_EFFORT as its primary record and
contains no data. */
&RS_TaskEffort = CreateRowSet(RECORD.PSU_TASK_EFFORT);
/* Then populate the rowset with rows from the record. The method
returns the number of rows selected */
&NRows = &RS_TaskEffort.Fill("Where TASK = :1 and CHARGE_BACK = 'Y' ",
PSU_TASK_TBL.TASK);

Now you can access the rowset using the techniques you just learned for traversing the rowset.

417
Using Data Buffer Methods Lesson 15

Working with Standalone Rowsets (continued)

CopyTo
The CopyTo method copies from the rowset executing the method to the destination rowset, copying like-
named record fields and subscrolls at corresponding levels.
&Rowset.CopyTo(&DestRowset [, RECORD.source_recname1, RECORD.
target_recname1]
[, RECORD.source_recname2, RECORD.target_recname2] ...)

Slide 261

Student Notes

Using the CopyTo Method


The CopyTo method copies from the rowset executing the method to the destination rowset, copying like-
named record fields and subscrolls at corresponding levels.

The following example copies data from one rowset object to another. Because no like-named records exist
between the two rowsets, the record names are specified. Only the like-named fields will be copied from one
rowset to the other:
Local Rowset &RS1, &RS2;
&RS1 = CreateRowset(RECORD.PSU_CUST_TBL);
&RS2 = CreateRowset(RECORD.PSU_STUDENT_TBL);
&Customer = "XYZ";
&RS1.Fill("WHERE CUSTOMER_ID = :1", &Customer);
&RS1.CopyTo(&RS2, RECORD.PSU_CUST_TBL, RECORD.PSU_STUDENT_TBL);

CopyTo creates a copy of the data in the destination object. This is not the same as assigning one object to
another. The following code is an example of assigning one object to another. It actually causes both objects
to point to the same data:
&RS2 = &RS1;

418
Lesson 15 Using Data Buffer Methods

Using Other Buffer Methods

Other Buffer Methods


GetRelated returns a reference to a related-display field.
&Field2 = &Field1.GetRelated(recname.fieldname);

CopyFieldsTo copies fields on one record object to like-named fields on another record object.
&Record1.CopyFieldsTo(&Record2);

CopyTo copies like-named record fields and subscrolls at corresponding levels from one row to another.
&Row1.CopyTo(&Row2 [, RECORD.source_recname1,RECORD.target_recname1]
[, RECORD.source_recname2,RECORD.target_recname2] ...)

Slide 262

Student Notes

Using GetRelated
The GetRelated field method retrieves the value of a related-display field.
&Field2 = &Field1.GetRelated (recname.fieldname);

Although you could normally reference the value of the related-display field directly, a couple of situations
might occur in which you would use this method.

If you have two related display fields tied to the same page field, but with different control fields, you can
use this method to reference one of them. For example, you might have the related-display field
PERSONAL_DATA.NAME controlled by EMPLID from the high-level key, and an enabled derived/work
field. This method will access the value you want to use.

If you have search keys only on level 0, the entire row of data for the search record won't be loaded into the
buffer. You can display other fields from the search record without loading the entire row of data by
making those fields related display. To reference these values in programs, you must use this method.

Using CopyFieldsTo
CopyFieldsTo copies fields on one record object to like-named fields on another record object.
&Record1.CopyFieldsTo (&Record2);

Using CopyTo
CopyTo copies like-named record fields and subscrolls at corresponding levels from one row to another..

419
Using Data Buffer Methods Lesson 15

&Row1 = CopyTo(&Row2 [, RECORD.source_recname1,RECORD.target_recname1]


[, RECORD.source_recname2,RECORD.target_recname2] ...)

420
Lesson 15 Using Data Buffer Methods

Using Other Buffer Methods (continued)

InsertRow and DeleteRow


InsertRow enables you to insert a new row. RowInsert code and all following events will be fired normally.
&Rowset.InsertRow(RowNumber);

DeleteRow enables you to delete a row programmatically. RowDelete code and all following events will be
fired normally.
&RowSet.DeleteRow(RowNumber);

Slide 263

Student Notes

Using InsertRow
InsertRow enables you to insert a new row. RowInsert code and all following events will be fired normally.
&Rowset.InsertRow(RowNumber);

InsertRow cannot be executed from the same rowset where the insertion will take place, or from a child
rowset against a parent. Place your PeopleCode in a parent rowset and execute it against a child rowset.

Using DeleteRow
DeleteRow enables you to delete a row programmatically. RowDelete code and all following events will be
fired normally.
&RowSet.DeleteRow(RowNumber);

If you are using InsertRow or DeleteRow in a loop, process from the bottom up rather than the top down.
This prevents all your rows from being renumbered incorrectly (when a row is inserted or deleted, all rows
below it are renumbered).

For both InsertRow and DeleteRow, you cannot place the code on the same scroll level as the row being
inserted or deleted.

421
Using Data Buffer Methods Lesson 15

Review
In this lesson, you learned that:

You use the Sort method to control the ordering of individual scrollable areas.

You use the Select method to populate a scroll buffer.

You use the Flush method to clear a scroll buffer.

Standalone rowsets have a data structure based on a record definition but do not reference data in the
component buffer.

Other buffer methods that you can use to perform custom processing on fields and rows include
GetRelated,CopyFieldsTo,CopyTo,InsertRow, and DeleteRow.

Slide 264

422
Lesson 16

Executing SQL in PeopleCode

Objectives
By the end of this lesson, you will be able to:

Write SQLExec statements.

Create SQL definitions.

Use the SQL class.

Execute SQL using Record objects.

Incorporate meta-SQL in PeopleCode and SQL.

Search PeopleCode for potential SQL injection.

Slide 266

423
Executing SQL in PeopleCode Lesson 16

Writing SQLExec Statements

SQLExec Built-in Function


You can use a SQLExec built-in function to execute any SQL statement.

In practice you will execute only Select, Update, Insert, and Delete statements.

Other SQL should be executed through the PeopleTools or by a DBA.

Slide 267

424
Lesson 16 Executing SQL in PeopleCode

Writing SQLExec Statements (continued)

Selecting Data
SQLExec can be used to select one or more specific fields.

A SQLExec select statement returns only one row of data.

The output of a SQL Select statement can be stored in a variable, a page field, or a derived/work field.

SQL that is simply selecting data can be placed in any event.

Slide 268

Student Notes

Selecting Data
The SQLExec built-in function can be used to select one or more specific fields. This can be a significant
performance improvement over bringing in an entire row through the Component Processor. The output of a
SQL Select statement can be stored in a variable, a page field, or a derived/work field.

A SQLExec select statement retrieves every row of data that meets the criteria for the Where clause.
However, only one row of data, the first one retrieved, will be made available to the PeopleCode program.

SQL that is simply selecting data can be placed in any event.

425
Executing SQL in PeopleCode Lesson 16

Writing SQLExec Statements (continued)

Manipulating Data
SQL Insert, Update, and Delete commands are known as DML (data manipulation language)

Use SQLExec with DML to modify data in tables that have not been loaded into the component buffer.

DML statements can be issued only in FieldChange (as of 8.4), SavePreChange, WorkFlow, and
SavePostChange.

Slide 269

Student Notes

Inserts, Updates, and Deletes

Important! Have SQL Insert, Update, and Delete commands reviewed by your DBA.

You can use SQLExec with insert, update, and delete commands to modify data in tables that have not been
loaded into the component buffer, avoiding the overhead of loading data into the buffers.

DML-type statements can be issued only within the following PeopleCode events:

FieldChange (as of 8.4)

SavePreChange

WorkFlow

SavePostChange
Be aware that DML executed in the FieldChange event is committed immediately, whereas DML that is
executed in the other events is not committed until after SavePostChange is passed successfully. If an error
occurs after SQL is executed and before the commit, all changes are rolled back.

If data on other tables is to be manipulated based on changes in the component, SavePostChg should be used
because it executes after the Component Processor updates the database.

The number of rows affected by a SQLExec DML command is stored in the system variable %SQLRows.

426
Lesson 16 Executing SQL in PeopleCode

Writing SQLExec Statements (continued)

SQLExec Statement
A SQLExec statement consists of three parts:

A string literal or variable containing the SQL statement. The SQL statement may contain input values in
the form of bind variables.

Bind values to correspond to bind variables in the SQL statement.

Output locationsvariables or fieldsto store values from each column selected.

[&Rtn = ]SQLExec("SQL statement", [bindvalues, [outputvars]])

Slide 270

Student Notes

SQLExec Syntax
[&Rtn = ]SQLExec("SQL statement", [bindvalues, [outputvars]])

Only one SQL statement can exist per SQLExec built-in function.

A SQL statement contained within quotes is a "black box." PeopleSoft applications cannot check the SQL
syntax of the statement, so errors are not detected until runtime. The SQL syntax is completely determined by
the programmer. Maintenance is also a problem. If a change is made to field names or record names,
PeopleTools cannot update the references within a quoted literal.

427
Executing SQL in PeopleCode Lesson 16

Writing SQLExec Statements (continued)

SQLExec Statement
SQLExec can refer to data values stored in the data buffers by means of bind variables in the form of :n.

Following the SQL statement, provide the variables or fields that will supply the value for the bind variable.
SQLExec("Select EFFORT_SPENT from PS_PSU_TASK_TBL
Where TASK= :1", PSU_TASK_RSRC.TASK, &EFFORT_SPENT);

An inline bind can also be used, in the form recordname.fieldname.


SQLExec("Select EFFORT_SPENT from PS_PSU_TASK_TBL
where TASK= :PSU_TASK_RSRC.TASK", &EFFORT_SPENT);

Each column returned needs to be stored in a field or a variable.

In the example above, &EFFORT_SPENT is the output variable.

Slide 271

Student Notes

Example: SQLExec
Here is an example of using SQLExec to update the database.
[PSU_CUST.GBL.SavePostChange]
If FieldChanged(PSU_CUST_TBL.STREET1) Or
FieldChanged(PSU_CUST_TBL.CITY) Or
FieldChanged(PSU_CUST_TBL.STATE) Or
FieldChanged(PSU_CUST_TBL.ZIP) Or
FieldChanged(PSU_CUST_TBL.COUNTRY) Or
FieldChanged(PSU_CUST_TBL.PHONE) Then
SQLExec("Update PS_PSU_STUDENT_TBL set STREET1 = :1, CITY = :2,
STATE = :3, ZIP = :4, COUNTRY = :5, PHONE = :6
Where CUSTOMER_ID = :7 and SAME_ADDR_CUSTOMER = 'Y' ",
PSU_CUST_TBL.STREET1, PSU_CUST_TBL.CITY,PSU_CUST_TBL.STATE,
PSU_CUST_TBL.ZIP, PSU_CUST_TBL.COUNTRY, PSU_CUST_TBL.PHONE,
PSU_CUST_TBL.CUSTOMER_ID);
End-If;

428
Lesson 16 Executing SQL in PeopleCode

Input Values
If the SQLExec needs to refer to data values stored in the data buffers, bind variables are used. Bind variables
are represented within the SQL statement as :1, :2, and so on. Following the SQL statement, provide the
variables, fields, or expressions that will supply the value for the bind variable.
SQLExec ("Select EFFORT_SPENT from PS_PSU_TASK_TBL
where TASK= :1", PSU_TASK_RSRC.TASK, &EFFORT_SPENT);

Instead of using the bind variables in the form of :1, you can also use an inline bind. An inline bind is
supplied in the form "recordname.fieldname". This eliminates the need to pass the input value as a parameter.
SQLExec ("Select EFFORT_SPENT from PS_PSU_TASK_TBL
where TASK= :PSU_TASK_RSRC.TASK", &EFFORT_SPENT);

Review the trade-offs (rename support is one) of regular versus inline bind variables. Remember that regular
bind variables are the method of choice.

SQLExec supports APPROXIMATELY 32 total bind variables, whether they are used as input or output. The
number varies slightly depending on variable size.

Inline bind variables were created to work around the numeric limits of regular bind variables.

Output Parameters
Each column returned needs to be stored, either in a field or in an output variable, for later reference. One
output location is required for each column selected. The first column selected is returned into the first output
location, the second column is returned into the second output location, and so on. In the preceding example,
&EFFORT_SPENT is the output variable.

429
Executing SQL in PeopleCode Lesson 16

Writing SQLExec Statements (continued)

SQLExec Limitations
Use one row per SQLExec select.

PeopleTools won't maintain quoted literals.

Slide 272

Student Notes

One Row per SQLExec Select


If a SQL select statement is written that selects more than one row, the extra rows is still retrieved by the
DBMS and brought back to the Application Server, even though only the first row is stored to the output
variable. Selecting more than one row can have an adverse impact on performance. You must verify that each
SQLExec statement returns only one row.

PeopleTools Won't Maintain Quoted Literals


If any changes are made to definitions that are referenced in a SQLExec quoted literal, PeopleSoft
PeopleToolscannot apply the changes to the code. For instance, if a record definition is renamed, PeopleSoft
searches for all instances that reference it (such as on records or in other PeopleCode) so that it can change
the name globally. A quoted literal is like a black box to PeopleSoft PeopleTools, so it can't find the reference
to make the change.

As you will see later, SQL definitions offer a solution to this problem.

430
Lesson 16 Executing SQL in PeopleCode

Activity 26: Updating Effort Spent with a SQLExec Statement


In this activity, you will review the activity overview and write a SQLExec statement that automatically
updates the Effort Spent field whenever the Refresh button is clicked.

Slide 273

431
Executing SQL in PeopleCode Lesson 16

Activity Overview
Having users manually update the Effort Spent field isn't reasonable. That's a perfect job for PeopleCode.

In this activity you will add a push button to the page and write a SQLExec statement that automatically
calculates the Effort Spent field whenever the Refresh button is clicked.

432
Lesson 16 Executing SQL in PeopleCode

Activity Detailed Steps


Perform the detailed steps to complete the activity.

Updating Effort Spent With a SQLExec Statement


To update Effort Spent with a SQLExec statement:

1. Open the PSU_TASK page in Application Designer.

a. Make the Effort Spent field display-only.

b. Add a Refresh push button and associate it with the record field
DERIVED_ED_SVCS.REFRESH_BTN.

2. Add the following PeopleCode:


[PSU_TASK.GBL.DERIVED_ED_SVCS.REFRESH_BTN.FieldChange]
/* Update Effort_Spent whenever the user chooses to refresh it using
the pushbutton to reflect actual values in Effort_Amt */
SQLExec("Select Sum(EFFORT_AMT) from PS_PSU_TASK_EFFORT where TASK =
:1", PSU_TASK_TBL.TASK, PSU_TASK_TBL.EFFORT_SPENT);

3. Test the PeopleCode.

a. Navigate to the Task page.

b. Note the value of the Effort Spent field when you first open the component.

c. Click the Refresh push button and observe the change.

The Effort Spent field should now reflect the sum of all effort amounts recorded for this task on the
Task Resources page.

This concludes the activity. Please do not continue.

433
Executing SQL in PeopleCode Lesson 16

Creating SQL Definitions

SQL Definition
A SQL definition is an Application Designer definition that you use to store and maintain a SQL statement.

A SQL statement can be a complete SQL program or a fragment.

You can create and modify SQL definitions in Application Designer using the SQL Editor.

You can also create a SQL statement in PeopleCode using CreateSQL and save it as a SQL definition using
StoreSQL.

Reference a SQL definition with the following syntax:


SQL.sqlname

Slide 274

Student Notes

Creating SQL Definitions


A SQL definition is an Application Designer definition that you use to store and maintain all or part of a SQL
statement. You can create and modify SQL definitions in Application Designer using the SQL Editor or
through PeopleCode.

One of the major limitations of using SQL inside a quoted literal is that PeopleTools cannot maintain the code
within a quoted literal. PeopleSoft 8 addresses that problem through SQL definitions.

Here are some benefits of SQL definitions:

Reusable.

Upgradeable.

Platform independent.

Using a SQL Definition in PeopleCode


Many of the early limitations of SQLExec are resolved by means of SQL definitions in your SQLExec
functions. These definitions eliminate "black box" string literals that cannot be maintained by PeopleTools
and add platform independence and code reusability.

To rewrite a SQLExec statement to use the SQL definition that you created:

434
Lesson 16 Executing SQL in PeopleCode

1. Open the program that you created in the previous activity in


PSU_TASK.GBL.DERIVED_ED_SVCS.REFRESH_BTN.FieldChange.

It should look like this:


SQLExec("Select Sum(EFFORT_AMT)from PS_PSU_TASK_EFFORT where TASK =
:1", PSU_TASK_TBL.TASK, PSU_TASK_TBL.EFFORT_SPENT);

2. Modify the PeopleCode to use the SQL definition instead of the SQL statement in a quoted literal.
SQLExec(SQL.PSU_EFFORT_SUM, PSU_TASK_TBL.TASK,
PSU_TASK_TBL.EFFORT_SPENT);

3. Test using the new PeopleCode.

4. Select Set Up Training, Training Tasks, Task Table.

Verify that the Effort Spent field is updating properly.

Using the SQL Editor


In Application Designer, you invoke the SQL Editor to create a new SQL definition or open an existing SQL
definition. You are also using the SQL Editor whenever you edit the SQL in a SQL View Record or Dynamic
View Record.

You can also create a SQL statement in PeopleCode (using CreateSQL), save it as a SQL definition
(StoreSQL), then access it in PeopleSoft Application Designer.

Exploring the SQL Editor


In Application Designer, take a minute to look at some other features of the SQL Editor.

1. Select the drop-down under the title bar.

You can write database-specific SQL and associate it with the appropriate platform in the SQL definition.
Along with meta-SQL, this gives you another level of database-independence.

2. Right-click in the editor pane and choose Resolve Meta-SQL from the pop-up menu.

Noticethat the output window shows what the SQL looks like when it executes. In this case, it resolves the
record name in %Table by adding "PS_" as a prefix to it.

This meta-SQL allows the use of record names instead of table names in the SQL definition, which is a
significant benefit at upgrade time. The "black box" problem we encountered with quoted literals is
eliminated.

3. Click the Properties button (or use Alt+Enter, or right-click and select Definition Properties), select the
Advanced tab, and select the Show Effective Date check box. Click OK.

SQL definitions are effective-dated. By showing the effective date in the Editor window, you can
effective-date versions of your code.

435
Executing SQL in PeopleCode Lesson 16

Activity 27: Creating a SQL Definition


In this activity, you will review the activity overview and create a SQL definition, then replace the SQL string
in a SQLExec statement with the SQL definition that you created.

Slide 275

436
Lesson 16 Executing SQL in PeopleCode

Activity Overview
Many of the early limitations of SQLExec are resolved by using SQL definitions in your SQLExec
functions. These definitions eliminate "black box" string literals that cannot be maintained by PeopleTools
and add platform independence and code reusability.

In this activity, you will create a new SQL definition in Application Designer. Then you will substitute that
SQL definition for the quoted SQL statement in the SQLExec that you created earlier to select the sum of
Effort Amount entries for a given task.

437
Executing SQL in PeopleCode Lesson 16

Activity Detailed Steps


In this activity you will:

1. Create a SQL definition to sum Effort Amounts for all resources assigned to a task.

2. Explore the features of the SQL Editor.

3. Replace the SQL string in a SQLExec statement with the SQL definition that you created.

Creating a New SQL Definition


To create a new SQL definition:

1. In Application Designer, select File, New.

2. For the definition type, select SQL.

3. Click OK.

4. Add the following SQL statement. If you copy and paste from
PSU_TASK.GBL.DERIVED_ED_SVCS.REFRESH_BTN.FieldChange PeopleCode, be sure to add the
%Table meta-SQL.
Select Sum(EFFORT_AMT) from %Table(PSU_TASK_EFFORT) where TASK = :1

5. Save your definition as PSU_EFFORT_SUM.

This concludes the activity. Please do not continue.

438
Lesson 16 Executing SQL in PeopleCode

Using the SQL Class

SQL Class
The SQL class enables you to bypass many of the limitations of SQLExec.

Where a SQLExec delivers only a single row, using the SQL class enables you to retrieve and process
multiple rows.

You can use the SQL class with the Record class to further extend its capabilities.

You declare a SQL object like any other object, with a scope of local, component, or global.
Local SQL &SQL;

You instantiate a SQL object with the CreateSQL built-in function.


&SQL = CreateSQL("SQL Statement" , [bind_values]);

Slide 276

Student Notes

Example: CreateSQL
Here is an example of a CreateSQL statement.

&SQL = CreateSQL("Select EFFORT_AMT from PS_PSU_TASK_EFFORT


where TASK= :1", PSU_TASK_TBL.TASK);
While &SQL.Fetch(&EffortAmt)
PSU_TASK_TBL.EFFORT_SPENT = PSU_TASK_TBL.EFFORT_SPENT + &EFFORTAMT;
End-While;

SQL Class
The SQL class enables you to bypass many of the limitations of SQLExec Where a SQLExec Select returns
only a single row, with the SQL class you can retrieve and process multiple rows. And later in this lesson
you'll see how the SQL class can be used with the Record class to further extend its capabilities.

Declaring and Instantiating SQL Objects


Declare a SQL object like any other object, with a scope of local, component, or global.
Local SQL &SQL;

Instantiate a SQL object with the CreateSQL built-in function.


CreateSQL("SQL Statement", [bind_values]);

439
Executing SQL in PeopleCode Lesson 16

The SQL statement is similar to a SQL statement that SQLExec would use. Like SQLExec, the SQL
statement can contain bind variables in the form :1, :2, and so on. Place the values for the bind variables, in
order, following the SQL statement. The following example looks very much like the SQLExec that you saw
earlier.
&SQL = CreateSQL("Select EFFORT_SPENT from PS_PSU_TASK_TBL
where TASK= :1", PSU_TASK_RSRC.TASK);

In this example, the SQL statement is contained in a quoted literal, which causes the same maintenance
problems that you saw with SQLExec. Using a SQL definition instead of the quoted literal prevents that
problem, as you will see later in this lesson.

You can also choose to omit the values for the bind variables and supply those values later. For Insert,
Update, or Delete commands these values would be supplied by means of the Execute method.
&SQL = CreateSQL("DELETE from PS_PSU_STUDENT_TBL
where STUDENT_ID= :1");
&SQL.Execute(&ID);

440
Lesson 16 Executing SQL in PeopleCode

Using the SQL Class (continued)

Fetch
For a SQL object containing a Select statement, the Fetch method is used to retrieve the next row from the
cursor.
&SQL.Fetch(output_values)

Fetch takes as its argument output variables to receive values from the Select.

When no more rows exist, Fetch returns as False

You must use the Fetch method as part of an expression, typically using an If, While, or an assignment
statement.

If you are retrieving only one row, just use a SQLExec.

Slide 277

Student Notes

Example: Fetch
Here is an example of using the Fetch method of the SQL class.

&SQL = CreateSQL("Select EFFORT_AMT from PS_PSU_TASK_EFFORT


where TASK= :1", PSU_TASK_TBL.TASK);
While &SQL.Fetch(&EffortAmt)
<process results>
End-While;

441
Executing SQL in PeopleCode Lesson 16

Using the SQL Class (continued)

DML
Executing DML with SQL objects is very similar to using SQLExec.

Use the CreateSQL function to instantiate a SQL object with a SQL statement.

If you supply all the necessary input values, the SQL is executed immediately.

Otherwise, you supply the input values and execute the SQL with an Execute method.

The advantage of SQL objects is that you can set the statement once and execute it multiple times.

Slide 278

Student Notes

Example: DML Delete


Here is an example of using a SQL object for a DML Delete statement.
&SQL = CreateSQL("Delete from PS_PSU_TASK_RSRC where
PS_PSU_TASK_RSRC.TASK = :1");
&Task = "0003";
&SQL.Execute(&Task);
&Task = "0004";
&SQL.Execute(&Task);

DML
As with SQLExec, DML should be placed only in these events:

FieldChange (As of 8.4)

SavePreChange

WorkFlow

SavePostChange

442
Lesson 16 Executing SQL in PeopleCode

Using the SQL Class (continued)

Advantages of SQL Definitions


Using SQL definitions with your SQL objects has real advantages:

Reusability: Use the same code in many places .

Maintenance: Maintain code in a single place. Changes to record definitions and field names are
automatically reflected in the code.
Use CreateSQL("SQLString") when you pass a text string to your SQL object.
&SQL = CreateSQL("Select EFFORT_AMT from PS_PSU_TASK_EFFORT
where TASK= :1", PSU_TASK_TBL.TASK);

Use GetSQL(SQL.sqlname) when you get the SQL from a SQL definition.
&SQL = GetSQL(SQL.PSU_EFFORT_SUM, PSU_TASK_TBL.TASK,
PSU_TASK_TBL.EFFORT_SPENT);

Slide 279

Student Notes

Advantages of Using SQL Definitions


Using SQL definitions with your SQL objects has real advantages:

Reusability: Use the same code in many places without rewriting or copying and pasting.

Maintenance: Maintain code in a single place. Any changes are reflected everywhere the definition is
referenced. Changes to record definitions and field names are automatically reflected in the code.
To reference a SQL definition, you will instantiate a SQL object with the GetSQL built-in function.
GetSQL(SQL.sqlname, [input_values, [output_vars]])

SQL.sqlname is the name you gave the definition when it was saved.

Here's the SQL definition that you just created used with a SQL object.
/* without a bind value */
&SQL = GetSQL(SQL.PSU_EFFORT_SUM);
/* or with the bind value supplied */
&SQL = GetSQL(SQL.PSU_EFFORT_SUM, PSU_TASK_TBL.TASK,
PSU_TASK_TBL.EFFORT_SPENT);

443
Executing SQL in PeopleCode Lesson 16

Activity 28: Using a SQL Object


In this activity, you will review the activity overview and modify the PeopleCode that you created in
PSU_TASK.GBL.DERIVED_ED_SVCS.REFRESH_BTN.FieldChange to use a SQL object.

Slide 280

444
Lesson 16 Executing SQL in PeopleCode

Activity Overview
In this activity, you will modify the PSU_TASK.GBL.DERIVED_ED_SVCS.REFRESH_BTN.FieldChange
PeopleCode program to use a SQL object instead of a SQLExec statement.

445
Executing SQL in PeopleCode Lesson 16

Activity Detailed Steps


Perform the detailed steps to complete the activity.

Using a SQL Object


To modify your PeopleCode to use a SQL object:

1. In Application Designer, open PSU_TASK.GBL.DERIVED_ED_SVCS.REFRESH_BTN.FieldChange


and edit the code so it looks like this:
/* Whenever the refresh button is invoked, update EFFORT_SPENT to
reflect
actual values in EFFORT_TO_GO */
/* Declare the SQL object */
Local SQL &SelectEffort;
Local Number &Spent;
/* Instantiate the SQL object using the SQL Definition */
&SelectEffort = GetSQL(SQL.PSU_EFFORT_SUM, PSU_TASK_TBL.TASK);
If &SelectEffort.Fetch(&Spent) Then
PSU_TASK_TBL.EFFORT_SPENT.value = &Spent;
DERIVED_TRAIN.EFFORT_TO_GO.Value = PSU_TASK_TBL.EFFORT_TOTAL.value
- PSU_TASK_TBL.EFFORT_SPENT.value;
End-If;

2. Test the modified code.

This concludes the activity. Please do not continue.

446
Lesson 16 Executing SQL in PeopleCode

Executing SQL Using Record Objects

Using a Record Object


By using a Record object to execute SQL, you can operate on an entire record instead of working field by
field.

Using the Record object leverages the data dictionary, giving you access to field lists and keys without having
to explicitly specify them.

You instantiate a Record object with CreateRecord.


CreateRecord(Record.recordname);

Slide 281

Student Notes

CreateRecord Function
A record object created with the CreateRecord function, as opposed to GetRecord, is a standalone object.
That is, it is not tied to the component buffer. It contains the structure of the record definition used to
instantiate it, but it contains no data.
Local Record &MyRec;
&MyRec = CreateRecord(RECORD.PSU_TASK_RSRC);

447
Executing SQL in PeopleCode Lesson 16

Executing SQL Using Record Objects (continued)

SelectByKey
The SelectByKey method selects one row of data based on the key values provided.
&Record.SelectByKey(key1, key2, ...)

SelectByKey returns True on successful completion (which includes returning zero rows) and False if the
record is not found.

If not all keys are set, so that more than one row would be retrieved, SelectByKey won't fetch any data and
you won't receive an error message.

You use SelectByKeyEffdt to select the current row from a table. It is used the same as SelectByKey, but
takes a date as its argument.

Slide 282

Student Notes

SelectByKey
The SelectByKey method selects one row of data based on the key values provided.

The following example selects one row of data from PSU_TASK_RSRC into &MyRec based on the key
values &Task and &Resource.
/* Assign values to all the key fields */
&MyRec.TASK.Value = &Task;
&MyRec.RESOURCE_NAME.Value = &Resource;
If &MyRec.SelectByKey() then
<Processing based on row returned>
End-if;

SelectByKey provides an optional return code that is set to True on successful completion and False if the
record is not found.

If not all keys are set, so that more than one row is retrieved, SelectByKey does not fetch any data and you
will not receive an error message.

You use SelectByKeyEffdt to select information as of a specific date. It is used the same as SelectByKey, but
takes a date as its argument. The following statement returns the current row (EFFDT <= Today) from an
effective-dated table.
&MyRec.SelectByKeyEffDt(%Date);

448
Lesson 16 Executing SQL in PeopleCode

Executing SQL Using Record Objects (continued)

Insert, Update, and Delete


The Insert method uses the field names of the record object and their values to build and execute a SQL
Insert statement that adds a row of data to the SQL table.
&MyRec.Insert()

The Delete method deletes one row from the table referenced by the record object.

You need to uniquely identify the row by supplying values for all the keys.

If you do not supply all the keys, no deletion occurs.


&MyRec.Delete();
The Update method uses the changed fields of the record object and their values to build and execute a SQL
update statement, updating the SQL table.
&MyRec.Update();

Slide 283

Student Notes

Explaining Insert, Delete, and Update


These methods directly modify the database tables. They can be issued only in the following events:

FieldChange (as of 8.4)

SavePreChange

WorkFlow

SavePostChange

Important! Record object DML, that is, Update, Insert, and Delete, goes directly to the database, not to the
component buffer.

Insert
To extend the previous example, the following code changes the value in &MyRec.Resource_Name field and
then inserts a new row of data directly into the database table. The new row of data is a duplicate of the row
selected except for the new value in &MyRec.Resource_Name.

449
Executing SQL in PeopleCode Lesson 16

&MyRec.TASK.Value = &Task;
&MyRec.RESOURCE_NAME.Value = &Resource;
If &MyRec.SelectByKey() then
&MyRec.RESOURCE_NAME.Value = "Media Production";
&MyRec.Insert();
End-If;

Delete
The Delete property deletes one row from the table referenced by the record object. The process to delete a
row is very similar. You need to uniquely identify the row by supplying values for all the keys. If you do not
supply all the keys, no deletion occurs.
&MyRec.TASK.Value = &Task;
&MyRec.RESOURCE_NAME.Value = &Resource;
&MyRec.Delete();

Update
The Update method uses the changed fields in the record object and their values to build and execute a SQL
update statement, updating the SQL table.
&MyRec.TASK.Value = &Task;
&MyRec.TASK_RESOURCE.Value = &Resource;
&MyRec.PCT_AVAILABLE.Value = 100;
&MyRec.Update();

Important! If you are updating the key fields of the record, you must supply a record object KeyRecord that
contains the old values of the key record fields.

&MyRec.Update(&KeyRec);

450
Lesson 16 Executing SQL in PeopleCode

Incorporating Meta-SQL in PeopleCode and SQL

Meta-SQL
Meta-SQL resolves to platform-specific SQL substrings, causes another function to be called, or substitutes a
value.

Meta-SQL can be used virtually anywhere SQL is performed in PeopleSoft, including:

SQLExec functions.

SQL object methods.

Data buffer methods.

SQL views and dynamic views in Application Designer.


Meta-SQL provides platform-independence along with powerful and efficient processing features.

Slide 284

451
Executing SQL in PeopleCode Lesson 16

Incorporating Meta-SQL in PeopleCode and SQL (continued)

Date Processing
Because different databases handle date processing differently, PeopleSoft provides meta-SQL to handle the
translation.

%Datein converts a date to database format.

%Dateout converts a date selected from the database to standard output format.

%DateAdd adds the specified number of days to the date supplied and returns a date.

%DateDiff takes two dates and returns the number of days between them.

Slide 285

Student Notes

Example: Date Processing


Here is an example using %DateOut and %DateIn.
&SQL = CreateSQL("Select %DateOut(EFFDT) from %Table(PSU_INSTR_TBL)
where %DateIn(EFFDT) <= %DateIn(:1)", %Date);

Here is an example using %DateAdd and %DateDiff.


SQLExec("Update %Table(PSU_TASK_TBL) Set END_DT = %DateAdd(START_DT, 90)
Where TASK = :1", PSU_TASK_TBL.TASK);
SQLExec("Select %DateDiff(COURSE_END_DT,COURSE_START_DT) From
%Table(PSU_CRS_SESSN) Where COURSE = :1 And SESSION_NBR = :2", &Course,
&SessionNbr);

%DateIn, %DateOut
%Datein converts a date from PeopleSoft internal format to native database format. This is typically used to
supply input values for insert and update commands, or as criteria for comparisons in where clauses.
%Dateout converts a date that has been selected from the database to standard output format.

You can avoid confusion when using %Datein and %Dateout if you remember that the "in" functions are
used to pass values into the database and "out" functions are used to fetch something out of the database.
&SQL = CreateSQL("Select %DateOut(EFFDT) from %Table(PSU_INSTR_TBL)
where %DateIn(EFFDT) >= :1", %Date);

Note the use of the %Table meta-SQL, which prefixes "PS_" to the record name, and the %Date system
variable (not meta-SQL), which returns today's date on the server.

452
Lesson 16 Executing SQL in PeopleCode

%DateAdd, %DateDiff
%DateAdd adds the specified number of days to the date supplied and returns a date. The number of days
can be negative. %DateDiff takes two dates and returns the number of days between them.
SQLExec("Update %Table(PSU_TASK_TBL) Set END_DT = %DateAdd(START_DT, 90)
Where TASK = :1", PSU_TASK_TBL.TASK);
SQLExec("Select %DateDiff(COURSE_END_DT,COURSE_START_DT) From
%Table(PSU_CRS_SESSN) Where COURSE = :1 And SESSION_NBR = :2", &Course,
&SessionNbr);

Always use %Datein for inputting date literals.

453
Executing SQL in PeopleCode Lesson 16

Incorporating Meta-SQL in PeopleCode and SQL (continued)

%Concat and %Join


%Concat resolves to the database-specific concatenation operator.

%Join resolves to a Where clause that joins two tables, either on common keys or common fields.
%Join({COMMON_KEYS | COMMON_FIELDS}, join_recname
[ correlation_id1], to_recname [ correlation_id2] )

Slide 286

Student Notes

Example: %Concat
The following PeopleCode uses the %Concat meta-SQL meta-variable:
SELECT INSTRUCTOR
,FIRST_NAME %Concat ' ' %Concat LAST_NAME
FROM %Table(PSU_INSTR_TBL)

On the SQL Server, this code resolves to:


SELECT INSTRUCTOR, FIRST_NAME + ' ' + LAST_NAME
FROM PS_PSU_INSTR_TBL

On Oracle, this code resolves to:


SELECT INSTRUCTOR
,FIRST_NAME || ' ' || LAST_NAME
FROM PS_PSU_INSTR_TBL

Example: %Join
The following PeopleCode uses the %Join meta-SQL construct.
SELECT A.TASK
,A.RESOURCE_NAME
,B.EFFORT_DT
,B.EFFORT_AMT
FROM PS_PSU_TASK_RSRC A
,PS_PSU_TASK_EFFORT B
WHERE %Join(COMMON_KEYS, PSU_TASK_RSRC A, PSU_TASK_EFFORT B)

The preceding PeopleCode resolves to

454
Lesson 16 Executing SQL in PeopleCode

SELECT A.TASK , A.RESOURCE_NAME , B.EFFORT_DT , B.EFFORT_AMT


FROM PS_PSU_TASK_RSRC A , PS_PSU_TASK_EFFORT B
WHERE A.TASK = B.TASK
AND A.RESOURCE_NAME = B.RESOURCE_NAME

Using %Join
How do you join two tables?

On common keys (preferred)


%Join(COMMON_KEYS,Record1 A, Record2 B)

On common fields
%Join(COMMON_FIELDS,Record1 A, Record2 B)
Join on all the common keys (or all the common fields) or you will get a partial Cartesian joinmultiple
rows returned from the second table for every row in the first table.

The advantage of %Join with Common_Keys is that if the key structure of the record definition is changed,
the SQL is automatically changed to conform.

455
Executing SQL in PeopleCode Lesson 16

Activity 29: Choosing the Best SQL Option


In this activity, you will review the activity overview and list the advantages and disadvantages of the
different ways to execute SQL in PeopleSoft.

Slide 287

456
Lesson 16 Executing SQL in PeopleCode

Activity Overview
In this activity, you will discuss as a class the advantages and disadvantages of using the various options you
have learned for executing SQL in PeopleSoft. Bear in mind that the Component Processor is also using SQL
to select and update data in the database.

457
Executing SQL in PeopleCode Lesson 16

458
Lesson 16 Executing SQL in PeopleCode

Activity Detailed Steps


Perform the detailed steps to complete the activity.

Choosing the Best SQL Option


If one best way to do everything existed, you wouldn't need choices. PeopleSoft gives you several choices for
executing SQL because each option has its pros and cons in different situations.

Complete the following tables with the advantages and disadvantages of each option.

Component Processor

Advantages Disadvantages

SQL Definition

Advantages Disadvantages

SQLExec

Advantages Disadvantages

SQL Object

Advantages Disadvantages

Record Object

Advantages Disadvantages

459
Executing SQL in PeopleCode Lesson 16

This concludes the activity. Please do not continue.

460
Lesson 16 Executing SQL in PeopleCode

Searching PeopleCode for Potential SQL Injection

SQL Injection
SQL Injection is a technique that enables users to pass SQL to an application in a way that was not intended
by the developer.

SQL injection is usually caused by developers who use string-building techniques to generate SQL that is
subsequently executed.

Oracle recommends that you search your PeopleCode for SQL injection vulnerabilities.

In Application Designer, select Edit, Find In . .

For Find Type, select SQL Injection in PeopleCode.

Slide 288

461
Executing SQL in PeopleCode Lesson 16

Activity 30: Executing SQL in PeopleCode


In this activity, you will review the activity overview and upgrade a SQLExec to use object-oriented
PeopleCode. Then you will use a Record object to keep Effort Spent current.

Slide 289

462
Lesson 16 Executing SQL in PeopleCode

Activity Overview
In this activity, you will use two of the techniques you have learned to execute SQL statements from within
PeopleCode.

Use the appropriate SQL technique to accomplish the following tasks:

1. Upgrade a SQLExec to Object-Oriented PeopleCode.

Earlier in this lesson, you saw an example of a SQLExec that was used in SavePostChange to update the
Student Table, PSU_STUDENT_TBL, when an address was changed on the Customer Table,
PSU_CUST_TBL.

For this activity, you will:

Create a new SQL definition, add the SQL statement to it, and save as PSU_UPDATE_STUDENT.

Modify the code in the PSU_CUST component to use a SQL object and your new SQL definition.

Test. Change an address on the Customer Table. The change should appear on the Student Table for a
student who works for that customer and has Same Address as Customer selected.
2. Use a Record object to keep Effort Spent current.

In this lesson, you wrote some SQL that updated Effort Spent on the Task Table.

The problem is that Effort Spent is never updated until a user opens that page, which can lead to a data
integrity problem.

For instance, if someone were to use Effort Spent in a report, it would not necessarily be accurate.

Modify your application so that Effort Spent is always current.

Use a Record object in your solution.

463
Executing SQL in PeopleCode Lesson 16

Activity Detailed Steps


The following tasks are potential solutions to the activity.

Upgrading a SQLExec to Object-Oriented PeopleCode


Earlier in this lesson, you saw an example of a SQLExec that was used in SavePostChange to update the
Student Table, PSU_STUDENT_TBL, when an address was changed on the Customer Table,
PSU_CUST_TBL.

1. Create a new SQL definition, add the SQL statement to it, and save as PSU_UPDATE_STUDENT.
[PSU_UPDATE_STUDENT.0 (SQL Definition)]
UPDATE %Table(PSU_STUDENT_TBL)
SET STREET1 = :1, CITY = :2, STATE = :3, ZIP = :4, COUNTRY = :5, PHONE
= :6
WHERE CUSTOMER_ID = :7
AND SAME_ADDR_CUSTOMER = 'Y'

2. Modify the code in the PSU_CUST component to use a SQL object and your new SQL definition.
[PSU_CUST.GBL-SavePostChange]
If FieldChanged(PSU_CUST_TBL.STREET1) Or
FieldChanged(PSU_CUST_TBL.CITY) Or
FieldChanged(PSU_CUST_TBL.STATE) Or
FieldChanged(PSU_CUST_TBL.ZIP) Or
FieldChanged(PSU_CUST_TBL.COUNTRY) Or
FieldChanged(PSU_CUST_TBL.PHONE) Then
SQLExec(SQL.PSU_UPDATE_STUDENT, PSU_CUST_TBL.STREET1,
PSU_CUST_TBL.CITY, PSU_CUST_TBL.STATE, PSU_CUST_TBL.ZIP,
PSU_CUST_TBL.COUNTRY, PSU_CUST_TBL.PHONE, PSU_CUST_TBL.CUSTOMER_ID);
End-If;

Using a Record Object to Keep Effort Spent Current


In this lesson, you wrote some SQL that updated Effort Spent on the Task Table.

The problem is that Effort Spent is never updated until a user opens the Task Table page, even though it may
have been changed on the Task Resources page. This can lead to a data integrity problem.

For instance, if someone were to use Effort Spent in a report, it would not necessarily be accurate.

Modify your application so that Effort Spent is always current.

Use a Record object in your solution.

464
Lesson 16 Executing SQL in PeopleCode

[PSU_TASK_RESOURCES.GBL.PSU_TASK_EFFORT-SavePostChange]
Local Field &Amt;
Local Record &TaskRec;
&Amt = GetField(Effort_Amt);
If &Amt.IsChanged Then
SQLExec("Select Sum(EFFORT_AMT) from PS_PSU_TASK_EFFORT
where TASK = :1", PSU_TASK_EFFORT.TASK, &EffortSum);
&TaskRec = CreateRecord(Record.PSU_TASK_TBL);
&TaskRec.TASK.Value = PSU_TASK_EFFORT.TASK;
&TaskRec.EFFORT_SPENT.Value = &EffortSum;
&TaskRec.Update();
End-If;

This concludes the activity. Please do not continue.

465
Executing SQL in PeopleCode Lesson 16

Review
In this lesson, you learned that:

SQLExec statements can be used to execute SQL select and data manipulation statements from within
PeopleCode.

SQL definitions are a flexible means to write and store SQL statements that are maintainable, reusable, and
platform-independent.

SQL objects offer another, more flexible means to execute SQL in PeopleCode.

Record objects extend the power of SQL objects by leveraging the structure of record definitions.

Meta-SQL facilitates database independence and cross-platform compatibility.

You can search for areas where SQL injection could be used to bypass security using the Find In ... tool in
Application Designer.

Slide 290

Student Notes

Additional Resources
This table lists additional resources that provide more details about the topics that we discussed in this lesson:

Topic Cross-Reference

Creating SQL Definitions PeopleTools 8.50 PeopleBook: PeopleCode Developer's


Guide,Introducing the SQL Editor

Using the SQL Class PeopleTools 8.50 PeopleBook: PeopleCode API


Reference, SQL Class

Executing SQL Using Record Objects PeopleTools 8.50 PeopleBook: PeopleCode API
Reference, Record Class

Incorporating Meta-SQL in PeopleCode and SQL PeopleTools 8.50 PeopleBook: PeopleCode Language
Reference, Meta-SQL.

Searching PeopleCode for Potential SQL Injection PeopleTools 8.50 PeopleBook: PeopleCode Developer's
Guide, Introducing What's New

466
Lesson 17

Charting

Objectives
By the end of this chapter, you will be able to:

Describe the Charting classes.

Describe the Chart class.

Describe the Gantt class, OrgChart class, and RatingBoxChart class.

Slide 292

467
Charting Lesson 17

Describing the Charting Classes

Overview of the Charting Classes


The charting classes are:

Chart

Use the Chart class to visually display data series in common formats, such as bar charts, line charts, pie
charts, and bubble charts.

Gantt

Use the Gantt class to create interactive Gantt charts that visually display data related to projects and tasks.

OrgChart

Use the OrgChart class to create interactive organizational charts that enable you to visually represent a
hierarchy of information as a series of connected nodes.

RatingBoxChart

Use the RatingBoxChart class to create rating box charts that enable you to display and manipulate points
of information in two-dimensional bins.

Slide 293

Student Notes

Creating PeopleSoft Charts


This section provides an overview of the process of creating charts using any of the PeopleSoft charting
classes. Further details can be found in the specific section for each chart class.

Font Considerations

The environment variable JAVA_FONTS must be set correctly so the fonts that are used in charting can be
picked up by the application server's Java Virtual Machine. It must be set to include the paths to any
TrueType fonts that are used to support extended languages.

468
Lesson 17 Charting

Component Processor Considerations

Sometimes records at level zero on a page are considered work records, even when they aren't specified as
such in PeopleSoft Application Designer. Work records are not updated by the database and are skipped
when the component is run.

A level zero record gets marked as a work record when:

All the fields for the record are used as read-only fields.

All the values for these fields can be read from the input keys.

When a chart field is attached to a level-zero record field of a record considered a work record, it is also
skipped when the system determines that record's 'work' status.

Translation

If you hardcode a value for a label, a title, a data hint, and so on, that value is not translated. Be sure to
specify field values as message catalog entries that will be translated.

Labels and iScripts


Labels

Chart labels are shown based on the size of the axis, fonts, and charts on the page. If all the labels are not
displaying for your chart, you should either make the chart larger or the font smaller.

Pie chart labels are staggered, so that, in most cases, both labels can be read. However, if one or both of the
labels are very long, they could be truncated or completely missing from the chart.

For Gantt charts, use double quotes to correctly display the use of single quotes in your label, if applicable

iScripts

Charts are generated using the chart control on a page,and these charts are generated at runtime and used in
an iScript.

To build a chart at runtime, use the CreateObject function instead of the GetChart function. You can then
use the GetChartURL Response class method to use the URL in your application.

The following is an example of building a chart using a standalone rowset:


Function IScript_GetChartURL()
local object &MYCHART;
local string &MYURL;
&MYCHART = CreateObject("Chart");
&MYCHART.SetData(xx);/* xx will be either a record definition or an
instantiated rowset */
&MYURL = %Response.GetChartURL(&MYCHART);/* use &MYURL in your
application */
...
End-Function;

469
Charting Lesson 17

StyleSheets
Style Sheets

A style sheet is a definition that you create in PeopleSoft Application Designer. It contains a collection of
formatting styles (called classes) each of which can be applied to either the entire chart or to specific
elements within a chart.

The default style sheet associated with a PeopleSoft Chart is PTSTYLEDEF.

The following style sheet properties are supported for PeopleSoft charting:

1. Font Family

2. Font Foreground Color

3. FontSize

4. Font Style (only Normal and Italic are supported.)

5. Font Weight (only Normal and Bold are supported)

Error Handling

470
Lesson 17 Charting

Describing the Chart Class

Creating Charts Using the Chart Class


A chart contains these major parts:

X Axis

The axis that data is measured against.

Y Axis

The axis that contains the data. In most charts, this is the vertical axis. In a horizontal bar chart, this is the
horizontal axis.

Overlay

Related data represented by a line drawn over the background chart. You can also specify a data series with
different line types for each overlay.

Slide 294

471
Charting Lesson 17

Describing the Chart Class (continued)

Creating Charts Using the Chart Class (continued)


A chart contains these major parts:

Legend

Text that identifies the different series in the chart.

Data

Text that identifies the data on one of the axes.

Title

The three titles are Main, X axis, and Y axis. Each title identifies that portion of the chart.

Slide 295

472
Lesson 17 Charting

Describing the Chart Class (continued)

ChartClass Chart Types


The following chart types are available for the Chart class:

2DBar

2D Histogram

2D Horizontal Bar

2D Horizontal Percent Bar

2D Horizontal Stacked Bar

2DLine

2D Percent Bar

Slide 296

473
Charting Lesson 17

Describing the Chart Class (continued)

ChartClass Chart Types (continued)

2DPie

2D Scatter

2D Stacked Bar

3DBar

3D Percent Bar

3DPie

3D Stacked Bar

Slide 297

474
Lesson 17 Charting

Describing the Chart Class (continued)

2D Bar
This is an example of a two-dimensional bar chart:

Slide 298

475
Charting Lesson 17

Describing the Chart Class (continued)

2D Histogram
This is an example of a two-dimensional histogram chart:

Slide 299

476
Lesson 17 Charting

Describing the Chart Class (continued)

2D Horizontal Bar
This is an example of a two-dimensional horizontal bar chart:

Slide 300

477
Charting Lesson 17

Describing the Chart Class (continued)

2D Horizontal Stacked Bar


This is an example of a two-dimensional horizontal stacked bar chart:

Slide 301

478
Lesson 17 Charting

Describing the Chart Class (continued)

2D Horizontal Percent Bar


This is an example of a two-dimensional horizontal percent bar chart:

Slide 302

479
Charting Lesson 17

Describing the Chart Class (continued)

2D Line
This is an example of a two-dimensional line chart without numeric axes; IsTrueXY is specified as False:

Slide 303

480
Lesson 17 Charting

Describing the Chart Class (continued)

2D Percent Bar
This is an example of a two-dimensional percent bar chart:

Slide 304

481
Charting Lesson 17

Describing the Chart Class (continued)

2D Pie
This is an example of a two-dimensional pie chart:

Slide 305

482
Lesson 17 Charting

Describing the Chart Class (continued)

2D Scatter
This is an example of a two-dimensional scatter chart:

Slide 306

483
Charting Lesson 17

Describing the Chart Class (continued)

2D Stacked Bar
This is an example of a two-dimensional stacked bar chart:

Slide 307

484
Lesson 17 Charting

Describing the Chart Class (continued)

3D Bar
This is an example of a three-dimensional bar chart:

Slide 308

485
Charting Lesson 17

Describing the Chart Class (continued)

3D Percent Bar
This is an example of a three-dimensional percent bar chart:

Slide 309

486
Lesson 17 Charting

Describing the Chart Class (continued)

3D Pie
This is an example of a three-dimensional pie chart:

Slide 310

487
Charting Lesson 17

Describing the Chart Class (continued)

Chart Class Methods


Basic methods and properties of the Chart class are:

Refresh

Use the Refresh method if the underlying data of the chart has changed and you want to update the chart.

Syntax:
&MyChart.Refresh()

Example:

&MyChart.Refresh();

Reset

Use the Reset method to clear all existing chart settings and data.

Syntax:
&MyChart.Reset()

Slide 311

488
Lesson 17 Charting

Describing the Chart Class (continued)

Chart Class Methods (continued)


Basic methods and properties of the Chart class are:

SetColorArray

Use the SetColorArray method to set the colors for a series. You can specify only a one-dimensional array
for the parameter. This method applies only to base chart data, not to overlay data.

Syntax:
&MyChart.SetColorArray(&Array_of_Color)

SetData

Use the SetData method to specify where the data from the chart originated.

Syntax:
&MyChart.SetData({Record_Name | &Rowset})

Slide 312

489
Charting Lesson 17

Describing the Chart Class (continued)

Chart Class Methods (continued)


Basic methods and properties of the Chart class are:

SetDataAnnotations

Use the SetDataAnnotations method to specify an optional text label that can be associated with each point
in the chart.

Syntax:
&MyChart.SetDataAnnotation(Record_Name.Field_Name)

SetDataGlyphScale

Use the SetDataGlyphScale method to specify a field that contains numeric data that defines the size of
each glyph. These values are mapped to a range of size values between a predefined minimum and
maximum.

Syntax:
&MyChart.SetDataGlyphScale(Record_Name.Field_Name)

Slide 313

490
Lesson 17 Charting

Describing the Chart Class (continued)

Chart Class Methods (continued)

SetDataSeries

Syntax:
&MyChart.SetDataSeries(Record_Name.Field_Name)

Use the SetDataSeries method to specify the name of the field containing the series values. Every distinct
value in this field is considered a unique series.

SetDataXAxis

Syntax:
&MyChart.SetDataXAxis(Record_Name.Field_Name)

Use the SetDataXAxis method to specify the groups along the X axis. If this value is not set or is Null, the
Y values are plotted along the X axis in groups labeled by their order number. The order of the data is
plotted in the order of the data in the record. By default, the labels along the X axis are populated by the
value of this field.

Slide 314

491
Charting Lesson 17

Describing the Chart Class (continued)

Chart Class Methods (continued)


SetDataYAxis

Syntax:
&MyChart.SetDataYAxis(Record_Name.Field_Name)

Use the SetDataYAxis to specify the data to plot in the chart. The Y axis is always considered the data axis.
The Y axis must always be numeric. If the greatest Y-axis value is less than 10, the Y-axis labels are given a
decimal place. If the greatest Y-axis value is greater than or equal to 10, the Y-axis labels appear as integers.

Slide 315

492
Lesson 17 Charting

Describing the Chart Class (continued)

Example: Creating a Chart


At a minimum, you need the following code to create a PeopleSoft chart:
Local Chart &MyChart;
&MyChart = GetChart(ABS_HIST.CHART);
&MyChart.SetData(ABS_HIST);
&MyChart.SetDataYAxis(ABS_HIST.Reason);
&MyChart.SetDataXAxis(ABS_HIST.Duration);

Slide 316

493
Charting Lesson 17

Describing the Chart Class (continued)

Example: Creating a Chart (continued)

Function IScript_GetChartURL()
local object &MYCHART;
local string &MYURL;
local rowset &MYROWSET;
&MYCHART = CreateObject("Chart");
&MYROWSET = CreateRowset(Record.ABS_HIST);
&EmplID = %Emplid;
&MYROWSET.Fill("Where EMPLID :=1", &EmplID);
&MYCHART.SetData(&MYROWSET);
&MYCHART.SetDataXAxis(ABS_HIST.ABSENCE_TYPE);
&MYCHART.SetDataYAxis(ABS_HIST.DURATION_DAYS);
&MYURL = %Response.GetChartURL(&MYCHART);
/* use &MYURL in your application */
...
End-Function;

Slide 317

494
Lesson 17 Charting

Describing the Chart Class (continued)

Example: Creating a Chart (continued)


The Chart class uses these properties:

DataStartRow

DataWidth

StyleSheet

Type

Width

Height

Slide 318

495
Charting Lesson 17

Describing the Chart Class (continued)

Chart Class Properties


The Chart class uses these properties:

XAxisMax

XAxisMin

XAxisScaleResolution

XAxisStyle

XAxisTicks

XAxisTitle

YAxisMax

YAxisMin

YAxisStyle

YAxisTitle

Slide 319

496
Lesson 17 Charting

Describing the Gantt Class, OrgChart Class, and RatingBoxChart


Class

Methods and Properties of Gantt Class


The Gantt class uses these methods.

Refresh

Returns

Reset

SetActualEndDate

SetActualStartDate

SetActualTaskBarColor

SetChartArea

SetDayFormat

SetHourFormat

SetPlannedTaskBarColor

Slide 320

497
Charting Lesson 17

Describing the Gantt Class, OrgChart Class, and RatingBoxChart


Class (continued)

Methods and Properties of Gantt Class (continued)


The Gantt class uses these properties, among others:

AxisEndDateTime

AxisStartDateTime

DataEndDateTime

DataStartDateTime

GridLines

Slide 321

498
Lesson 17 Charting

Describing the Gantt Class, OrgChart Class, and RatingBoxChart


Class (continued)

Methods and Properties of OrgChart Class


The OrgChart class uses the methods defined for the Chart class plus these:

SetLegend

SetLegendImg

SetNodeData

SetPopUpNodeData

SetPopUpNodeRecord

Slide 322

499
Charting Lesson 17

Describing the Gantt Class, OrgChart Class, and RatingBoxChart


Class (continued)

Methods and Properties of OrgChart Class (continued)


The OrgChart class uses these propeties:

Collapsed_Msg

CollapsedImage

Direction

Expanded_Msg

Height

MainTitleStyle

Slide 323

500
Lesson 17 Charting

Describing the Gantt Class, OrgChart Class, and RatingBoxChart


Class (continued)

Methods and Properties of RatingBoxChart Class


The RatingBoxChart class uses these methods:

setlegend

setlegendImg

setRBnodedata

SetRBNodeRecord

SetXAxisLabels/SetYAxisLabels

Slide 324

501
Charting Lesson 17

Describing the Gantt Class, OrgChart Class, and RatingBoxChart


Class (continued)

Methods and Properties of RatingBoxChart Class (continued)


The RatingBoxChart class uses these properties.

GridLineType

HasLegend

LegendPosition

MainTitleStyle

ShowNodeDescription

XAxisBoxNum

Slide 325

502
Lesson 17 Charting

Activity 31: Creating a Bar Chart


In this activity, you will review the activity overview and create a bar chart.

Slide 326

503
Charting Lesson 17

Activity Overview
In this activity, you will review the methods and properties needed to create a bar chart.

You will create a chart from a record that contains fields relating to sales, the month, and the product. The
series in the chart will be based on the product.

504
Lesson 17 Charting

Activity Detailed Steps


Perform the detailed steps to complete the activity.

1. Open PeopleSoft Application Designer.

2. Open the page where the chart is to be inserted.

3. Insert the chart control by either:

a. Clicking the chart icon in the toolbar.

b. Selecting Insert, Chart.

4. Draw the chart control on the page.

5. Associate the chart control with a record field.

Every chart control must be associated with a record field. This is the field for the chart control; it is not
the field used to drill down to the chart data:

Bring up the chart control properties by either Double-clicking on the chart control, or

Right-clicking on the chart control and selecting Page Field Properties.


6. On the Record tab of the chart control properties, select the record name and field for the chart.

To make the control a page anchor, select the Enable as Page Anchor on the General tab.

7. Write your PeopleCode.

In some event on the page, such as Activate, put the PeopleCode you need for populating the chart.

8. Get the chart using the record and field name that you associated with the chart control on the page:
&oChart = GetChart(QE_CHART_DUMREC.QE_CHART_FIELD);

9. Set the data records.

The SetData function associates the record data with the chart. You will then use the SetDataYAxis and
SetDataXAxis functions to associate specific fields in the record with the Y axis data and the X-axis data:
&oChart.SetData(Record.QE_CHART_RECORD);

&oChart.SetDataYAxis(QE_CHART_RECORD.QE_CHART_SALES);

&oChart.SetDataXAxis(QE_CHART_RECORD.QE_CHART_PRODUCT);

Note. This is all the code you need to create the chart. You do not need to set the chart type; the default is
a 2D bar chart. You do not need to set the series unless you want to group your data. All other steps are
optional.

10. (Optional) Set the data series.

We want to set the region as the series. This means that the data will be grouped according to the region.
&oChart.SetDataSeries(QE_CHART_RECORD.QE_CHART_REGION);

505
Charting Lesson 17

11. (Optional) Set the chart type.

Because we want a stacked bar for the chart, we must set the Type property of the chart. This means that
each product (footballs, rackets, and so on) will have a single bar, and the data series (California, Oregon,
and so on) will be stacked.
&oChart.Type = %ChartType_2DStackedBar;

12. (Optional) Set legend and label attributes.

We want a legend and we want it to appear on the right side. In addition, because the text of the series
labels is so large, the labels must be vertical to display all of them.
&oChart.HasLegend = True;

&oChart.LegendPosition = %ChartLegend_Right;

&oChart.XAxisLabelOrient = %ChartText_Vertical;

506
Lesson 17 Charting

Review
In this lesson, you learned that:

You use the Chart class to visually display data series in common formats, including bar charts, line charts,
pie charts, and bubble charts.

To build a chart at runtime, use the CreateObject function instead of the GetChart function.

You can use the XAxisScaleResolution property to increase or decrease the number of marks and labels on
the X axis.

Slide 327

Student Notes

Additional Resources
This table lists additional resources that provide more details about the topics that we discussed in this lesson:

Topic Cross-Reference

For More on Methods and Properties of different Chart Enterprise PeopleTools 8.50 PeopleBook: PeopleCode
Classes API Reference , "Chart Classes"

507
Lesson 18

Course Workshop

Objectives
By the end of this lesson, you will be able to use a standalone rowset to track overtime hours.

Slide 329

509
Course Workshop Lesson 18

Activity 32: Using a Standalone Rowset to Track Overtime


Hours
In this activity, you will review the activity overview and write a PeopleCode program that tracks overtime
hours using a standalone rowset.

Slide 330

510
Lesson 18 Course Workshop

Workshop Overview
In this activity, you will have the opportunity to bring together some of the concepts you have learned.

A requirement has been identified to place a field on the Task page that will track overtime hours for each
task.

To accomplish this, you will need to create a standalone rowset that contains all the efforts for a task. Then
loop through that rowset and check each row for effort amount. If the effort is greater than 8, add the amount
over 8 to an accumulator.

(You may think of another way to accomplish this. Try it first using a standalone rowset, then when this is
working, try it your way.)

Display the accumulator on the Task page. Include a button on the Task page to refresh the Total Overtime
field.

After you get your SQL working with a quoted literal, store the SQL statement in a SQL definition and
modify your program to use the SQL definition.

511
Lesson 19

Course Review

Objectives
In this course, you learned how to:

Describe PeopleCode.

Use the PeopleCode development tools to write, edit, and debug PeopleCode programs.

Write PeopleCode programs and choose the events in which to place them.

Manipulate data in the component buffer.

Program with object-oriented PeopleCode.

Manipulate data in the data buffers and in SQL tables.

Slide 332

513
Course Review Lesson 19

Describing PeopleCode

Uses
PeopleCode is used to:

Control presentation of information to the user.

Validate user inputs and maintain data integrity.

Perform calculations and data manipulation.

Update database tables.

Manage portal navigation and administer security.

Integrate with other PeopleSoft applications and with third-party applications.

Manage workflow.

Slide 333

514
Lesson 19 Course Review

Using the PeopleCode Development Tools

The PeopleCode Editor


The PeopleCode Editor:

Automatically formats the code when you save, including indents, spaces, and capitalization.

Validates your syntax. Any syntactic errors are reported so that you can fix them.

Supports drag and drop of definition names or text from the Project Workspace, another definition window,
or another Editor window.

Enables you to open any definition or view PeopleCode on any definition referenced in the program with a
right-click.

Provides context-sensitive help for any PeopleCode built-in function, system variable, or meta-SQL
function.

Automatically backs up your program every keystroke.

As of PeopleTools 8.50, the PeopleCode Editor is color coded.

Slide 334

515
Course Review Lesson 19

Using the PeopleCode Development Tools (continued)

The PeopleCode Debugger


The PeopleCode Debugger includes the following features:

It is integrated into the Application Designer.

It has a visual breakpoints indicator.

It enables you to step through code.

Variables panes enable you to inspect values in variables and function parameters.

PeopleCode objects can be expanded so that you can inspect their component parts.

Slide 335

516
Lesson 19 Course Review

Writing PeopleCode Programs and Choosing Events

When, Where, and What


Before you write a PeopleCode program, you to need to decide three things:

WHEN you want to have it runwhich event or events in the flow of the Component Processor are most
appropriate for your rule.

WHERE to place your PeopleCodeon which definition, and perhaps on which field.

WHAT to programthe code syntax.

Slide 336

517
Course Review Lesson 19

Writing PeopleCode Programs and Choosing Events (continued)

PeopleCode Events
These principles apply to PeopleCode events:

Every PeopleCode program is associated with a PeopleSoft Application Designer definition and with an
event.

Events are predefined exit points in the Component Processor flow.

As each point is encountered, the event runs PeopleCode for that event on each definition.

Certain definitions in Application Designer can have an event seta group of events that are appropriate to
that definition.

A definition can have zero or one PeopleCode programs for each event in its event set.

Slide 337

518
Lesson 19 Course Review

Writing PeopleCode Programs and Choosing Events (continued)

Definitions
PeopleCode can be associated with the following definitions:

Within the Component Processor Flow Outside the Component Processor Flow

Record Field Component Interface


Menu Message
Component Application Engine
Page

Slide 338

519
Course Review Lesson 19

Writing PeopleCode Programs and Choosing Events (continued)

PeopleCode Statements
A PeopleCode program is made up of statements.

A statement can be:

A declaration of variables or objects.

An assignment.

A program construct (such as a Warning statement or a conditional loop).

A function call.

A comment.
Every PeopleCode statement should end in a semicolon.

Slide 339

520
Lesson 19 Course Review

Manipulating Data in the Component Buffer

Buffer Allocation Rules


The following rules apply to Level 0:

For search keys and alternate search keys, only those fields are loaded.

Any other fields from the level 0 record, the entire row is loaded.
The following rules apply to the scroll levels (1 through 3):

If one field from a scroll's primary record definition is placed on a page, all fields from that record
definition are retrieved into the component buffer.

Related-display field that field is loaded, plus fields referenced by PeopleCode.

Derived/workonly that field is loaded.

Slide 340

521
Course Review Lesson 19

Programing with Object-Oriented PeopleCode

Definitions
To discuss object-oriented programming, you need to understand these terms:

Class The formal definition of an object.

Object A data structure in memory, created from its class.

Instance An object is an instance, a unique runtime copy, of a class in memory.

Instantiate To create an instance of an object by using a function or method.

Property An attribute of an object.

Method The code associated with a given object.

Dot Notation The means by which you access an object's properties or execute its
methods.

Slide 341

522
Lesson 19 Course Review

Manipulating Data in the Data Buffers and in SQL Tables

Data Buffer Methods


You learned that:

You use the Sort method to control the ordering of individual scrollable areas.

You use the Select method to populate a scroll buffer.

You use the Flush method to clear a scroll buffer.

Standalone rowsets have a data structure based on a record definition but do not reference data in the
component buffer.

Other buffer methods you can use to perform custom processing on fields and rows include GetRelated,
CopyFieldsTo,CopyTo,InsertRow, and DeleteRow.

Slide 342

523
Course Review Lesson 19

Manipulating Data in the Data Buffers and in SQL Tables (continued)

Executing SQL in PeopleCode


You learned that:

SQLExec statements can be used to execute SQL select and data manipulation statements from within
PeopleCode.

SQL definitions are a flexible means to write and store SQL statements that are maintainable, reusable, and
platform independent.

SQL objects offer another, more flexible means to execute SQL in PeopleCode.

Record objects extend the power of SQL objects by leveraging the structure of record definitions.

Meta-SQL facilitates database independence and cross-platform compatibility.

You can search for areas where SQL injection could be used to bypass security using the Find In ... tool in
Application Designer.

Slide 343

524
Appendix A

Course Workshop Solution

Using a Standalone Rowset to Track Overtime Hours


To place a field on the Task page that will track total overtime hours for a each task, perform the following
tasks:

1. Display the accumulator on the Task page.

2. Create a standalone rowset.

3. Populate the rowset using a data buffer method.

4. Loop through the rows in the rowset to check overtime hours.

Displaying the Accumulator on the Task Page


To display the accumulator on the Task page:

1. Create a new number field, TOTAL_OT.

2. Add TOTAL_OT to the DERIVED_TRAIN record definition.

3. Place a display-only field on the page and associate the field with DERIVED_TRAIN.TOTAL_OT.

4. Put a button on the Task page to refresh the Total Overtime field.

5. Associate it with the field DERIVED_ED_SVCS.REFRESH_BTN.

Creating a Standalone Rowset


To create a standalone rowset, enter the following code on the PSU_TASK_TBL component.
[PSU_TASK.GBL.DERIVED_ED_SVCS-RowInit]

and
[PSU_TASK.GBL.DERIVED_ED_SVCS.REFRESH_BTN-FieldChange]
Local Rowset &TaskEffort;
Local number &N, &OT, &I;
&TaskEffort = CreateRowset(Record.PSU_TASK_EFFORT);

525
Course Workshop Solution Appendix A

Populating the Rowset Using a Data Buffer Method


Add the following code to the programs you wrote in the previous step.
&N = &TaskEffort.Fill("Where TASK = :1", PSU_TASK_TBL.TASK);

Looping Through the Rows in the Rowset to Check Overtime Hours.


Loop through your rowset and check each row for Effort Amount. If the effort is greater than 8, add the
amount over 8 to an accumulator.

Add the following code to the programs you wrote in the previous step.
DERIVED_TRAIN.TOTAL_OT.SetDefault();
For &I = 1 To &N
&OT = &TaskEffort(&I).PSU_TASK_EFFORT.EFFORT_AMT.Value - 8;
If &OT > 0 Then
DERIVED_TRAIN.TOTAL_OT = DERIVED_TRAIN.TOTAL_OT + &OT;
End-If;
End-For;

526
Appendix B

Component Processor Flow

Flow Chart and Table of Events


This appendix contains:

Component Processor flow chart with PeopleCode events.

Table of PeopleCode events.

Component Processor Flow Chart with PeopleCode Events


This chart shows the flow for all PeopleCode events in the Component Processor.

527
Component Processor Flow Appendix B

528
Appendix B Component Processor Flow

Table of PeopleCode Events


This table summarizes the PeopleCode events:

529
Component Processor Flow Appendix B

Field- Errors or
Event Abbr Locations Function Specific Warnings

SearchInit SrI RF Initialize search page values. Yes* No


CR Set initial display characteristics for
these fields (for example, restrict the
keys used for security).

SearchSave SrS RF Edit or validate key values entered into Yes* Yes
the search page (for example, to force
CR
the user to enter a key or partial key
value).
*SearchInit and SearchSave can only be
placed on the search or alternate search
keys of the search record.

RowSelect RSe RF Currently not used. No Yes*


CR
Used in prior PeopleTools releases to
filter rows of data into the component
buffer.

*Errors and warnings are no longer


used.

PreBuild C Set initial display characteristics that run NA No*


only once during the initial component
build.
For example, hide and unhide pages, set
component and global variables.
*Technically, PreBuild accepts errors
and warnings, but it is not
recommended.

FieldDefault FDe RFCRF Used for the conditional assignment Yes No


of default values.

Runs only if the field it is attached to


has no value.

Remember, any record default takes


precedence.

FieldFormula FFo RF Used in prior PeopleTools releases to NA NA


perform calculations.

Now used to store application-specific


functions and web libraries.

Not generally used anymore as part of


the event flow.

530
Appendix B Component Processor Flow

Field- Errors or
Event Abbr Locations Function Specific Warnings

RowInit RIn RF Usually used to calculate values and to No No


set initial display characteristics.
CR

PostBuild C Set initial display characteristics that run NA No


only once during the initial component
build.
For example, hide and unhide pages,
perform calculations, set component and
global variables.

Activate Page Used for processing related to a specific NA No


page. Can be used to apply security,
hide and unhide a page.
Used to initialize grid object properties.

FieldEdit FEd RF Validate one enabled field. (Starting in Yes Yes


version 7, allows assignment statements
CRF
for all fields except the one being
validated, but should be in FCh
anyway.)

FieldChange FCh RF "Other processing": calculate values and Yes No


set display characteristics.
CRF

RowInsert RIs RF Simulate or override effective dating No No


(For example, clearing out a comment
CR
field to initialize it) and auto-increment
row numbers.

RowDelete RDe RF Recalculate totals, conditionally prevent No Yes


deletion, auto-decrement row numbers.
CR

SaveEdit SEd RF Cross-validation of two or more enabled No Yes


fields. Last point of user interaction.
CR

SavePreChange SPr RF "Other processing." No No


CR For example, set high-level key. Last
chance to modify data before it's written
C
out to the database.

Workflow Wrk RF Trigger electronic routings. No No


C

531
Component Processor Flow Appendix B

Field- Errors or
Event Abbr Locations Function Specific Warnings

SavePostChange SPo RF Update other tables not present in the No No


CR component buffer.

C Also used for sending messages.

Used to manage referential integrity of


database tables that are not in the buffer
but are affected by user changes.

532
Appendix C

Buffer Access Classes and SQL Class


Quick Reference

Rowset Class
These tables show functions, methods, and properties for the rowset class:

Functions

This table shows functions for the rowset class:

Function Returns

CreateRowset({RECORD.recname|&Rowset} [, {FIELD.fieldname, RECORD. Rowset object


recname|&Rowset}] . . .)

GetLevel0() Rowset object

GetRowset([SCROLL.recordname]) Rowset object

Methods

This table shows methods for the rowset class:

533
Buffer Access Classes and SQL Class Quick Reference Appendix C

Method Returns

CopyTo(&DestRowset[, RECORD.SourceRecname,RECORD.DestRecname]. . .)

DeleteRow(n) Boolean

Fill([wherestring[,bindvalue] . . .]) Number

FillAppend([wherestring[,bindvalue] . . .]) Number

Flush()

FlushRow(n)

GetCurrEffRow() Row Object

GetNewEffRow() Row Object

*GetRow(n) Row Object

HideAllRows()

InsertRow(n) Boolean

Refresh()

Select([parmlist], RECORD.selrecord[ ,wherestr,bindvars]) Number

SelectNew([parmlist], RECORD.selrecord[,wherestr,bindvars]) Number

SetDefault(recname.fieldname)

ShowAllRows()

Sort([paramlist,]sort_fields)

Properties

This table shows properties for the rowset class:

534
Appendix C Buffer Access Classes and SQL Class Quick Reference

Property Returns

ActiveRowCount Number, RO

ChangeOnInit Boolean

DataAreaCollapsed Boolean

DBRecordName String, RO

DeleteEnabled Boolean

EffDt Date, RO

EffSeq Number, RO

InsertEnabled Boolean

IsEditError Boolean, RO

Level Number, RO

Name String, RO

ParentRow Row Object, RO

ParentRowSet Rowset Object, RO

RowCount Number, RO

TopRowNumber Number, RO

Row Class
These tables show functions, methods, and properties for the row class:

Functions

This table shows functions for the row class:

Function Returns

GetRowset([SCROLL.scrollname]) Rowset object

Methods

This table shows methods for the row class:

535
Buffer Access Classes and SQL Class Quick Reference Appendix C

Method Returns

CopyTo(rowobject) Row Object

GetNextEffRow() Row Object

GetPriorEffRow() Row Object

*GetRecord(n/RECORD.recname) Record Object

GetRowSet(n/SCROLL.recordname) Rowset Object

scrollname(n) Row Object

Properties

This table shows properties for the row class:

Property Returns

ChildCount Number, RO

DeleteEnabled Boolean

IsChanged Boolean, RO

IsDeleted Boolean, RO

IsEditError Boolean, RO

IsNew Boolean, RO

ParentRowSet Rowset object, RO

recname Record object, RO

RecordCount Number, RO

RowNumber Number, RO

Selected Boolean

Style String

Visible Boolean

Record Class
These tables show functions, methods, and properties for the record class:

536
Appendix C Buffer Access Classes and SQL Class Quick Reference

Functions

This table shows functions for the record class:

Function Returns

CreateRecord(RECORD.recname) Record object

GetRecord([RECORD.recname]) Record object

Methods

This table shows methods for the record class:

Method Returns

CompareFields(RecordObject) Boolean

CopyChangedFieldsTo(RecordObj)

CopyFieldsTo(RecordObject)

Delete() Boolean

ExecuteEdits([EditLevel])

*GetField(n/FIELD.fieldname) Field Object

Insert() Boolean

SearchClear()

SelectByKey() Boolean

SelectByKeyEffDt(Date) Boolean

SetDefault()

SetEditTable(%PromptField, RECORD.recname)

Update([KeyRecord]) Boolean

Properties

This table shows properties for the record class:

537
Buffer Access Classes and SQL Class Quick Reference Appendix C

Property Returns

FieldCount Number, RO

fieldname Field Object, RO

IsChanged Boolean, RO

IsDeleted Boolean, RO

IsEditError Boolean, RO

Name String, RO

ParentRow Row Object, RO

RelLangRecName String, RO

Field Class
These tables show functions, methods, and properties for the field class:

Functions

This table shows functions for the field class:

Function Returns

GetField([recname.fieldname]) Field object

Methods

This table shows methods for the field class:

538
Appendix C Buffer Access Classes and SQL Class Quick Reference

Method Returns

GetAuxFlag(FlagNumber) Boolean

GetLongLabel(LabelID) String

GetRelated(recname.fieldname) Field object

GetShortLabel(LabelID) String

SearchClear()

SetCursorPos(PAGE.pagename| %Page)

SetDefault()

Properties

This table shows properties for the field class:

539
Buffer Access Classes and SQL Class Quick Reference Appendix C

Property Returns

DataAreaCollapsed Boolean

DisplayFormat String

DisplayOnly Boolean

EditError Boolean

Enabled Boolean

FieldLength Number, RO

FormattedValue String

IsAltKey Boolean, RO

IsAuditFieldAdd Boolean, RO

IsAuditFieldChg Boolean, RO

IsAuditFieldDel Boolean, RO

IsAutoUpdate Boolean, RO

IsChanged Boolean, RO

IsDateRangeEdit Boolean, RO

IsDescKey Boolean, RO

IsDupKey Boolean, RO

540
Appendix C Buffer Access Classes and SQL Class Quick Reference

Property Returns

IsEditTable Boolean, RO

IsEditXlat Boolean, RO

IsFromSearchField Boolean, RO

IsInBuf Boolean, RO

IsKey Boolean, RO

IsListItem Boolean, RO

IsRequired Boolean, RO

IsSearchItem Boolean, RO

IsSystem Boolean, RO

IsThroughSearchField Boolean, RO

541
Buffer Access Classes and SQL Class Quick Reference Appendix C

Property Returns

IsUseDefaultLabel Boolean, RO

IsYesNo Boolean, RO

Label String

LabelImage {Image.imagename | String}

LongTranslateValue Any

MessageNumber Number, RO

MessageSetNumber Number, RO

Name String, RO

OriginalValue Depends on field

ParentRecord Record Object, RO

PromptTableName String, RO

SeachDefault Boolean

SearchEdit Boolean

ShortTranslateValue Any

ShowRequiredFieldCue Boolean

SqlText String

StoredFormat String, RO

Style String

Type String, RO

Value Depends on field

Visible Boolean

SQL Class
These tables show functions, methods, and properties for the SQL class:

542
Appendix C Buffer Access Classes and SQL Class Quick Reference

Functions

This table shows functions for the SQL class:

Function Returns

CreateSQL(sqlstring [, paramlist])

DeleteSQL([SQL.]sqlname [ , dbtype [ , effdt]]] ) Boolean

FetchSQL([SQL.]sqlname [ , dbtype [ , effdt ]] ) String

GetSQL(SQL.sqlname [, paramlist]) SQL object

StoreSQL(sqlstring, [SQL.]sqlname [ , dbtype [ , effdt]] )

Method

This table shows methods for the SQL class:

Method Returns

Close() Boolean

Execute(paramlist) Boolean

Fetch(paramlist) Boolean

Open(sql [, paramlist])

Properties

This table shows properties for the SQL class:

Property Returns

BulkMode Boolean

IsOpen Boolean, RO

LTrim Boolean

ReuseCursor Boolean

RowsAffected Number, RO

Status Number, RO

TraceName String

Value String, RO

543
Appendix D

Alternate Solutions and Additional


Activities

Below are the alternate solutions for various activities:

Activity 17 Alternate Solution

[PSU_CRS_SESSN.GBL.PSU_CRS_SESSN - SaveEdit]
Local Record &Rec = GetRecord();
If All(&Rec.START_DATE.Value, &Rec.END_DATE.Value) And
&Rec.START_DATE.Value > &Rec.END_DATE.Value Then
&Rec.START_DATE.SetCursorPos(%Page);
Error MsgGet(30420, 3, "Message Not Found: Course Start Date must not
be later than End Date.",
&Rec.START_DATE.Value, &Rec.END_DATE.Value);
End-If;
[PSU_TASK_RESOURCES.GBL.PSU_TASK_RSRC.INSTRUCTOR - FieldChange]
Local Record &Rec = GetRecord();
&Rec.RESOURCE_NAME.SetDefault();
If All(&Rec.INSTRUCTOR.Value) Then
&Rec.RESOURCE_NAME.Enabled = False;
Else
&Rec.RESOURCE_NAME.Enabled = True;
End-If;
[PSU_TASK_RESOURCES.GBL.PSU_TASK_RSRC - RowInit]
Local Record &Rec = GetRecord();
If All(&Rec.INSTRUCTOR.Value) Then
&Rec.RESOURCE_NAME.Enabled = False;
End-If;

545
Alternate Solutions and Additional Activities Appendix D

Activity 19 Alternate Solution

[PSU_STU_ENROLL.GBL.PSU_STU_ENROLL - SaveEdit]
/* Loop through level 1 scroll and determine if the course being added is
PeopleCode */
If PSU_STU_ENROLL.ENROLL_STATUS.Value = "ENR" And
PSU_STU_ENROLL.COURSE.Value = "1011" Then
/* Declare variables */
Local boolean &PrereqComp = False;
Local date &StartDate;
Local Rowset &RS1;
Local Record &Rec;
/* From the PeopleCode row - determine the start date of the PeopleCode
class */
&StartDate = GetField(PSU_CRS_SESSN.START_DATE).Value;
/* Loop through the level 1 scroll to determine if the student has
PeopleTools II */
&RS1 = GetRowset();
For &i = 1 To &RS1.ActiveRowCount
&Rec = &RS1(&i).PSU_STU_ENROLL;
If &Rec.COURSE.Value = "1002" Then
/* If so, see if student has completed PeopleTools II. If they
have the prerequisite has been met.
*/
If &Rec.ENROLL_STATUS.Value = "CMP" Then
&PrereqComp = True;
Break;
End-If;
/* If Tools not completed, see if student is enrolled prior to Code
class. If so, the prerequisite
has been met. */
If &Rec.ENROLL_STATUS.Value = "ENR" Then
If &StartDate > &RS1(&i).PSU_CRS_SESSN.START_DATE.Value Then
&PrereqComp = True;
Break;
End-If;
End-If;
End-If;
End-For;
/* If the prerequisite has not been met - issue an error so stating */
If Not &PrereqComp Then
Error MsgGet(30420, 7, "MNF: Prereq not met.");
End-If;
End-If

546
Appendix D Alternate Solutions and Additional Activities

Activity 20 Alternate Solution

[PSU_TASK_RESOURCES.GBL.DERIVED_TRAIN.TOTAL_RES_HRS - FieldDefault]
/* If the field is blank - determine the Total Resource Hours */
Local Rowset &RS2 = GetRowset(Scroll.PSU_TASK_EFFORT);
For &i = 1 To &RS2.ActiveRowCount
DERIVED_TRAIN.TOTAL_RES_HRS = DERIVED_TRAIN.TOTAL_RES_HRS +
&RS2(&i).PSU_TASK_EFFORT.EFFORT_AMT.Value;
End-For;
[PSU_TASK_RESOURCES.GBL.PSU_TASK_EFFORT.EFFORT_AMT -FieldChange] and
[PSU_TASK_RESOURCES.GBL.PSU_TASK_EFFORT - RowDelete]
Local Field &FoTtlResHrs = GetField(DERIVED_TRAIN.TOTAL_RES_HRS);
&FoTtlResHrs.SetDefault();
[PSU_TASK_RESOURCES.GBL.PSU_TASK_EFFORT - RowInit]
If PSU_TASK_RSRC.COMPLETED_FLAG = "Y" Then
Local Record &Rec_TaskEffort = GetRecord();
For &i = 1 to &Rec_TaskEffort.FieldCount
&Rec_TaskEffort.GetField(&i).Enabled = False;
End-For;
End-If;
[PSU_TASK_RESOURCES.GBL.PSU_TASK_RSRC.COMPLETED_FLAG - FieldChange]
If PSU_TASK_RSRC.COMPLETED_FLAG = "N" Then
Local Boolean &bComp = False
Else
Local Boolean &bComp = True
End-If
Local Rowset &RS2 = GetRowset(Scroll.PSU_TASK_EFFORT);
For &i = 1 to &RS2.ActiveRowCount
Local Record &RecTaskEffort = &RS2(&i).PSU_TASK_EFFORT;
For &j = 1 To &RecTaskEffort.FieldCount
&RecTaskEffort.GetField(&j).Enabled = &bComp;
End-For;
End-For;

Activity 21 Alternate Write an Application Class

[EO:ApplicationClass:Subpackage]

547
Alternate Solutions and Additional Activities Appendix D

class Example
property string Name get set;
method Example();
method Communicate() returns string;
private
Instance string &m_Name;
Constant &myName = "Steve";
method helper() returns string;
end-class;
/* Property Definitions */
get Name /* read property value */
return &m_Name;
end-get;
set Name /* write property value */
&m_Name = &NewValue;
end-set;
/* private methods */
method helper
Return "Hello there " | %This.Name | "!";
end-method;
/* public methods */
method Example /* Constructor */
&m_Name = &myName;
end-method;
method Communicate
return %this.helper();
end-method;

Activity 22 Alternate - Implement the Application Class

[PSU_GET_ENROLL.GBL.DERIVED_ED_SVCS.REFRESH_BTN.FieldEdit]
Import EO:ApplicationClass:Subpackage:Example;
Local Example &ex = Create Example();
/* Show the Name property get */
WinMessage("Your name is: " | &ex.Name, 0);
/* Show the Name property set */
&ex.Name = "Mareesa";
WinMessage("The new name is:" | &ex.Name, 0);
/* Call the Communicate method */
WinMessage(&ex.Communicate(),0);
To Test: Set Up Training > Training Tasks > Get Enrollments

548
Appendix D Alternate Solutions and Additional Activities

Activity 23 Alternate Solution

class Order_Number
method Assign_Order_Number(&ORDER_NBR As Field);
private
constant &LENGTH = 8;
instance string &Check, &Pad;
instance number &Nbr;
end-class;
method Assign_Order_Number
/+ &ORDER_NBR as Field out +/
Local string &Last_Order;
&Check = Rept("9", &LENGTH);
SQLExec("Select order_last From PS_INSTALLATION_TR", &Last_Order);
If Value(&Last_Order) + 1 > Value(&Check) Then
Error MsgGet(10001, 4, "MESSAGE NOT FOUND.", &Check);
Else
&Nbr = Value(&Last_Order) + 1;
&Pad = Rept("0", &LENGTH - Len(String(&Nbr)));
&ORDER_NBR.Value = String(&Pad | &Nbr);
SQLExec("Update PS_INSTALLATION_TR Set order_last = :1",
&ORDER_NBR.Value);
End-If;
end-method;
[PSU_PO_HDR.ORDER_NBR - SavePreChange]
Import PSU:Order_Number;
Local Order_Number &NewOrder;
If PSU_PO_HDR.ORDER_NBR = "NEW" And %Mode = "A" Then
&NewOrder = Create Order_Number();
Local Field &Fo = GetField(PSU_PO_HDR.ORDER_NBR);
&NewOrder.Assign_Order_Number(&Fo);
End-If;

549

Vous aimerez peut-être aussi