# 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 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)
Last Updated: 5/20/2019, 11:42:35 AM