# OOP Approach
Content Server uses a procedural programming approach in the majority of its implementation. This means most operations have two parts: data and operations on that data. Data represents some type of information (e.g., an Assoc
, Integer
, RecArray
, Record
, etc.) and these are passed into functions to operate on it.
The difficulty with procedural programming is that a developer must know what a piece of data represents (e.g., a node, user, workflow, permission, category, etc.), and what functions are available to operate on that data. Furthermore, it's often required a developer must call a long sequence of functions to convert data from one form to another to finally get to the desired result.
RHCore simplifies this by adopting an object-oriented programming approach. It should be noted that OScript does not natively support objects in the traditional OOP sense. However, with some coercion the Frame
data type can be used like an object.
RHCore wraps many concepts in Content Server such that they can be used like an object. For example, consider the RHNode class for wrapping a node:
Frame node = $RHCore.RHNode.New(prgCtx, 12345)
This returns a Frame
representation of the node with DataID 12345
. From here we can call methods to operate on it:
node.name() // returns the name of the node
node.rename('My Document') // rename the node
node.children() // get the child nodes (if a container)
node.url() // get the "open" link
node.addVersion('C:/upload_folder/document.doc') // add a version (if a document)
TIP
RHObject instances use the Frame
data type. A Frame
in the context of RHCore usually means an RHCore object instance.
# Base class
The base class is RHObject and is akin to java.lang.object (opens new window) in Java. All RHCore objects are derived from RHObject.
# Constructors
An object can be instantiated by calling the class New()
function. For example, the RHWorkStatus class can be instantiated to wrap a workflow instance by calling it's New
function:
Frame wf = $RHCore.RHWorkStatus.New(prgCtx, WorkID, SubWorkID)
# Subclassing
An RHCore class is based on an OScript object. This permits subclassing (via the "New Orphan" and "New Child" operations in Builder) where new classes can inherit, add, or override features from the parent class. Any RHCore class an be "subclassed" into another module and be extended.
# Calling Super
Methods can make a super call with the callSuper
method. The method takes the method name as its first parameter, and the parameters as a list as the second parameter. For example, say we want to override the doSomething
method in our subclass and wish to call the super method:
function Assoc doSomething(Object prgCtx, Integer userid)
Assoc results = .callSuper('doSomething', {prgCtx, userid})
// ...
return results
end
# Testing Inheritance
The isInstanceOf method can be used to test if an RHObject instance is of a particular class. For example:
myObject.isInstanceOf('RHObject') // always returns true
# Conventions
A few conventions have been adopted since public, private, protected, static, and class methods are not natively supported in OScript:
- methods beginning with an uppercase character are class methods;
- methods beginning with a lowercase character are instance methods;
- methods beginning with an underscore are protected; and
- features beginning with a lowercase "f" are private, but can be made accessible with setter and getter methods.
# Property Methods
Methods that accept no parameters and have a return value are considered, by default, to be a "property" method. Property methods can be accessed with the valueForKey method. For example, RHNode has an isFolder method, which returns true if the node represents a folder:
function Boolean isFolder()
return .subtype() == $TypeFolder
end
This is a property method since it has a return value and accepts no parameters. This permits the following:
Boolean isFolder = node.valueForKey('isFolder')
Or, in an RHTemplate:
{% if node.isfolder %}
...
{% endif %}
With few exceptions, property methods should not mutate the state of the system.
A @notproperty
directive can be added to the comments to prevent it from being interpretted as a property method. For example:
// @notproperty
function Assoc delete()
return .llnode().NodeDelete(.dapiNode())
end
Similarily, a @property
directive can be used to explicitly indicate a property method (only necessary if the method has optional parameters):
// @property
function String name(String langCode=Undefined)