2.0 OpenBiz Manual

This document is OpenBiz 2.0 manual. You can access OpenBiz 1.x manual at manual11.html

Other links: Openbiz Eclipse plug-in designer manual, Openbiz best practice

Overview of Openbiz 2.0

Openbiz Installation

Build Applications with Openbiz

Openbiz Configuration Guide

  • Organize metadata by package
  • Use object metadata inheritance
  • Simple Expression Language
    • Using Expressions
    • Literals
    • Operators
    • Variables
    • Functions
    • Examples
  • Configuration of BizDataObj
    • Map BizDataObj to Tables
    • Query lanaguage in BizDataObj
    • Data type and format of BizFields
    • Data validation
  • Object Relational (O/R) Mapping
    • Map a table to a BizDataObj
    • Primary key (Id) generation
    • Composite primary key support
    • Map multiple tables to a BizdataObj
    • Many to one relationship between BizDataObjs
    • One to many relationship between BizDataObjs
    • Many to many relationship between BizDataObjs
  • BizView and BizForm Configuration
    • BizView - the HTML page container
    • Basic BizForm layout: Data, Toolbar and Navigation bar
    • Map BizDataObj to BizForm
    • Present data with various HTML elements
    • Event handling in BizForm
    • Keyboard navigation on BizForm
    • Form controls dependency
    • Configure drilldown link to another view
    • Select field data from comboBox or ListBox
    • Controlling page navigation
    • Import and export data from BizForm
    • Upload file in BizForm

Openbiz Development Guide

Appendix A - third party libraries

Appendix B - metadata DTD files


Overview of Openbiz 2.0

Openbiz 2.0 is a metadata-driven framework. All openbiz objects are declared in their own metadata files. Openbiz 2.0 architecture follows Model-View-Controller (MVC) design pattern, it also implements Object/Relational Mapping.

Openbiz 2.0 architecture

Metadata-driver framework

The goal of Openbiz framework is to make design, development and maintenance of software applications easy. Openbiz is XML metadata-driven framework, which means openbiz objects are constructed based on description in their metadata files. Building an application means design and development of metadata files. Due to the self-explanation nature of XML language, the application is easy to maintain. Meanwhile Openbiz is an extensible framework due to the extensible nature of XML.

The diagram below shows metadata based objects in Openbiz framework. These objects cover most functional needs of web application development.

Openbiz's implementation of MVC

One of the key advantages of Openbiz is that it is a framework that follows the Model-View-Controller (MVC) design pattern. This makes Openbiz applications much more manageable because the presentation code (View) is cleanly separated from the application data and logic (Model). All user interactions with the application are handled by a front-end controller.

Comparing Openbiz MVC with existing MVC frameworks in market such as JSF and Struts, Openbiz is more close to JSF because both are component based architecture. Openbiz's View layer comprises components of BizView, BizForm and ojects within BizForm. These components are accessible during request processing. The following table lists the openbiz implementation of top 6 advantages of Top Ten Reasons to Prefer JSF over Struts

JSF's advantages 
over Struts
Openbiz implementation
Components BizView and BizForm as persistent UI objects 
Render Kits Associate different templates to UI objects
Renderers Customer class to implement Render() method
Value Binding Support static and dynamic value bindings
Event Model Associate client event to server function
Extensibility Developers can link their own class to openbiz object
other four .... Not applicable

Openbiz's implementation of persistent object and ORM

Similar with popular Hibernate approach, Openbiz uses session to maintain the persistency of objects. Unlike J2EE web container who has objects pool in memory, PHP objects are be constructed and released for each request (this is called shared-nothing architecture). To keep the persistency of objects, openbiz persistent objects (BizDataObj, BizForm ...) save a set of states in session, then reconstruct the object with these states. Also to avoid multiple object instances of same class in the same session, openbiz use ObjectFactory to ensure object singleton.

Openbiz implements necessary object/relational mapping (ORM) features to allow BizDataObj represents the data and relationships of database tables. The following table list the features of Openbiz ORM.

Flexible mapping table-per-class, N table to 1 class
Many to one, one to many, many to many, one to one
Query facilities SQL like query language - support SQL functions and operators, support SQL aggregate functions, support group by, having and order by
Metadata facilities XML metadata describe the mapping

Openbiz security model

Openbiz supports web security in three ways - user authentication, view access control and data access control. Openbiz mainly uses plugin services to control security. This implementation allows customers to plugin their own logic to the services. The details will discussed in the developer guide - Implement authentication, view and data access control.

User authentication flow:

View access control flow:

Security concept Openbiz implementation with plugin services
User authentication Openbiz uses authentication service (bin/service/authService.php) to authenticate username and password
Role-based view access control  Openbiz uses profile service (bin/service/profileService.php) to get user profile that includes "role". 
Then match this role to access service (bin/service/accessService.php) to determine the users' accessibility to the view
Attribute-based data access control Openbiz uses profile service (bin/service/profileService.php) to get user profile that includes attributes. 
Then based on these attributes to determine browser/update/delete permission of data record. The data access permissions are controlled in BizDataObj.

Openbiz 2.0 package organization

OpenBiz provides a PHP framework that assists you to build complicated web application in an easy way. 

OpenBiz is designed as a multi-layer architecture as the figure below.

Usually a business application can be modulated to 3 layers - Data layer, Business Logic layer and Presentation layer. In OpenBiz architecture, these 3 layers map to 3 packages, Presentation layer is refined to logic which is implemented by BizView package and GUI layers which is implemented by jbForm javascript package. Business Logic layer is implemented by BizDataObj package. 3rd party package ADODB handles Database layer. Plugin services provide functional service components that can be invoked by both presentation and data layer objects.

Package Class
BizSystem BizSystem
- Provide a global variable accessed anywhere in openbiz application
- Provide the Get method for ObjectFactory, SessionContext, TypeManager, ClientProxy and Configuration
- Provide static methods for accessing XML metadata, logging and error reporting.
ObjectFactory 
- It's a factory class to get metadata-driven objects (BizView, BizForm, BizdataObj and their extended classes) 
SessionContext
- Session management class that has additional methods to save/get session variables of metadata-driven stateful objects through their GetSessionVars|SetSessionVars interfaces
TypeManager
- Type management class that has help methods to format data to UI and unformat UI input to data
ClientProxy
- It's a class that is treated as the bi-direction proxy of client. Through this class, others can get client form inputs, redraw client form or call client javascript functions.
Configuration
- A class that has help methods to get data from config.xml
BizDataObj BizDataObj
- It's the base class of all data object classes. Before Openbiz 1.2, BizDataObj was called BizObj. Since BizObj means Business Object, but it acts as business data unit, in 1.2 it is changed as BizDataObj.
BizRecord
- BizRecord class implements basic function of handling record
BizField
- BizField is the class of a logic field which mapps to a table column
BizDataSql
- BizObjSql is the class to construct SQL statement for BizDataObj
CacheRecordList
- CacheRecordList implements the cache for BizDataObj
ObjRefernces
- ObjReferences contains a list of BizDataObj whose relationship to this object is defined in the ObjReference
TableJoins
- Table Joins contains a list of table joins to the main table of this object
BizView BizView
- BizView is the class that contains list of forms. View is same as html page.
BizForm
- BizForm is the base class that contains UI controls. BizForm is a html form that is included in a BizView which is a html page.
RecordRow
- RecordRow is the class that contains FieldControls
ToolBar
- ToolBar is the class that contains HTMLControls
NavBar
- NavBar is the class that contains navigation buttons
HTMLControl
- HTMLControl is the base class of HTML controls
FieldControl
- FieldControl is the base class of field control who binds with a bizfield
DisplayMode
- contains the BizForm display mode information
jbForm  jbForm (javascript bizForm) 
- the base class that handles RPC function call and callback
ADODB This is an abstract database connection package which can connects to all major databases from different vendors. It can be downloaded from http://php.weblogs.com/ADODB

Class diagram of multi-layer architecture

Sequence diagram of a typical RPC call

Openbiz client browser communicates with server through AJAX JS-based RPC invocation.


Openbiz Installation

Running environment

OpenBiz (2.0 or later) is written by PHP5 scripts, it won't work in PHP4.x web server. We recommend platforms as

  • Apache HTTP Server 1.3.x or 2.x + PHP 5.x
  • Internet Information Server (IIS) 5.x + PHP 5.x

Installation directory is openbiz, or you can configure apache using Alias.

Windows installer is not in Openbiz 2.0 so far.

Support web browsers - IE5.x, Netscape 7.x and Mozillar/FireFox 1.x

Install OpenBiz

Download the zip file and unzip it to a directory under your web access root.

Please read through the sysheader.inc under openbiz/bin directory and app.inc under demoapp/bin.

  • Openbiz core path "OPENBIZ_HOME" can be specified in both syshearder.inc and app.inc. The value in app.inc will override the value in sysheader.inc.
  • sysheader.inc defines the paths of 3rd party php packages including Smarty "SMARTY_DIR", Adodb "ADODB_DIR" and so on. If you have same packages installed in other directories and you don't want to use the packages installed with openbiz, please modify them to appropriate paths. 
  • Application home "APP_HOME", metadata file path "META_PATH", log file path "LOG_PATH" and session file path "SESSION_PATH" and smarty template files path "SMARTY_TPL_PATH" are specified in app.inc
  • "DEBUG" flag indicates whether print debug infomation or not
  • "CHECKUSER" flag checks whether user logged in
  • "TIMEOUT" is the session timeout seconds

Source tree structure:

From Openbiz 2.0 RC2, two main directories are included in the package. They are Openbiz core library and demo application. 

The demo application is an openbiz-based web application. Because openbiz provides metadata-driven framework, bin and metadata directories are required. The rest of the directories are suggested structure, not required. Users may have their own way to arrange the web application structure. Please modify demoapp/bin/app.inc to change constant definition.

As you observe from the bin and metadata structures, each subdirectory under bin has a matching subdirectory under metadata. This is code/metadata match-up rule, say if you have an object's metadata under /metadata/aaa/ directory, if the object implementing code is a user-defined class (not openbiz core class), the class code file must be under /bin/aaa/ directory.

Openbiz core library
openbiz_root/ 
---bin/        
(openbiz core php source - required)
------service/     
(openbiz core service library directory)
---document/    (openbiz documents - optional)
------apidoc/     
(openbiz core API)
---medata/     
(openbiz metadata files - required)
------service/     
(service package)
---others/      (third party libraries - optional)
------adodb/      
(adodb package)
------Smarty/     
(smarty package)

 

demo application
demoapp/     (demoapp web pages)
---bin/         (demoapp php source)
------demo/        
(demapp demo library)
------shared/      
(demoapp shared library)
------service/     
(demoapp service library)
---js/
          (demoapp javascript files)
---pages/       (demoapp HTML files)
---css/        
(demoapp style sheets)
---images/     
(demoapp images)
---log/        
(demoapp logs)
---medata/     
(demoapp metadata files)
------demo/       
(demoapp demo package)
------shared/      
(demoapp shared package)
------service/     
(demoapp service package)
---session     
(demoapp session files)
---templates    (demoapp smarty templates files)
------cpl          (demoapp smarty compiled templates)
------cfg          (demoapp smarty configuration files)
---tmpfiles     (temporary files)

In Unix or Linux box, you need to give write permission to web users on log, metadata, session, tmpfiles and templates directories.

Install necessary third party packages

The following package are necessary - they are included in openbiz package.

We recommend you install PHP optimization packages.

Start demo application

Populate the demo database. Find gendb.sql under openbiz root directory, apply it against your database. Notes this gendb.sql is for mysql database, please adjust the syntax according to different database type.

Open demoapp/clientUtil.js. Change the var binPath = "/demoapp/bin/"; to the appropriate bin directory under demoapp installation root. Remember the should be absolute path which begins with "/".

Open demoapp/metadata/config.xml, verify the default database entry has the correct attributes (such as username and password).

Then start a browser, open url http://localhost/demoapp/demo.html

Upgrade guide

Metadata-driven framework gives customers full flexibility to configure application as the way they like. From a version to higher version, metadata schema may be changed to fit the new features. Move from one version to a higher version usually include code and metadata upgrade. We here discuss metadata upgrade.

Upgrade from 2.0 to 2.1

- Application tree structure. In 2.1, javascript files are under app_root/js. Therefore all view templates must be changed to have correct path of javascript files. 
<script language="javascript" src="../js/clientUtil.js"></script>

- In clientUtil.js, developers must change the bin path to point to the application root directory. 
var binPath = "/application_root/bin/";

- Metadata file change

Metadata change 2.0 2.1
Control event handlers Function, FunctionType, PostAction are attributes of Control element Function, FunctionType, PostAction are attibutes of EventHandler element who is child of Control element
Id generation option BizDataObj Id field value is implicitly generated. Support generating ID with openbiz id table or auto-increment column (MySQL)  User controls BizDataObj Id field value generation with IdGeneration attribute in BizDataObj element. Support native database Id generation.

If your original Id maps on auto-increment column, you need to specify IdGeneration="Identiry"

BizField on audit NA New OnAudit attribute in BizField element to enable audit trail

Control element syntax in 2.0

<Control Name="ControlName" Type="ControlType" Function="..." FunctionType="..." PostAction=""/>

Control element syntax in 2.1

<Control Name="ControlName" Type="ControlType">
   <EventHandler Name="ehName" Event="eventName" Function="..." FunctionType="..." PostAction=""/> +
</Control>

More than one event handlers can be associated to a control. In Openbiz 2.0, one control can have only one event handling function. In 2.1, Function and FunctionType attributes are moved from Control Element (2.0 way) to EventHandler element under Control element (2.1 way). Even though the 2.1 code still work with 2.0 metadata file, such conversion is recommended when upgrading to 2.1. 

Access latest source code with SVN

Developers can access and contribute to openbiz source code with SVN client. The SVN url is at https://svn.sourceforge.net/svnroot/bigchef/trunk/, 2 modules openbiz and demoapp are in the repository. 

You can do anonymous checkouts from the svn repository. The anonymous user has only read-access to the repository. If you don't have SVN client installed on your machine, these 2 links can help you. http://sourceforge.net/docman/display_doc.php?docid=31178&group_id=1 and http://sourceforge.net/docman/display_doc.php?docid=31165&group_id=1.

If you want to contribute (add features or fix bugs) to SVN repository, you need to have a sourceforge account. To apply for sourceforge account, go to http://sourceforge.net/account/newuser_emailverify.php . Email your account to rockyswen@phpopenbiz.org, your account will be added to openbiz project. Then you should be able to check in/out openbiz SVN repository.  


Build Applications with Openbiz

Specify requirement of your application

OpenBiz is a perfect tool that help you develop your complicated web application easily and comprehensively. Based on its 3-layer architecture, your application will be on a clear logic model. It takes care the basic and advanced features of the data-oriented application. In order to tell whether OpenBiz can help building your application, you need ask these questions:

  • Is your application web-based application or can be converted to web-based application?
  • Is your application need manipulate different types of data using database?

If the answers are YES, OpenBiz is the right framework for developing your application!

Plan your web applications

When you install the Openbiz package, you would notice there are two main directories "openbiz" and "demoapp" in the zip file. "openbiz" directory contains the openbiz core library and metadata. "demo" directory contains the source for a demo application (event management  and calendar demo). 

The above structure is different with that of Openbiz 2.0 RC1 and prior version where you can see demo application was in the openbiz directory. Why does Openbiz has this change? 

  • It brings developers a clear logic picture - openbiz core library and application code are under different locations.
  • Openbiz core library is more portable than the openbiz application, it can be shared by multiple applications.
  • If openbiz core has new release, it's easy to upgrade.

Develop web application with your own directory

Your own development Where to put
Your source code your_app_root/bin/
Your metadata files your_app_root/metadata/your_package/
Your web templates your_app_root/templates/
Your web pages your_app_root/
Your style sheet files your_app_root/css/
You image files your_app_root/images/
Your log files your_app_root/log/
Your session files your_app_root/session/
Your temporary files your_app_root/tmpfiles/

This is a more organized way to develop an openbiz-based web application. Your application specific files are in a separate directory, not mixed with openbiz core files. You can build multiple web applications based on single openbiz core. You need to do some extra steps to set up your own application directory. The following steps are suggested.

  1. Copy demoapp directory and rename it to your application name, say "testapp"
  2. Open testapp/bin/app.inc, change the constants appropriately. If the default values may work for you, no change is needed.
  3. Open testapp/bin/login.php, change the $application_homepage to the first web page shown to users after they login.

In the app.inc file, OPENBIZ_HOME has to be define to point to the installed path of openbiz core library. Your applications will use the openbiz core library as well as core objects defined in metadata directory.

Another important change from RC2 is that metadata and code have to match up under /metadata and /bin directories. If you have an object's metadata under /metadata/aaa/ directory, if the object implementing code is a user-defined class (not openbiz core class), the class code file must be under /bin/aaa/ directory. For example, /metadata/shared/FMCalendar.xml has a special implementing class "FMCalendar", this FMCalendar class must be located in /bin/shared/FMCalendar.php. If the object's implementing class is openbiz core class, no special code is needed, thus there's no matching code under /bin. This match-up rule is to give a clear view of the metadata and code.  

How to upgrade to the new structure if you are using the structure in RC1 or prior version? In Openbiz RC1 and prior version, application code is under bin/usrlib/ directory. Based on the metadata/code match-up rule, you need to create subdirectories with the same names of the metadata packages under /bin directory and move the code under /bin/usrlib to those subdirectories.

Create your database model

Modeling your business data with Relational database tables is the necessary base for building your whole application.

Create a new database

  • Assign the new database to be Default database in config.xml
  • Create "ob_users" table which stores user id and password. Since 2.0, openbiz counts on authentication service to authentiate user and password, so the user id and password can be stored in the storage that is queried by the authentication service.
  • Create "ob_sysids" table which stores SYSID information for all tables who have SYSID column
  • Create customer tables. Each table must have a SYSID column and add a record in ob_sysids table (TABLE=your table name, PREFIX=prefix of sysid, IDBODY=starting integer)

Use existing database

  • Assign the new database to be Default database in config.xml
  • Create "ob_users" table or reuse an existing table which contains userid and password columns. Ensure that authentication service queries the user id and password on the right table (or source).
  • Set IdGeneration attribute to the existing id generation algorithm. For example, if your oracle database uses sequence to generate value for PK column, the IdGeneration should be "Sequence:seqname". Please refer the chapter of Primary Key (Id) Generation for details.

Fit your system design in Openbiz

Fit your design in Openbiz framework, you leverage the power of the framework. Your design will have

  • Clear three-layer architecture stack
  • XML metadata driven application
  • MVC (Model-View-Controller) design pattern
  • Rich set libraries and valuable crafts
  • Common application features

Build new application

Business requirement -> UI design + data modeling + objects design

User Interface: Pages, forms, interactivities

Data Modeling: Database table schema

Objects Design:

  • UI objects - BizView, BizForm
  • Data objects - BizDataObj with object/relational mapping
  • Functional objects - Plugin services

Convert existing application

Convert existing UI to BizViews, BizForms

Map existing database tables to BizDataObjs

Port existing business functionalities to plugin services

Sample implementation - Calendar

Requirement:

  • users can see their calendar in day, week, month formats
  • users can create/delete/edit an event on calendar
  • users can invite attendees to an event and see the schedule of attendees

Step 1. Data Modeling with table schemas

Step 2. Map tables to BizDataObjs

  • Map driving table columns to BizFields
  • Join other table columns to BizFields
  • Map table relationship using ObjReference

Step 3. Bind UI controls with data

  • Associate a BizDataObj to a BizForm
  • Map FieldControl of BizForm to BizField of BizDataObj
  • Configure drilldown link on FieldControl
  • Configure value picker form on FieldControl

Step 4. User Interactions

  • Map action to UI control (usually a button)
  • Associate UI control to a function
  • Implement the function as a BizForm method

Step 5. Implement special logic by extending openbiz

  • Write special data logic by extending BizDataObj
  • Write special presentation logic by extending BizForm

Calendar view: event navigation

User Interface Objects Calendar form
  - day, week, month and all events display modes
  - FieldControls: Id, Subject, Location, Type, Notes, Start, End, RepeatCycle, RepeatEnd
Data Objects Calendar data object
  - Fields: Id, Subject, Location, Type, Notes, Start, End, RepeatCycle, RepeatEnd
Tables calevts table
  - Columns: SYSID, SUBJECT, LOCATION, TYPE, NOTES, STARTTIME. ENDTIME, REPEATCYCLE, REPEATEND

Calendar Detail view: event editing and invite attendees

User Interface Objects Calendar Detail form
  - SubForm is Event Attendee form
  - New, Edit modes
  - FieldControls: Id, Subject, Location, Type, Notes, Start, End, RepeatCycle, RepeatEnd, AttendeeId, AttendeeName
Event Attendee form
  - Parent form is "Calendar Detail form"
  - List and Schedule modes
  - FieldControls: Id, LastName, FirstName, ...
Data Objects Calendar detail data object
  - Fields: Id, Subject, Location, Type, Notes, Start, End, RepeatCycle, RepeatEnd
  - ObjReference: Calendar Attendee data object
  - Joined Fields: Attendee Id, AttendeeName (from calattds table)
Calendar Attendee data object
  Fields: Id, LName, FName, ...
Table calevts table
  - Columns: SYSID, SUBJECT, LOCATION, TYPE, NOTES, STARTTIME. ENDTIME, REPEATCYCLE, REPEATEND

calevts_attds table (intersection table of calevts and calattds)

calattds table
  Columns: SYSID, LASTNAME, FIRSTNAME, ...

Class Diagram:

Note: Calendar Form and Calendar Detail Form have special rendering logic, they are based on FMCalendar and FMCalAttendee classes which are extended from BizForm base class.

User interaction - UI controls maps to server functions

User action UI Control Function Method implementation
Show Day calendar: switch to day mode, draw the day calendar Day button ShowDay() class FMCalendar
public function ShowDay()
Show Week calendar: switch to week mode, draw the week calendar Week button ShowWeek() class FMCalendar
public function ShowWeek()
Show Month calendar: switch to month mode, draw the month calendar Month button ShowMonth() class FMCalendar
public function ShowMonth()
Show all calendar events: switch to list mode, list all events page by page All Events button ShowList() class FMCalendar
public function ShowList()
New a calendar event: Click New button on Calendar View, jump to Calendar Detail View with new mode New Event button NewEvent() class FMCalendar
public function NewEvent()
Delete a calendar event: In Calendar Detail View, click Delete button to delete an event Delete button DeleteRecord() class BizForm
public function DeleteRecord()
Edit a calendar event: Click an event link on the Calendar view, jump to Calendar Detail with edit mode Drill down link URL = "bizController.php? view=shared.CalDetailView &amp;form=shared.FMCalDetail &amp;mode=NEW"  
Add event attendees: In Calendar Detail View, click Add button on the Calendar Attendee form to pick an attendee Add button ShowPopup (shared.FMAttendeePopup) class BizForm
public function ShowPopup()
Remove event attendees: In Calendar Detail View, click Remove button on the Calendar Attendee form to remove an attendee Delete button RemoveRecord() class BizForm
public function RemoveRecord()
Show attendees' schedule: In Calendar Detail View, click Show Schedule button to switch to schedule mode Schedule button ShowSchedule() class FMCalAttendee
public function ShowSchedule()

To see the sample calendar, open http://localhost/openbiz/bin/BizController.php?view=shared.CalendarView in your browser.


Openbiz Configuration Guide

Developers can choose use XML editor to edit metadata files. Openbiz Eclipse Plug-in is recommended to be used as a design and configuration tool. Please refer to Openbiz Eclipse plug-in designer manual.

Organize metadata by package

In a big application, user may need to build lots of objects, therefore they have big metadata file list. If they put these files under a single metadata directory, managing the metadata files is a painful thing. From openbiz 1.1, metadata files can be organized by package name. Bear in mind, metadata package is different with the (BizObj, BizView ...) packages which are the code units. Metadata package is a naming system, different package maps to different directory. It is like the package concept used in Java. 

PackageX.PackageY.metaA.xml refers to the metaA.xml under META_PATH/PackageA/PackageB directory. Where META_PATH is the root metadata directory. This macro is defined in sysheader.inc and app.inc. 

How to configure  package in metadata files?

Let's explain it with the demo example. After you unzip the source, find the demo directory under metadata directory. Open FMRegist.xml file with a text editor. You'll see a Package="demo" attribute in the BizForm element. This attribute is to say the default package of any type of openbiz object is under "demo" package. Here the openbiz objects refer to the following object types.

Object Type Referred as attributes in metadata files
BizObj BizForm[BizObj]
BizObj->BizFieldList->BizField[SelectBizObj]
BizForm BizView->ControlList->Control[Form]
BizView->ControlList->Control[SubCtrl]
BizForm->BizCtrlList->BizCtrl[SelectFrom]
BizView  
BizPopup BizForm->BizCtrlList->BizCtrl[SelectBizForm]
BizFormTree Same as BizForm

If an object name doesn't contain dot symbol ("."), the system uses the package attribute defined in the object root element as its package. Otherwise, if an object name has format as aaa.objectname, the system thinks such object under package "aaa" and will locate such object under aaa directory.

Go back to the example, you can find <BizForm Name="FMRegist" Package="demo" ... BizObj="BORegist"...>, <BizCtrl Name="reg_attdln" ...  SelectBizForm="AttendeePopup"...> and <BizCtrl Name="reg_fee" ... SelectFrom="Selection(Fee)"...>. They all use default package, so the system will try to locate the metadata files as demo/BORegist.xml, demo/AttendeePopup.xml and demo/Selection.xml.

If you want to refer to an object under other package, just add the package name as the prefix of the object name. Notice, there're a Selection.xml under /demo directory and another Selection.xml under /design directory, they belong to different packages. In FMRegist, whose package is "demo", you can use <BizCtrl ...  SelectFrom="design.Selection(Mode)" ...> to configure a comboBox whose values are from the "Mode" element of "design/Selection.xml".

You cannot refer to an object in different application. But you can refer to any object in openbiz core application. For example, the core application has refer to objects under metadata/shared/ directory. Openbiz tries to locate objects in same application and then in core application. If no object is found, it reports an error.

Use object metadata inheritance

If you have a complex application, you want to reuse the existing object to different places, but you want the object behave a little differently in different scenarios. Object inheritance will solve the above problem. Since in openbiz framework objects maps to metadata file, object inheritance becomes metadata file inheritance.

How to specify inheritance between metadata files?

Specify an object attribute, InheritFrom = "parent object name". For example, in demo application, BOEventX has <BizObj Name="BOEventX" Description="Event BizObj Extended from BOEvent" Package="demo" Class="BizObj" InheritFrom="demo.BOEvent"...>. This indicates that is BOEventX is inherited from BOEvent. 

Metadata file inheritance is similar with class inheritance in programming languages, child object can inherit (if not defined in child object, but defined in parent object)  or override (if same attribute defined in both child object and parent object) the parent object attributes.

Object Type which can has inheritance What CAN be inherited or overridden What CANNOT be inherited - must be specified in child metadata file
BizObj Object Attributes: Description, DBName, Table, SearchRule, SortRule, OtherSQLRule, CacheMode

Object BizFieldList: BizField

Object Attributes: Name, Package, Class, InheritFrom
BizForm Object Attributes: Description, jsClass, Title, BizObj, PageSize, Width, Height, SearchRule

Object BizCtrlList: BizCtrl
Object DisplayModes: Mode
Object Toolbar: Control
Object Navbar: Control

Object Attributes: Name, Package, Class, InheritFrom

Simple Expression Language

In order to adding flexibility of metadata configuration, Openbiz accepts simple expression language in metadata files. If a statement has {expr} pattern, expr will be evaluated as simple expression. Basically, the simple expression is a single PHP statement which returns a value. If users need more complicated logic which can't be put in a simple expression, they can associate an object with user-defined class where they put special code.

Using Expressions

Simple expression is to support dynamic value binding of metadata attributes. Users can use simple expression in the following place in metadata files.

  • BizDataObj
    SearchRule, SortRule, OtherSQLRule, AccessRule, UpdateCondition, DeleteCondition. These attributes are query related attributes of BizDataObj element, [field_name] is not evaluated to field value. [field_name] is the syntax of query lanaguage, it will be replaced by table column name. Please see Query Language in BizDataObj for details.
  • BizDataObj.BizFied
    Required, Validator, Value, DefaultValue 
  • BizForm
    Link, Style, Hidden, Enabled, SelectFrom
  • BizForm.EventHandler
    Function, PostAction

Literals

The simple expression language defines the following literals:

  • Boolean: true and false
  • Integer: as in PHP
  • Floating point: as in PHP
  • String: with single and double quotes; " is escaped as \", ' is escaped as \', and \ is escaped as \\.
  • Null: null

Operators

The simple expression language provides the following operators:

  • Arithmetic: +, - (binary), *, / and div, % and mod, - (unary)
  • Logical: and, &&, or, ||, not, !
  • Relational: ==, !=, <, >, <=, >=.  Comparisons can be made against other values, or against boolean, string, integer, or floating point literals.
  • Conditional: A ? B : C. Evaluate B or C, depending on the result of the evaluation of A. 

Variables

  • Simple expression allows developers to use variables of openbiz metadata objects:
Syntax to get metadata object variables Meaning Implementation Sample usage
@object_name:property_name get the given property of the given object. Call object->GetProperty ($propname) @BOEvent:Name
@FMEvent:Title
@object_name:*[child_name].property_name get the given property of the given object's child element Call object->GetProperty ($propname), where $propname="*[child_name]", to get the child object. 
Then call child_object->GetProperty($propname)
@BOEvent:Field[Id].Value
@FMEvent:Control[evt_id].Value
@:property_name or 
@this:property_name
get the given property of this object ("this" object is the object defined in the metadata file) Call this->GetProperty ($propname) In BOEvent, @:Name or @this:Name means getting the "Name" property of BOEvent.
@:*[child_name].property_name or
@this:*[child_name].property_name
get the given property of this object's child element Call this->GetProperty ($propname), where $propname="*[child_name]", to get the child object. 
Then call child_object->GetProperty($propname)
In BOEvent, @:Field[Id].Value or @this:Field[Id].Value means getting the "Id" field value of BOEvent.
[field_name] get the value of a given BizField of this BizDataObj. 
It is evaluated to field value only if it is used in BizField element
Call object->GetProperty ($field_name) to get the child BizField object. 
Then call field_object->GetProperty("Value")
In BOEvent, [Id] means getting the "Id" field value of BOEvent.
@object_name:param[param_name] or
@:param[param_name]
get the given parameter's value of this object Call object->GetProperty ($propname), where $propname="param[param_name]" @:param[Evt_Id]
@profile:property_name get the user profile property.  User profile is provided with ProfileService. @profile:ROLEID

As implied from the implementation, developers can add more property support by modifying/overriding GetProperty() method. The input of GetProperty() can be either "property_name" or "*[child_name]" or something new that supported by customer code.

Functions

Developers can invoke any PHP functions in simple expression. A user defined functions can be invoked if the file that contains such function is included. For example, if the metadata object A is based on a customer class, the class file is A.php that includes another A_help.inc. In this case, you can invoke functions defined in A_help.inc in simple expression.

Examples

  • <BizDataObj SearchRule="[Start]>'date(\"Y-m-d\")'">
  • <BizDataObj AccessRule="[OwnerId]='{@profile:USERID}'">
  • <BizDataObj UpdateCondition="[OrgId]=={@profile:ORGID}">
  • <BizDataObj DeleteCondition="'admin'=={@profile:ROLEID}">
  • <BizField Name="NeedApprove" Required="{[Amount]>1500}"/>
  • <BizField Name="Fee" Validator="{[Fee]>=15}"/>
  • <BizField Name="FullName" Value="{[LastName]}, {@:Field[FirstName].Value}"/>

Configuration of BizDataObj

The DTD file of the BizDataObj xml is listed in Appendix A.1

Map BizDataObj to Tables

Openbiz maps database tables to object with BizDataObj. This chapter introduce the concept of mapping tables with BizDataObj, the next chapter "ORM" has full details of the mapping configuration. A BizDataObj must have table name and mapping between table columns to BizDataObj fields.

  • Specify the base table: 

    <BizDataObj Name="BizDataObjName" Table="TableName" ...>

  • Map Column to BizField: 

    <BizField Name="FieldName" Column="ColumnName"....>. One of BizFields must have name as "Id". This is required. This Id field usually map to the primary key column of a table.

  • Map SQL Function to BizField: 

    Users can assign a BizField with SQL functions provided by the database engine. The syntax is <BizField Name="FieldName" Column="" SQLExpr="FUNC([FieldName1]...[FieldName2]...)">. Make sure that the Column attribute is empty. For example: <BizField Name="FullName" Column="" SQLExpr="CONCAT([FirstName],' ',[LastName])"...>. Please note that SQLExpr is a query related attributes, [FieldName] is not evaluated to field value. [FieldName] is the syntax of query lanaguage.

  • Specify default value of BizField: 

    <BizField Name="FieldName" Column="ColumnName" DefaultValue="default_value">. Use DefaultValue attribute to give default value to the BizField when dataobject creates a new record.

Query Language in BizDataObj

Openbiz users won't worry about the composing complicated SQL statements. BizDataObj support more intuitive query language at the object level. The basic syntax is "[FieldName] opr 'Value' AND/OR [fieldName] opr 'Value'..." Here "opr" is SQL operator. At runtime, openbiz convert [FieldName] to column name and generate SQL statement. Openbiz also put table relationship in generated query statements.

  • Specify the default query in SearchRule
    Example: <BizObj Name="BOCalendar" Description="Calendar BizObj" Package="shared" Class="MyClass" Table="calevts" SearchRule="[Start]>'1999-10-20'" ...>

  • Specify the default sort in SortRule
    Example: <BizObj Name="BOCalendar" Description="Calendar BizObj" Package="shared" Class="MyClass" Table="calevts" SortRule="[Start] ASC" ...>

  • Specify additional SQL statement in OtherSQLRule
    Example: <BizObj Name="BOCalendar" Description="Calendar BizObj" Package="shared" Class="MyClass" Table="calevts" OtherSQLRule = "GROUP BY [EvtId] HAVING [Fee]>10" ...>

Data type and format of BizFields

BizField supports following data types and formats in its Type and Format attributes.

Type Format Syntax Format Example
Text none Text is the default type  
Number format supported by printf <BizField ... Type="Number" Format="%..." ...> %5.2f to print a float number
  "Int" - integer format according locale <BizField ... Type="Number" Format="Int" ...> If locale=enu, 12345.678 is displayed as 12,346
  "Float"- float format according locale <BizField ... Type="Number" Format="Float" ...> If locale=enu, 12345.678 is displayed as 12,345.68
Date In default read-only mode, a date can be formatted according to the Date format. <BizField ... Type="Date" Format="date format" ...> 6/21/2003 can be formatted as
%A, %b %d %Y - Saturday, Jun 21 2003 if system locale is enu
Datetime In default read-only mode, a date can be formatted according to the Date format. <BizField ... Type="Datetime" Format="datetime format" ...> 6/22/2003 9:30am can be formatted as
%m/%d/%Y %H:%M:%S - 06/22/2003 09:30:00 if system locale is enu
Currency Formatted according to locale setting <BizField ... Type="Currency" Format="Currency" ...> 1456.89 is formatted as $1,456.89 (enu)
1456.89 is formatted as F1 456,89 (fra)
Phone Formatted according to given mask # <BizField ... Type="Phone" Format="mask string" ...> 1234567890 is formatted as 
mask=(###) ###-####, 
phone=(123) 456-7890
mask=###-###-####, phone=123-456-7890
  If a phone number starting with "*", it represents international phone number, it won't be formatted   *123 4567890 is treated as international number
Blob/Clob none <BizField ... Type="Blob" ...>
<BizField ... Type="Clob" ...>
 

Data validations

Validation Type Example
Required - indicates the field can not be empty <BizField Name="Name" Required="Y" Column="NAME"/>
Validator - simple expression language  <BizField Name="Fee" Type="Currency" Format="Currency" Validator="{[Fee]>=15}" Column="FEE">

Object Relational (O/R) Mapping

To support O/R mapping, TableJoin and ObjectReference are introduced to BizDataObj metadata file.

To understand the O/R mapping, a sample is listed below:

attendee:regist = 1:M (one to many), regist:attendee = M:1 (many to one)

events:regist = 1:M (one to many), regist:events = M:1 (many to one)

attendee:events = M:M (many to many)

Map a table to a BizDataObj

To map a table to a BizDataObj, users only need to configure the BizFieldList part in the metadata. 

<BizDataObj Name="BOEvent" Description="Event BizDataObj" Package="demo" Class="BizDataObj" Table="events" ...>
<BizFieldList>
  <BizField Name="Id" Column="SYSID"/>
  <BizField Name="Name" Column="NAME"/>
</BizFieldList>
</BizDataObj>

Primary key (Id) generation

From Openbiz 2.1RC, BizDataObj supports multiple id generation algorithms. Add a BizDataObj attribute IdGeneration="Openbiz|Identity|Sequence:seqname|GUID|UUID|Other...".

IdGeneration how id (Primary Key column) is generated Supported database types
Openbiz (default) Id is generated using "ob_sysids" table which stores SYSID information for all tables who have SYSID column Apply to all database types
Identity Primary key column is generated by database engine.
Id is called "Identity" column in SQL Server, also called "auto-increment" column in MySQL.
MySQL, SQL Server, Sybase, DB2
Sequence:seqname Primary key column is generated by database sequence. "seqname" is the sequence name used to generate PK. Oracle, PostgreSQL, DB2
GUID Primary key column is database-generated GUID MySQL, SQL Server, Oracle
UUID Primary key column is generated with php uuid function Apply to all database types
Other Developers can write customer specific Id generation algorithm by modifying function GetNewID(...) in genIdService class under openbiz/bin/service/genIdService.php decided by customer 

Composite key support

In Openbiz 2.1, BizDataObj supports composite key. This feature would be useful when working with legacy database tables who does not have single primary key column. The syntax of BizDataObj whose Id field maps >2 primary key columns is:

<BizDataObj Name="" Package="" Class="" ... IdGeneration="None">
<BizField Name="fpk1" Column="PK1"/>
<BizField Name="fpk2" Column="PK2"/>
<BizField Name="Id" Column="PK1,PK2" />
...

Map multiple tables to a BizdataObj

User can map multiple tables to a BizDataObj through Join. Joined table is referred by a foreign key column in the base table of the BizDataObj, that says the base table has a foreign key points to joined table's column.

<BizObj Name="BORegist" Package="demo" Class="BizObj" Table="regist" ...>
<BizFieldList>
  <BizField Name="Id" Column="SYSID"/>
  <BizField Name="EvtId" Column="EVENT_ID"/>
  <BizField Name="AttendeeId" Column="ATTENDEE_ID"/>
  <BizField Name="AttdLName" Join="attendee" Column="LASTNAME"/>
  <BizField Name="AttdFName" Join="attendee" Column="FIRSTNAME"/>
</BizFieldList>
<TableJoins>
  <Join Name="attendee" Table="attendee" Column="SYSID" ColumnRef="ATTENDEE_ID" JoinType="INNER JOIN"/>
</TableJoins>

Join Attribute Description
Name The name of the join. It is referred in the Join attribute of BizField
Table The joined table name
Column The joined column name
JoinRef If JoinRef is empty, the joined table joins to the base table. User can specify the JoinRef in the 2-level join.
ColumnRef ColumnRef refers to the column of the base table (or the JoinRef table). It contains the foreign key of the Join column.
JoinType INNER JOIN, LEFT JOIN, RIGHT JOIN, or FULL OUTER JOIN.

The query SQL is like "SELECT ... FROM BaseTable INNER JOIN JoinedTable ON BaseTable.ColumnRef=JoinedTable.JoinedColumn ...". In the above example, the SQL is 

SELECT T0.SYSID, T0.EVENT_ID, T0.ATTENDEE_ID, T1.LASTNAME, T1.FIRSTNAME 
FROM regist as T0
         INNER JOIN attendee as T1 ON T0.ATTENDEE_ID = T1.SYSID

- More explanation about the JoinRef

JoinRef is to support cascade-join. For example, in a query, table A joins B and table B joins C. Table A and C is joined through table B. User can use the following part to link C and A together.

<TableJoins>
<Join Name="join_b" Table="B" Column="B_PK" ColumnRef="A_FK_B" JoinType="LEFT OUTER JOIN"/>
<Join Name="join_c" Table="C" JoinRef="join_b" Column="C_PK" ColumnRef="B_FK_C" JoinType="LEFT OUTER JOIN"/>
</TableJoins>

Many to one relationship between BizDataObjs

Many to one relationship between two tables means table 1 has a column that contains the foreign key pointing to a key/unique column in table 2. To map such relationship between two BizDataObjs, use an Object in ObjectReference section.

<BizObj Name="BORegist" Package="demo" Class="BizObj" Table="regist" ...>
<BizFieldList>
  <BizField Name="Id" Column="SYSID"/>
  <BizField Name="EvtId" Column="EVENT_ID"/>
  <BizField Name="AttendeeId" Column="ATTENDEE_ID"/>
  <BizField Name="AttdLName" Join="attendee" Column="LASTNAME"/>
  <BizField Name="AttdFName" Join="attendee" Column="FIRSTNAME"/>
</BizFieldList>
<TableJoins>
  <Join Name="attendee" Table="attendee" Column="SYSID" ColumnRef="ATTENDEE_ID" JoinType="INNER JOIN"/>
</TableJoins>
<ObjReferences>
  <Object Name="BOEvent" Description="" Relationship="M-1" Table="events" Column="SYSID" FieldRef="EvtId"/>
</ObjReferences>

</BizObj>

Object Attribute Description
Name The name of the referred BizDataObj
Description  
Relationship Relationship between this dataobj and the referred dataobj
Table The table of the referred dataobj
Column The column of the referred dataobj's table
FieldRef The field mapping to the foreign key column in base table

To get the referred dataobj (child dataobj), call GetRefObject($objame) method from parent dataobj. The referred dataobj instance will have the restriction according to the parent dataobj.

One to many relationship between BizDataObjs

One to many relationship between two tables means table 2 has a column that contains the foreign key pointing to a key/unique column in table 1. To map such relationship between two BizDataObjs, use an Object in ObjectReference section.

<BizDataObj Name="BOEvent" Description="Event BizDataObj" Package="demo" Class="BizDataObj" Table="events" ...>
<BizFieldList>
  <BizField Name="Id" Column="SYSID"/>
  <BizField Name="Name" Column="NAME"/>
</BizFieldList>
<ObjReferences>
  <Object Name="BORegist" Description="" Relationship="1-M" Table="regist" Column="EVENT_ID" FieldRef="Id" CascadeDelete="Y"/>
</ObjReferences>

</BizDataObj>

Object Attribute Description
Name The name of the referred BizDataObj
Description  
Relationship Relationship between this dataobj and the referred dataobj
Table The table of the referred dataobj
Column The column of the referred dataobj's table. This column contains the foreign key to the base table
FieldRef The field mapping to the column in base table
CascadeDelete Indicate whether deleting a record in base table will cause the deletion of all related record in referred table.

To get the referred dataobj (child dataobj), call GetRefObject($objame) method from parent dataobj. The referred dataobj instance will have the restriction according to the parent dataobj.

- One to one relationship between BizDataObjs

One to one relationship is a special case of many to one or one to many relationship.

Many to many relationship between BizDataObjs

Many to many relationship between two tables means an intersection table (also called cross reference table, or correlation table) contains the foreign key columns pointing to a key/unique column in table 1 and table 2. To map such relationship between two BizDataObjs, use an Object in ObjectReference section.

<BizDataObj Name="BOEvent" Description="Event BizDataObj" Package="demo" Class="BizDataObj" Table="events" ...>
<BizFieldList>
  <BizField Name="Id" Column="SYSID"/>
  <BizField Name="Name" Column="NAME"/>
</BizFieldList>
<ObjReferences>
  <Object Name="BOAttendee" Description="" Relationship="M-M" Table="attendee" Column="SYSID" FieldRef="Id" CascadeDelete="Y"
XTable="regist" XColumn1="EVENT_ID" XColumn2="ATTENDEE_ID"/>
</ObjReferences>

</BizDataObj>

Object Attribute Description
Name The name of the referred BizDataObj
Description  
Relationship Relationship between this dataobj and the referred dataobj
Table The table of the referred dataobj
Column The column of the referred dataobj's table. This column contains the foreign key to the base table
FieldRef The field mapping to the column in base table
CascadeDelete Indicate whether deleting a record in base table will cause the deletion of all related record in intersection table.
XTable The intersection table name
XColumn1 The intersection table column that has the foreign key of the base table
XColumn2 The intersection table column that has the foreign key of the referred table
XKeyColumn (No longer valid in 2.1) The primary key column name of the intersection table. 
If this attribute doesn't have value, openbiz won't generate the ID column in the table. In this case, the intersection table should auto-generate the ID column or there's no such ID column in the table.
 
XDataObj (New in 2.1) BizDataObject whose base table is the intersection table that is XTable. When user associates one record from referred DataObject to the base DataObject, a new record is created from the XDataObj and added in the intersection table. 

To get the referred dataobj (child dataobj), call GetRefObject($objame) method from parent dataobj. The referred dataobj instance will have the restriction according to the parent dataobj.

BizView and BizForm Configuration 

BizView metadata DTD file can be found in Appendix A.2.

BizForm metadata DTD file can be found in Appendix A.3.

BizView - the HTML page container

BizView is the physical web page that contains multiple BizForms and other HTML elements. Its layout is based on smarty template enginee. BizView defines the layout of BizForms as well as the relationship between BizForms.

- Map BizDataObj relationship of BizForms

If more than one BizForm is placed in a BizView and they are linked by specifying Parent-Child relationship in BizView, the BizForms will have the relationship of their underline BizDataObj.

<BizView Name="EventView" ...>
<ControlList>
  <Control Name="fm_event" Form="FMEvent" SubCtrls="FMAttendeeChild"/>
  <Control Name="fm_attd" Form="FMAttendeeChild"/>
</ControlList>
</BizView>

SubCtrls attribute has syntax like SubCtrls="childform1_name;childform2_name;...". It tells children forms name of the parent form, which means children form data may change along the change of the parent form.

Because BOEvent and BOAttendee have many to many relationship, the event form and attendee form will take the M-M as their relationship. They present the data relationship on user interface.

- Sample Event View:

EventView (Event-Attendee as M-M)

FMEvent as BizForm
 |-- BOEvent as BizDataObj
FMAttendeeChild as BizForm
 |-- BOAttendee as BizDataObj

Basic BizForm layout: Data, Toolbar and Navigation bar

Openbiz BizForm is composed with three part - data part, toolbar and navigation bar.

  • Data part is the area showing the data. It can be shown as list, table, form, tree and so on.
  • Toolbar is a list of controls where users can invoke command on the BizForm.
  • Navigation bar is a set of controls that controls data navigation such as paging, scrolling.

Here's a sample layout of a BizForm:

Toolbar                                     Navigation bar

Data part

Present BizDataObj by BizForm

BizForm represents data from BizDataObj. BizForm defines the mapping between BizCtrls in the BizForm and the BizFields in BizDataObj. Here's an example.

<BizForm Name="FMRegist" ... BizObj="BORegist" ...>
<BizCtrlList>
  <BizCtrl Name="reg_id" FieldName="Id" DisplayName="Registration Id"/>
  <BizCtrl Name="reg_evtid" FieldName="EvtId" DisplayName="Event Id"/>
  <BizCtrl Name="reg_attdid" FieldName="AttendeeId" DisplayName="Attendee Id"/>
  <BizCtrl Name="reg_attdfn" FieldName="AttdFName" DisplayName="First Name"/>
  <BizCtrl Name="reg_attdln" FieldName="AttdLName" DisplayName="Last Name"/>
</BizCtrlList>
</BizForm>

Present data with various HTML elements

HTMLControl or BizCtrl can present its data with various HTML elements by specifying element type and attributes. HTML elements are displayed in edit/query modes

Attributes of HTMLControl element in BizForm

Type Width Height HTMLAttr* Style** SeclectFrom Caption Image Comments
Text x x x
Limit the input length
x       Single line text input. Default type
Textarea x x x x       Multi-line Text input
RichText x x x x       Rich text editor edit HTML source
ListBox x x x
Show ListBox or ComboBox
x x
Set list of values
    ListBox or ComboBox
CheckBox x x x x x
Set True value
    CheckBox
Radio x
Arrange radio list 
x x x x
Set list of values
    Radio buttons
HTMLButton x x x x   x   Standard HTML Button
SubmitButton x x x x   x   Standard HTML Submit Button
ResetButton x x x x   x   Standard HTML Reset Button
Password x x x x       HTML password
Button x x x x   x x OpenBiz image button
Date x x x x       Textbox with date picker icon
Datetime x x x x       Textbox with datetime picker icon
HTMLBlock x x   x   x
Special Characters
  Caption is treated as HTML block
File x x x x       File control to upload file
FunctionColumn x x x x     x This type doesn't map to a data field

* HTMLAttr field can contain any valid additional HTML attribute applied on the HTML element type

** Style field can contain any valid style properties (css)

Limit the input length: 

HTMLAttr="maxlength=N" to limit the maximum number of characters that the user can enter in a text control. 

Show ListBox or ComboBox: 

By default show comboBox. If HTMLAttr="size=N", show N-row listbox.

Set list of values: 

SelectFrom="XmlFile(Key)" means this field control is a listbox or radio buttons whose data is from the "Key" elements in XmlFile.

Set True value: 

SelectFrom="Value" means this checkbox returns the Value when user check the checkbox.

Arrange radio list: 

By default the radion buttons are arranged horiztionally. If Width="1", you can force them arranged vertically.

Special characters:

"<" and ">" used in HTML block have to be replaced by "&lt;" and "&gt;". Please refer to http://www.w3schools.com/html/html_entities.asp for more details.

Rich text editor

Openbiz rich text editor primarily uses the code (LGPL license) from Kevin Roth http://www.kevinroth.com/rte/demo.htm. Thanks Kevin for his excellent work. It supports IE5.5+ and Firfox 1.x. Below is a screenshot.

Date/Datetime picker

Openbiz 2.1 uses the open source DHTML calendar 1.0 (LGPL license) provided by dynarch.com. The DHTML calendar is well documented at  http://www.dynarch.com/demos/jscalendar/doc/html/reference.html. Many thanks to Nik Chankov for his help on integrating openbiz with DHTML calendar. Openbiz by default uses system style for the calenar.

Additional attributes of BizCtrl

  • FieldName - the BizField name of BizForm's BizDataObj
  • DisplayName - the label of the control, it is the column head in table format
  • Link - the hyperlink of the control under READ display mode. An example: <BizCtrl Name="LName" FieldName="LastName" Link="a valid relative or absolute url"/>. Users will see on the UI the last name (i.e. Wilson) hyperlink (the link is the url).
  • DrilldownLink - refer to "Configure drilldown link to another view"
  • Sortable - indicates if the field is sortable column in table format
  • Order - the sequence of BizCtrls
  • ValuePicker - refer to "Configure a BizCtrl to show popup"

Event handling in BizForm 

As a html element can trigger events like onclick and onblur, each html Control or BizCtrl may have event handling functions associating to events. Event handling is defined in following syntax.

<Control Name="ControlName" Type="ControlType">
   <EventHandler Name="ehName" Event="eventName" Function="..." FunctionType="..." PostAction=""/> +
</Control>

More than event handlers can be associated to a control. This is a new feature in 2.1 release. In Openbiz 2.0, one control can have only one event handling function. In 2.1, Function and FunctionType attributes are moved from Control Element (2.0 way) to EventHandler element under Control element (2.1 way).

- Event is the html element event name. Please refer to http://www.w3.org/TR/REC-html40/interact/scripts.html, 18.2.3 Intrinsic events.

- Function gives a BizForm method name and arguments. Server side should have a corresponding BizForm method. When the request hits BizController, it is routed to the BizForm method. If the method doesn't exist, an error is returned. Function with syntax of 

  <EventHandler ... Function="objectName.methodName(arg1, arg2...)" .../>. 

The objectName can be empty, this means it calls method of current BizForm. For example, <EventHandler ... Function="SaveRecord()" .../>. User can only invoke method of objects whose have metadata files. These objects include BizForm, BizDataObj, BizView and PluginService. BizForm methods and PluginService methods are recommended to be callable from client side.

- FunctionType can be either RPC or Page or Form or Popup.

FunctionType Explanation Example
RPC the function is invoked on server side by HTTPRequest (AJAX). RPC is default value New record button:
<Control Name="btn_new" Function="NewRecord()" FunctionType="RPC"/>
Page the function is invoked on server side with page reload, form data is not passed to server Export button to bring up a file save dialog in the page
<Control Name="btn_export" Function="CallService(ioService,exportXML)" FunctionType="Page"/>
Form the function is invoked on server side by form submission Save button when there's file to upload in the form:
<Control Name="btn_save" Function="SaveRecord()" FunctionType="Form"/>
Popup the function is invoked on server side targeting to a new popup window Excel output button to show excel format in a popup:
<Control Name="btn_excel" Function="CallService(excelService,renderHTML)" FunctionType="Popup"/>

- ShortcutKey associates a shortcut key to the function. It is explained in "Keyboard navigation on BizForm".

- PostAction is the redirected page/view after an action is taken. It is explained in "Controlling page navigation".

Keyboard navigation on BizForm

Openbiz 2.1RC adds a very important feature - keyboard navigation support on BizForm. Once shortcut keys are defined on BizForm, users are able to use keyboard to to navigate records and pages, create/edit/delete record. Users can have the rich client experience on browser. 

Shortcut keys are defined in BizForm metadata files. EventHandler of controls can have a ShortcutKey attribute to associate the shortcut key to a function. The syntax is <Control Name="" Function="" ShortcutKey="key_combination".../>. BizForm only recognizes shortcut keys defined in controls of its Toolbar and Navbar.

Openbiz recognizes keys including:

Key input key text to use in ShortcutKey attribute
0,1,...9 0,1,...9
a,b,...z or A,B,...Z A,B,...Z
Ctrl key Ctrl
Shift key Shift
Alt key Alt
Enter key Enter 
Escape key Escape
Page up key PageUp
Page down key PageDown
Left arrow key Left
Right arrow key Right
Up arrow key Left
Down arrow key Down
Insert key Insert
Delete key Delete

Developers can configure combination of Ctrl and/or Shift and/or Alt with other key, just use "+" to link them together. Be aware of not conflicting with default shortcut keys of browsers. Please refer to http://www.mozilla.org/support/firefox/keyboard for shortcut key for different browsers.

See shortcut key sample in demoapp/metadata/demo/FMEvent.xml. This BizForm supports following shortcut keys:

Shortcut key Command to execute
Ctrl+Shift+Right go to next page
Ctrl+Shift+Left go to previous page
Ctrl+Shift+Down go to next record
Ctrl+Shift+Up go to previous record
Ctrl+Shift+N create a new record
Ctrl+Shift+E edit the selected record
Delete delete the selected record
Ctrl+Shift+Q switch to search record mode
Enter run search, or save record
Escape cancel search or cancel editing
Ctrl+Shift+C copy the selected record
Ctrl+Shift+R refresh form with default query

Form controls dependency

In a complex form, there's usually some controls depending the values of other controls. When the driving control changes, its children controls change accordingly. This is so called form controls dependency.

With the help of expression language, controls relationship can specified in BizForm metadata file. With the help of event handlers, events on driving control will cause the dynamical changes on its children controls.

A sample form is delivered  under demoapp/metadata/demo/FMFieldDepTest.xml

The first combobox is the driving control. Based on its value,
- 2nd control will be enabled or disabled (BizForm configuration)
- 3rd control will be hidden or shown (BizForm configuration)
- 4th control will have different lists (BizForm configuration)
- 5th control will change value and color when monuseover the 1st control (customer js class extending from jbForm)

Configuration of record-selecting popup BizForm 

Users can pick record from a different form on the following cases:

  • Add/change the child record (parent-child is M-1) by picking another child record.
  • Add a child record in the child form (parent-child is M-M) by picking an existing child record
  • Add/change the joined fields by picking a record from joined dataobj.

Note: Openbiz keeps only one instance of a metadata object (of BizDataObj, BizForm, BizView) in a user session, so always configure a different object when two instances of same entity needed in one view. For example, on an Event form (FMEvent / BOEvent), we usually configure an event popup as (FMEventPopup / BOEventX). There're two ways to configure a record-selecting popup BizForm.

  • Configure a html control to show popup

To configure a html control to show popup form, users can set "ShowPopup($popupFormName)" in the control Function attribute and set FunctionTarget="Popup". This configuration can be used in picking a child record (M-1 or M-M) in the child form.

<Control Name="btn_new" Caption="Add" Type="Button" Function="ShowPopup(demo.FMAttendeePopup)" FunctionTarget="Popup"/>

On the popup form, add a button to call AddToParent() to add the current selected record to the parent form (the form trigger the popup). 

  • Configure a BizCtrl to show popup

To configure a BizCtrl to show popup from, user ValuePicker attribute.

<BizCtrl Name="reg_attdln" FieldName="AttdLName" DisplayName="Last Name" ValuePicker="FMAttendeePopup"/>

On the popup form, add a button to call JoinToParent() to join the current selected record to the parent form (the form trigger the popup).

  • Configure an automatic value picker for a BizCtrl

You can user ValuePicker attribute to allow users to click the icon to show the picker popup window. Users may want to type in the value in the control and system will automatically pick the right record according to the user input. Openbiz supports this feature by BizForm's AutoPickValue($ctrlname) method. To configure auto picker.

<BizCtrl Name="reg_attdln" FieldName="AttdLName" DisplayName="Last Name" ValuePicker="FMAttendeePopup">
   <EventHandler Name="onchange" Event="onchange" Function="AutoPickValue(reg_attdln)" />
</BizCtrl>

According to the user input, the behavior is described in the following table:

Case User input Behavior
1 empty delete all related controls values
2 not empty query the DataObj of valuepicker BizForm with searchRule as [field] LIKE 'input_value%'. Based on the query results:

  • if single record returned, auto fill all related controls values with returned value
  • if no record returned, show value picker popup with no searchRule
  • if multiple records returned, show value picker popup with the searchRule

Configure drilldown link to another view

You can configure a BizCtrl associated with a hyperlink (drilldown link) which changes current view to another view who has the detailed information of that BizCtrl.

In a BizForm, set a DillDownLink attribute of a BizCtrl. The syntax is

DrillDownLink="OtherView,OtherBizForm.OtherBizCtrl=MyBizCtrl".
OtherView - a view name the link takes to;
OtherBizForm - an independent BizForm, which is not a subforml of any other BizForm, in OtherView;
OtherBizCtrl - a BizCtrl of OtherBizForm
MyBizCtrl - a BizCtrl in current BizForm 

Here's an example: <BizCtrl Name="reg_attdln" FieldName="AttdLName" DisplayName="Last Name" ValuePicker="FMAttendeePopup" DrillDownLink="AttendeeView,FMAttendee.attd_id=reg_attdid"/>.

Select field data from comboBox or ListBox

- Bind static list to comboBox

In your BizForm, you assign SelectFrom="Selection(Fee)" for a BizCtrl, which means this field control is a comboBox whose data is from the "Fee" elements in Selection.xml file. Please see example in demo FMRegist.xml where BizCtrl reg_fee is defined as a comboBox.
<Selection>
  <Fee Value=""/>
  <Fee Value="15"/>
  <Fee Value="20"/>
</Selection>

Also, you can give both value and text. If only give value, openbiz uses the value as the display text.
<Selection>
   <ChartOption Value="AAA" Text="BarLine Chart"/>
   <ChartOption Value="BBB" Text="Pie Chart"/>
   <ChartOption Value="CCC" Text="GroupBar Chart"/>
</Selection>
You can make up your own xml file that has list of values for selection.

- Bind dynamic list (Table column) to comboBox

In your BizForm, you assign SelectFrom="BizDataObjName[BizFieldName]" for a BizCtrl, which means this field control is a comboBox whose data is from the table column mapping to the BizFieldName of the BizObjName. To avoid same values appear in the comboBox, you need to make sure the BizObj query returns an unique list.

Format SelectFrom="BizDataObjName[BizFieldName4Text:BizFieldName4Value]" is supported too. So users can show BizFieldName4Text field in comboBox and set BizFieldName4Value for value.

A SearchRule can be applied on the SelectFrom with syntax as SelectFrom="BizDataObjName[BizFieldName4Text:BizFieldName4Value], SearchRule_of_the_BizDataObj". For example, <BizCtrl Name="" ... SelectFrom="BOEvent[Name], [Name] LIKE '%Soc%'"/>.

Controlling page navigation

Openbiz has an unique concept of display mode. BizForm can have more than one display modes. Basically each display mode is a rendering mode of the BizForm. A Bizform presents a BizDataObj data to UI, the same data set can be rendered in different modes which is called "display modes".

- Display modes in a BizForm

Display modes are specified in <DisplayModes> section of BizForm metadata file. You can associate smarty template with each mode. For detail please refer to build view and form web templates.

Usually a BizForm can have READ, NEW, EDIT, QUERY display modes. But no limit to associate any display mode to the BizForm. An example is under /demoapp/metadata/shared/FMCalendar.xml. It has display modes as "LIST", "DAY", "WEEK", "MONTH".

Switching between display modes in a BizForm is done in code by calling BizForm method SetDisplayMode($mode). Code may be applied to each display mode to implement special logic.

Each control or BizCtrl has DisplayMode attribute. You can set DisplayMode = "MODE1|MODE2|...". For example, <BizCtrl Name="LastName" ... DisplayMode="EDIT|NEW"/>, then LastName only shown on EDIT and NEW modes.

- Page redirection after an action is finished

It's very common that users click on a button to trigger an action on server side and after the action is finished the page is redirected to another page. Page redirection can be specified as a post action in BizForm metadata file. The syntax is

<EventHandler Name="..." Function="..." PostAction="url|view"/> PostAction can accept url:url_string or view:view_name.

An example is the login form demoapp/metadata/shared/FMAuth.xml

<Control Name="btn_submit" Image="" Caption="Submit" Type="HTMLButton" Function="Login()" PostAction="url:login.php?login=success"/>

- Error page and error message

If the action errors out, application should return error page or error popup to browser.

Import and export from BizForm

Data import and export support is important feature for off-line users. Off-line users usually run the application (web application also can be run in local box) locally on their laptops and take the work back to synchronize with server database. Openbiz provides import and export support in the following ways:

Data export - implemented in exportXML method of ioService. The exported xml file has format as 

<BizDataObj Name="demo.BOAttendeeX">
  <Record>
   <Field Name="field name" Value="field value" /> *
  </Record>
</BizDataObj>

Data import - implemented in importXML method of ioService. The xml file to import has the same format as described above.

Import and Export buttons are configured in FMAttendee form. Import button invokes ioService's exportXML method directly, while export button brings up a popup window to ask for the file to be imported. Please refer to the demoapp/metadata/demo/FMAttendee.xml for details.

It would be possible to add more export/import methods in ioService to support other file types.

Upload file from BizForm

File upload is supported in openbiz shared package. Metadata file is at demoapp/metadata/shared/FMAttachment.xml and class file is at demoapp/bin/shared/FMAttachment.php.

To upload the file, user needs to configure a BizCtrl with type as "File". It maps to a BizField with type as "Blob".

To download the file, users needs to configure a BizCtrl with Function as Download($record_id). Download method is implemented in FMAttachment class.

Please refer to the FMAttachement class and metadata for details.


Openbiz Development Guide

Show openbiz views (pages)

- User URL string as controller.php?view=...&form=...&rule=...&mode=...&OtherInputs...

- Use client javascript GoToView(view, rule, loadPageTarget)

Input Description Sample
view bizview name shared.CalDetailView
form bizform name. This form must not depend on (a subform of) another bizform shared.FMCalDetail
rule the search rule of a bizform

syntax is "form.ctrl operator value".
operator can be =,>,>=,<,<=,!=. "LIKE %" SQL format is also valid rule. "AND", "OR" can be used to add more restriction.

FMSponsor.spr_exp>=12000 

FMSponsor.spr_name=\'Midas Auto\' OR FMSponsor.spr_id=\'SPSR_2\'

FMSponsor.spr_name LIKE \'S%\'

loadPageTarget the window or frame target to load the page  

Build view and form web templates

Smarty template engine is used in OpenBiz to render the HTML output. We provides some basic templates for render BizForm and BizView. You can create your own templates. Remember that an openbiz form must begin with a form tag <form id={$name} name={$name}>. For detail, please refer to http://smarty.php.net/docs.php 

Smarty engine recognizes the subdirectories under the main template directory. So you can create a fold under demoapp/templates/ and put template files there. When you give template file name in metadata file, just give Template="subdir/view.tpl".

- Draw BizForm as a html table

In BizForm xml file, you need give DataFormat as "block" and FormatStyle as table style which is given in css file.
<Mode ... TemplateFile="list.tpl" ... DataFormat="htmltable" FormatStyle="tbl"/>

In template file, {$fmttable}represents form whole html table.

Please refer to demo files FMEvent.xml and list.tpl

- Draw BizForm as a set of controls

Since the array dataformat output to smarty template is associated array, user can easily layout controls by their names. The associated array has format as fields[control_name][label] and fields[control_name][control].

Please refer to demo files FMEvent.xml and edit.tpl

Three DataFormats decide what data is passed to templates

DisplayMode DataFormat Data passed to template Controllability on template Example
array - Variable name to use in template is $fields
- associated array of single record
- array (control_name=>array ("label"=>label_text, "control"=>control_html))
Highly controllable in template edit.tpl
table - Variable name to use in template is $table
- 2D array of multiple records
- array (index=>array (control1_name=>value1, control2_name=>value2, ...))
  array[0] is column header
  array[1-n] are the 1st record to nth record
Highly controllable in template rptlist.tpl
block - Variable name to use in template is $block
- HTML string
lowly controllable in template list.tpl

Using BizDataObj functionalities

Only basic usage of BizDataObj is listed below. Please refer to the API doc for details.

Query and get results

1.x BizObj is renamed as BizDataObj in 2.0, because it mainly acts as business data unit. 

1.x use GetField and SetField to do get and set field values. In 2.0, no field level methods, but using GetRecord() and UpdateRecord() method to do record level operations. The idea behind is to make easier coding to retrieve query results and provide coarse-grained interfaces between 2 layers.

1.x way to query and get records

$bizobj->SetSearchRule("...");    // set search rule
$bizobj->RunSearch(-1);    // run query against the database tables. 
$bizobj->Home();    // reset the result record set
$hasVal = $bizobj->MoveFirst();    // move cursor to first record
while ($hasVal)
{
    foreach ($fieldlist as $field)
        $field_val[] = $bizobj->GetField($field);
   
// user logic code can be put here. 
    $hasVal = $bizobj->MoveNext();    // move cursor to next record
}

2.0 way to query and get records - option 1

$bizobj->SetSearchRule("...");    // set search rule
$bizobj->RunSearch(-1);    // run query against the database tables. query results can be cached
while ($recArray = $bizobj->GetRecord(1))    // get current record and move the cursor to the next record 
{
    // user logic code can be put here. recArray is an associated array whose key is "fieldname" and value is value of the field
}

2.0 way to query and get records - option 2

$bizobj->FetchRecords ($searchRule, $resultSet, $numRecords);    // get the whole recordset (list of recArray), query results won't be cached

Insert, Update and Delete a record 

// Insert Record
$recArr = $boUser->NewRecord();    // NewRecord returns an empty record array with a generate Id field
$recArr["LastName"] = "Test";
$recArr["FirstName"] = "Add";
$ok = $boUser->InsertRecord($recArr);
if (!$ok)     // handle error message
  print $boUser->GetErrorMessage();

// Update a record
$boUser->SetSearchRule("[Id]='USER-1006'");
$boUser->RunSearch();
$recArray = $bizobj->GetRecord(0);
$recArray["FirstName"] = "Update";
$ok = $boUser->UpdateRecord($recArray);
if (!$ok)     // handle error message
  print $boUser->GetErrorMessage();

// Delete a record
$boUser->SetSearchRule("[Id]='USER-1006'");
$boUser->RunSearch();
$recArray = $bizobj->GetRecord(0);
$ok = $boUser->DeleteRecord($recArray);
if (!$ok)     // handle error message
  print $boUser->GetErrorMessage();

Using BizForm functionalities

User can configure function in BizForm metadata file to invoke appropriate action on server side. The commonly used BizForm methods are listed below. Please refer to the API doc for details.

Query and show results

  • SearchRecord - show the query record mode
  • RearchRecord - Issue the query with user input in query mode and return to read mode

Insert a new record

  • NewRecord - show the new record mode
  • SaveRecord - Save current edited record with user input in query mode and return to read mode

Update a record

  • EditRecord - show the edit record mode on current focus record
  • SaveRecord - Save current edited record with user input in query mode and return to read mode

Delete a record

  • DeleteRecord - delete the current focus record

Copy a record

  • CopyRecord - copy the current focus record to new record

Page Navigation

  • MoveNext - show next page records
  • MovePrev - show previous page records

User input validation

According the topic at http://www.boringguys.com/?p=30, there are 3 different types of data validation checks one can do:

  • Syntactic validation - check data syntax 
  • Semantic validation - check one piece of data makes sense in regards to other incoming data
  • Domain or model validation - check data against another source of acceptable values

Syntactic and semantic validation can be implemented on client side and service side. Domain validation involves query data source, it is usually done in service code that connects to database.

Client side form validation

Openbiz does input validation using jsval library (LGPL, http://jsval.fantastic-bits.de/). To configure a validation rules for an openbiz HTMLControl, developers can use jsVal's "Inline initialization" to add validation attributes to HTMLAttr part of HTMLcontrol and FieldControl.

<Control Name="" Type="" HTMLAttr="jsval validation attributes here" ... /> 

Example: <BizCtr Name="email" Type="Text" HTMLAttr="regexp='JSVAL_RX_EMAIL' minlength=5..." ... /> 

In addition, HTMLControl has a Required (=Y|N) attribute. It is passed to pass as $fields['required'] (along with $fields['label'] and $fields['control']) to smarty template. In smarty template (edit.tpl), has code {if $item.required=="Y"} <span class='required'>*</span>{/if} to append a * to the label. Then the required control's label looks as "Email *"

Server side input validation

Openbiz mainly support validation on BizDataObj. In BizField, Required and Validator attributes are used for such purpose. Please see the BizDataObj configuration chapter for explanation of these two attributes.

Developers can use customer class to override DataObj::ValidateInput() method or Field::Validate() method achieve their own validation rules.

BizForm has an empty ValidateForm method which may be overridden by customer classes to implment special validation logic.

Extend OpenBiz classes

OpenBiz provide many functionalities to building a complicated web application. But different application has different requirement, so you may extend OpenBiz packages to build customer applications.

Extend server side classes

Because OpenBiz packages are based on object-oriented design, you can easily build up your own object by extending these packages and inherit all useful functions provided by them.

Extended classes are automatically loaded on demand. Extended class  must be included in a file with format as ClassName.php.

Use can specify class name for BizDataObj, BizField, BizView, BizForm, BizCtrl, Control and PluginService by filling the "Class" attribute of in metadata file

Base Class Where to specify the extend class
BizDataObj <BizDataObj ... Class="" ...>
BizField <BizField ... Class="" ...>
BizView <BizView ... Class="" ...>
BizForm <BizForm ... Class="" ...>
FieldControl <BizCtrl ... Class="" ...>
HTMLControl <Control ... Class="" ...>

Example: Extend BizDataObj and BizForm

/**
* class BOUser is the BizDataObj class to implement USER logic object
*/

class BOUser extends BizDataObj 
{
    function BOUser($xmlFile=null) {} 

      function my_special_function() {}    // new function

/**
* class FMUser is the BizForm class to implement USER UI object
*/

class FMUser extends BizForm 
{
    function FMUser($xmlFile=null) {} 

      function my_special_function() {}    // new function

      function Render() {}    // override Render()
}

Extend client side classes

BizForm is the main server side presentation class, it has its counterpart class on client browser side. In the BizForm metadata, users can specify client side class in jsClass attribute of BizForm element. For example.

<BizForm Name="FMEvent" ... Class="BizForm" jsClass="jbForm"...>

Openbiz provides two client side classes AjaxForm and jbForm that is a subclass of AjaxForm.

AjaxForm methods:

  • CallFunction(method, params_array) - convert function to request and send it to server. A server side BizForm method is invoked by this method if there's no specific method implemented in the client class. For example, a BizForm, whose jsClass=jbForm, has a method named "SelectRecord". Openbiz will check if "SelectRecord" method is defined in jbForm class. If yes, it calls jbForm's SelectRecord(params_array), otherwise it calls CallFunction(method, params_array).
  • CallbackFunction(retContent) - Ajax callback function. It passes the returned content to Show().
  • CollectFormData() - collect form data into a message in Ajax call
  • Show(retContent) - called by callback function to show Ajax returned content in the form

jbForm methods:

  • CollectFormData() - overriding AjaxForm CollectFromData(), add additional "selected row" in the form data
  • SelectRecord(params_array) - special logic on select record call
  • SortRecord(params_array) - special logic on sort record call
  • DeleteRecord(params_array) - special logic on delete record call

To implement UI logic on client side, developers need to create their own client side class like jbForm and give the class name to jsClass attribute of BizForm element. If you need special logic in some methods, add these methods in the client class, which can be subclass of either AjaxForm or jbForm. These methods can be pure client code or it can this.CallFunction(...) to send the request to server.

An example:

Form metadata file is like:

<BizForm ... Class="MyForm" jsClass="MyjbForm"...>
...
   <BizCtrl Name="mybutton" ...>
      <EventHandler Name="onclick" Event="onclick" Function="server_MyButtonClick"/>
      <EventHandler Name="onblur" Event="onblur" Function="js_MyButtonBlur"/>
...
</BizForm>

In server side MyForm class, server_MyButtonClick() needs to be defined.

In client side MyjbForm class, js_MyButtonBlur() needs to be defined. Of course, if server_MyButtonClick() is defined in client class, server_MyButtonClick() needs to call this.CallFunction("server_MyButtonClick", params_array) at the end of the method to send the request to server MyForm server_MyButtonClick() method. The client side code will be like:

function MyjbForm(name) {}
MyjbForm.inheritsFrom(jbForm); //set inheritance
MyjbForm.prototype.js_MyButtonBlur = function (params_array)
{
    // put client logic here
    ...
}
MyjbForm.prototype.server_MyButtonClick= function (params_array)
{
    // put client logic here
    ...
    // send request to server side at the end
    this.CallFunction("server_MyButtonClick", params_array);
}

Implement Plug-in Service

Openbiz customer can write their special logic by implement Plug-in Service. Plugin services are also metadata-driven objects. Service code is under bin/service and metadata is under /metadata/service. The plugin service metadata only gives the service name, package and implementing class. Any xml elements can be child of the root PluginService element. This is because different services may have different metadata configuration. Please refer to the Appendix to see the DTD of plugin service metadata xml file.

Openbiz core library includes services under openbiz/bin/service/ and their metadata files under openbiz/metadata/service/.

  • excelService.php - print Excel output with HTML or CSV formats
  • authService.php - authentication service, please refer to next chapter for usage
  • accessService.php - view access control service, please refer to next chapter for usage
  • profileService.php - user profile service, please refer to next chapter for usage
  • logService.php - write log to file
  • ioService - data winput/output service
  • pdfService.php -  prints PDF report
  • emailService.php - integrated with PHPMailer to send emails through smtp mail server.
  • doTriggerService - BizDataObj trigger service
  • auditService - audit trail service to trace data change

In the application, you can specify your own plugin service implementation with following methods.

  1. Change the service metadata content under your_app/metadata/service/, still use the core service. For example, you can write different accessService.xml to control the view access rule, but the implementing class is accessService.php in core library. The accessService.xml is like 
    <PluginService Name="accessService" Package="service" Class="accessService">
       application specific view access definition
    </PluginService>
  2. Specify the service implementing class. For example, different applications have different profile service. The profileService.xml is like 
    <PluginService Name="profileService" Package="service" Class="your_own_service_class">
    </PluginService>
  3. Combine the above 2 methods.

Write a plug-in service

Implement the class and method in the ClassName.php
A input argument of the method are the caller's object name (a BizForm name) and the input data string (a collection of form values from client browser). It implements the user-specific business logic and returns void. See the following code snippet.

class pdfService
{
 function pdfService() {}

 function renderView($viewName)
 {
  global $g_BizSystem;
  // get the view object and render the view to a html string
  $viewobj = $g_BizSystem->GetObjectFactory()->GetObject($viewName);
  if($viewobj) {
    $viewobj->SetConsoleOutput(false);
  $sHTML = $viewobj->Render();
  // convert HTML to PDF
  // ... customer code to do the convert 
 }
}

Call a plug-in service method

  • Call service in form. Define the caller function in BizForm metadata file
    <... Function="CallService(ClassName,MethodName)"...> is to call a method "MethodName" of the service "ClassName". ClassName is a class which defined in ClassName.php under bin/usrlib/ directory
  • Call service with url. Use url like bin/BizController.php?F=Invoke&P0=[servicename]&P1=[methodname]&P2=[parameter1]... The example is bin/BizController.php?F=Invoke&P0=[pdfService]&P1=[renderView]&P2=[demo.ReportView]
  • Call service in code. 
    global $g_BizSystem;
    $svcobj = $g_BizSystem->GetService($class);
    $svcobj->$method($this->m_Name);

Implement authentication, view and data access control

User authentication

Openbiz uses authentication service (usrlib/authService.php) to authenticate username and password

public function AuthenticateUser ($userid, $password) is called to authenticate user. 

  • AuthenticateUser by default querys on "User Id" and "Password" fields defined in metadata/shared/BOAuth.xml. If input user id and password is found in in BOAuth, AuthenticateUser returns true. AuthenticateUser method is to be modified to fit customer logic.
  • metadata/shared/SignupView.xml is the default login view. This view can be configured for change the login look and feel.

Role-based view access control

View access control depended on the AccessControl attribute in view metadata file in Openbiz 1.x. From Openbiz RC1, openbiz implements role-based view access control in its new security architecture. 

Openbiz uses profile service (usrlib/profileService.php) to get user profile that includes "role". Then match this role to access service (usrlib/accessService.php) to determine the users' accessibility to the view

public function GetProfile ($userid=null) is called to get user profile array which is an associated array with profile key and profile value pairs.

  • Customer must replace the default GetProfile method in openbiz package, because the default GetProfile method returns some randomly made array.

public function AllowViewAccess ($viewName, $role=null) is called to check the accessibility of a view

  • accessService has a configuration file (accessService.xml) that defines the view access permission. Please see an example below.

  • The xml configuration file is easy to understand. Customer needs to put their own logic in the accessService.xml.

Attribute-based data access control

Openbiz uses profile service (usrlib/profileService.php) to get user profile that includes attributes. Then based on these attributes to determine browse/update/delete permission of data record. The data access permissions are controlled in BizDataObj.

User can refer to attributes by @profile:attribute in BizDataObj metadata files. Profile attributes are all from profileService. When user first login, profileService returns a profile array that is saved in session. If an attribute is found in the profile array, the attribute value is returned. If the profile array doesn't contain such attribute, profileService method GetAttribute ($userid, $attr) is called to return the attribute value. Customer must implement GetAttribute method with their own logic.

- Data browse permission. A typical access control requirement is to limit the accessibility of table record to different users. This feature can be achieved by configuring AccessRule in BizDataObj metadata file. We do the configuration with the following two scenario.

Scenario  Configuration
Event can be only accessed by the owner

(personal access control)

<BizDataObj Name="Event" ... AccessRule="[OwnerId]='@profile:ORGID'" ...>

<BizField Name="OwnerId" Column="OWNER_ID"/>

Event can be accessed by all invited attendees 

(if the login user is one of the attendees, he can access the event)

<BizDataObj Name="Event" ... AccessRule="[AttendeeId]='@profile:USERID'" ...>

<BizField Name="AttendeeId" Column="ATTD_ID" Join="Attendee"/>

<Join Name="Attendee" Table="evts_attds" Column="EVT_ID" ColumnRef="SYSID" JoinType="LEFT JOIN"/>

- Data update permission. UpdateCondition is to control the record update permission. UpdateCondition expects true or false. A sample is UpdateCondition = "[OrgId]=={@profile:ORGID}". {} is the evaluated as simple expression.

- Data delete permission. DeleteCondition is to control the record delete permission. DeleteCondition expects true or false. A sample is DeleteCondition = "'admin'=={@profile:ROLEID}"

Build a multi-step wizard view

Wizard is a sequence of forms (questionnaires) which guide users to complete a complicated task. An example is filling an expense report which include different types (hotel, airfare, other activities...) of expenses.

Openbiz support wizard by easy metadata configuration. Openbiz wizard has following features:

  • Each form has "Next", "Back", "Cancel" and "Finish" navigation buttons.
  • If user clicks cancel button, user input data is not saved to database.
  • User input data won't to commit to database until user clicks finish button.

To see sample of wizards, go to Test view, click on "Wizard tests +" submenus. As you can see from the demo, wizard can be accessed with an url. 

As shown in the 2nd link, developer can give the parameter on the fly to run the wizard against given record

Configuration of wizard view

Openbiz wizard is a regular view that contains several wizard forms. So configuring a wizard in openbiz is no harder than  configuring a BizView. The difference between a wizard view and regular view is wizard view show the wizard forms one by one based on the their sequence in view metadata file, but regular view show all forms in one page. Below is an example of a wizard view metadata file.

<?xml version="1.0" standalone="no"?>
<BizView Name="EventWizardView" Description="" Package="demo" Class="BizViewWizard" Template="view.tpl">
   <ControlList>
      <Control Name="wizardForm1" Form="FMEventWzd1"/>
      <Control Name="wizardForm2" Form="FMEventWzd2"/>
   </ControlList>
   <Parameters>
      <Parameter Name="Evt_Id" Value="" />
   </Parameters>
</BizView>

Configuration of wizard forms

A wizard form is a regular form with class as BizFormWizard or BizFormNewWizard (or their subclasses).

  • BizFormWizard - to edit a record
  • BizFormNewWizard - to create a record

This is a typical wizard form metadata file.

<?xml version="1.0" standalone="no"?>
<BizForm Name="FMNewEventWzd1" Package="demo" Class="BizFormNewWizard" jsClass="jbForm" Title="Enter event information:" SearchRule="" Description="Event BizForm" BizDataObj="BOEvent">
  <DisplayModes>
    <Mode Name="EDIT" TemplateFile="edit.tpl" DataFormat="array" FormatStyle="" />
  </DisplayModes>
  <BizCtrlList>
    <BizCtrl Name="evt_id" FieldName="Id" DisplayName="Event Id" />
    <BizCtrl Name="evt_name" FieldName="Name" DisplayName="Name" Type="" Width="250" />
    <BizCtrl Name="evt_desc" FieldName="Description" DisplayName="Description" Type="Textarea" />
    <BizCtrl Name="evt_host" FieldName="Host" DisplayName="Host" />
  </BizCtrlList>
  <Toolbar>
    <Control Name="btn_back" Image="" Caption="&lt; Back" Type="Button" Function="GoPrev()" />
    <Control Name="btn_next" Image="" Caption="Next &gt;" Type="Button" Function="GoNext()" />
    <Control Name="btn_cancel" Image="" Caption="Cancel" Type="Button" Function="DoCancel()" PostAction="view:demo.EventView"/>
    <Control Name="btn_finish" Image="" Caption="Finish" Type="Button" Function="DoFinish()" PostAction="view:demo.EventView"/>
  </Toolbar> 
  <Navbar>
  </Navbar> 
</BizForm>

Extend wizard with customer wizard class

If application has speical logic, Openbiz suggest developers to write their own wizard form class drived from BizWizardForm. By overriding GoPrev(), GoNext(), DoCancel() and DoFinish() methods, developers can do different handling on navigation buttons events.

Openbiz wizard view play the role as a form controller where wizard form can set/get input data, cancel/finish the whole wizard process and render wizard forms. Please see the API document for details.

Implement dataobject events trigger

Upon dataobjects update/delete operations, openbiz allows triggering different alerts and action requests based on boolean results from search criteria for specific object. Briefly it is called DO Trigger which executes in a response to a change in the values stored in the database. DO trigger has two parts - trigger events and trigger actions. These information are defined in DOTrigger plugin service metadata files. At runtime when user update/delete a BizDataObj record, openbiz searches for this dataobj's trigger by looking for its trigger metadata file with name DataObjName_trigger.xml under the same directory. For example, demo/BOEvent's dataobj trigger metadata file is demo/BOEvent_trigger.xml.

Define a dataobject trigger metadata

<PluginService Name="BOEvent_Trigger" Description="" Package="demo" Class="service.doTriggerService" DataObjectName="BOEvent">
<DOTrigger TriggerType="UPDATE|DELETE">*
  <TriggerCondition Expression="" ExtraSearchRule="" />
  <TriggerActions>
    <TriggerAction Action="Method_Name" Immediate="Y|N" DelayMinutes="" RepeatMinutes="">
      <ActionArgument Name="" Value="" /> *
    </TriggerAction>
  </TriggerActions>
</DOTrigger>
</PluginService>

Trigger conditions Description Sample
trigger type Update or Delete record  
expression any expression supported by openbiz {[Expense]}>100. Check if current record's Expense field > 100
extra search rule search rule added on the current dataobj search rules {[AlertFlag]}='Y'. Check if there's at least one record whose AlertFlag is 'Y'
Trigger action methods Description Parameters
ExecuteSQL ExecuteSQL method executes SQL statement Name="DBName" Value="Default"
Name="SQL" Value="select * from regist where EVENT_ID='{[Id]}'"
ExecuteShell ExecuteShell method executes external application Name="Script" Value="dir"
Name="Inputs" Value=" > d:\temp\out.txt"
SendEmail SenEmail method sends outbound emails. 

It calls emailService's sendEmail method

Name="EmailService" Value="service.emailService"
Name="Account" Value="MyPhpopenbiz"
Name="TOs" Value="rockyswen@gmail.com; rockyswen@phpopenbiz.org"
Name="CCs" Value=""
Name="BCCs" Value=""
Name="Subject" Value="alert message"
Name="Body" Value="This is an alert message. \nPlease notice that the record with {[Id]} was updated."
Name="Attachments" Value="" 
AuditTrail Trace record field change

It calls auditService Audit method

Name="AuditService" Value="service.auditService"
Name="DataObjectName" Value="{@:Name}"
any method in doTriggerService The method of doTriggerService is called  Parameters needed to the method

Make customer specific UI components

Due to the extensibility nature of metadata xml files, developers can create their own metadata file, which does not comply with openbiz metadata DTD, to describe the behavior of objects. Openbiz converts xml file to a php array and pass it to the class constructor to save developers' parsing work. Developers need to write their own code to extend from MetaObject class and read in the array by overriding ReadMetadata(&$xmlArr) method.

Tabs component

This is the good example of using customer metadata xml file. Openbiz 2.1 supports tabs UI component. The metadata file (demo/tabs.xml) is like

<?xml version="1.0" standalone="no"?>
<BizForm Name="Tabs" Package="demo" Class="HTMLTabs">
  <TabViews>
    <View Name="demo.AttendeeView" URL="" Caption="Attendees"/>
    <View Name="demo.EventView" URL="" Caption="Events"/>
  </TabViews>
</BizForm>

The class code is under openbiz/bin/HTMLTabs.php. Its css file is in openbiz.css.

Developer can draw more UI widgets like tree, menu using the same approach. 

Menu component 

Openbiz 2.1 supports menu UI component. The metadata file of a menu (i.e. demo/Menus.xml) is like

<?xml version="1.0" standalone="no"?>
<Menu Name="Menus" Package="demo" Class="HTMLMenus">
  <MenuItem URL="" Caption="" Target=""> *
    <MenuItem URL="" Caption="" Target=""/> *

The class code is under openbiz/bin/HTMLMenus.php. Its css file is /css/menu.css

The menu provided in the demo application can be seen in "Test" view. This menu is a horizontal dropdown menu. It is a pure css menu. The idea is copied from http://solardreamstudios.com/learn/css/cssmenus. The output html (<ul><li>...) has same format of the output of well-known DynarchMenu http://www.dynarch.com/products/dhtml-menu/. So integration with DynarchMenu is an easy job. Of course, developers are free to modify the HTMLMenus class to work with other menu libraries. Same principle will apply to other customer UI components.

Tree component

Openbiz 2.1 supports tree UI component. The metadata file of a tree (i.e. demo/Tree.xml) is like

<?xml version="1.0" standalone="no"?>
<Tree Name="Tree" Package="demo" Class="HTMLTree">
  <Node URL="" Caption="" Target=""> *
    <Node URL="" Caption="" Target=""/> *

The class code is under openbiz/bin/HTMLTree.php. Its css file is in openbiz.css

The tree provided in the demo application can be seen in "Test" view. The technique of drawing tree is same as the tree of Eclipse help system http://help.eclipse.org/help30/index.jsp. Again, developers are free to modify the HTMLTree class to work with other tree libraries.

Control the look and feel with css files

The openbiz look and feel is controlled by stylesheet css files. The main css file is /css/openbiz.css

Control BizForm table style

In case of using Format="block" in the BizForm's displayMode, users can modify the following section in css/openbiz.css file.

/* -------- table style -------- */
.tbl {...}
.tbl .head {...}
.tbl .rowodd {...}
.tbl .roweven {...}
.tbl .rowsel {...}
.tbl .cell {...}

Control tabs style

In order to give user specific tab styles, users can modify the following section in css/openbiz.css file.

/* -------- tabs style -------- */
.tabmenu {...}
.tabmenu li {...}
.tabmenu a, a.active {...}
.tabmenu a.active {...}
.tabmenu a:hover {...}
.tabmenu a:visited {...}
.tabmenu a.active:hover {...}

Control menu style

In order to give user specific tab styles, users can modify the following section in css/menu.css file.

Control tree style

In order to give user specific tree styles, users can modify the following section in css/openbiz.css file.

/* ----- tree style ----- */
UL.expanded {...}
UL.collapsed {...}
LI.tree {...}

Control rich text editor (RTE) style

In order to give user specific RTE styles, users can modify the following section in pages/rte/rte.css file.

Date and Datetime picker

The DHTML calendar is well documented at  http://www.dynarch.com/demos/jscalendar/doc/html/reference.html. The javascript file is under demoapp/js/jscalendar.

Debug strategies

- Logging. BizSystem::log() method  can be called to log 4 priority levels LOG_EMERG, LOG_ERR, LOG_WARNING and LOG_DEBUG. Also a subject can be specified to give log messages different categories. The error is logged under /log/log_error.html, open it and you may find out what's wrong

- Debugging. Other than the DEBUG flag in 1.1.x is still valid, developers can turn on other 2 debug flags.
  1) Open the sysheader.inc under /bin, turn on debug log by changing define("DEBUG", 1); Then you'll see some debug information in /log/log_debug.html. This debug file records mainly the database calls and other operations
  2) Turn on SQL debug flag. Uncomment //$this->m_DbConnection[$rDBName]->debug = true; in BizSystem::GetDBConnection().
  3) Turn on RPC debug flag, each RPC response is printed in a separate window. Set var RPC_DEBUG = true; in clientUtil.js.

API document

Openbiz 2.0 API document

Appendix  A - third party libraries

Library URL Description License
Smarty  http://smarty.php.net template engine LGPL
Adodb http://adodb.sourceforge.net  database abstraction library BSD
PHPMailer http://phpmailer.sourceforge.net  email library LGPL
jsval http://jsval.fantastic-bits.de  client side data validation LGPL
jscalendar http://www.dynarch.com/projects/calendar  DHTML calendar LGPL
RTE http://www.kevinroth.com/rte/demo.htm  Cross browser rich text editor free
dompdf http://www.digitaljunkies.ca/dompdf  html to pdf convertor free

Appendix  B - metadata DTD files

BizDataObj metadata DTD file

<!--OpenBiz BizObj metadata DTD-->

<!ELEMENT BizObj (BizFieldList, TableJoins, ObjRefernces, Parameters) >
<!ATTLIST BizObj Name CDATA #REQUIRED >
<!ATTLIST BizObj Description CDATA #REQUIRED >
<!ATTLIST BizObj Package CDATA #IMPLIED >
<!ATTLIST BizObj Class CDATA #REQUIRED >
<!ATTLIST BizObj InheritFrom CDATA #IMPLIED >
<!ATTLIST BizObj DBName CDATA #IMPLIED >
<!ATTLIST BizObj Table CDATA #REQUIRED >
<!ATTLIST BizObj SearchRule CDATA #IMPLIED >
<!ATTLIST BizObj SortRule CDATA #IMPLIED >
<!ATTLIST BizObj OtherSQLRule CDATA #IMPLIED >
<!ATTLIST BizObj AccessRule CDATA #IMPLIED >
<!ATTLIST BizObj UpdateCondition CDATA #IMPLIED >
<!ATTLIST BizObj DeleteCondition CDATA #IMPLIED >

<!ATTLIST BizObj CacheMode CDATA #IMPLIED >

<!ELEMENT BizFieldList (BizField+) >
<!ELEMENT BizField EMPTY >
<!ATTLIST BizField Name CDATA #REQUIRED >
<!ATTLIST BizField Class CDATA #IMPLIED >
<!ATTLIST BizField Join CDATA #IMPLIED >
<!ATTLIST BizField Column CDATA #REQUIRED >
<!ATTLIST BizField SQLExpr CDATA #IMPLIED >
<!ATTLIST BizField Type CDATA #IMPLIED >
<!ATTLIST BizField Format CDATA #IMPLIED >
<!ATTLIST BizField Required CDATA #IMPLIED >
<!ATTLIST BizField Validator CDATA #IMPLIED >
<!ATTLIST BizField DefaulValue CDATA #IMPLIED >
<!ATTLIST BizField Value CDATA #IMPLIED >
<!ATTLIST BizField OnAudit CDATA #IMPLIED >
<!ELEMENT TableJoins (Join+) >
<!ELEMENT Join EMPTY >
<!ATTLIST Join Name CDATA #REQUIRED >
<!ATTLIST Join Table CDATA #REQUIRED >
<!ATTLIST Join Column CDATA #REQUIRED >
<!ATTLIST Join JoinRef CDATA #IMPLIED >
<!ATTLIST Join ColumnRef CDATA #REQUIRED >
<!ATTLIST Join JoinType CDATA #REQUIRED >

<!ELEMENT ObjReferences (Object+) >
<!ELEMENT Object EMPTY >
<!ATTLIST Object Name CDATA #REQUIRED >
<!ATTLIST Object Description CDATA #IMPLIED >
<!ATTLIST Object Relationship CDATA #REQUIRED >
<!ATTLIST Object Table CDATA #REQUIRED >
<!ATTLIST Object Column CDATA #REQUIRED >
<!ATTLIST Object FieldRef CDATA #REQUIRED >
<!ATTLIST Object CascadeDelete CDATA #IMPLIED >
<!ATTLIST Object XTable CDATA #IMPLIED >
<!ATTLIST Object XColumn1 CDATA #IMPLIED >
<!ATTLIST Object XColumn2 CDATA #IMPLIED >

<!ELEMENT Parameters (Parameter+) >
<!ELEMENT Parameter EMPTY >
<!ATTLIST Parameter Name CDATA #REQUIRED >
<!ATTLIST Parameter Value CDATA #IMPLIED >
<!ATTLIST Parameter Required CDATA #IMPLIED >
<!ATTLIST Parameter InOut CDATA #IMPLIED >

BizView metadata DTD file.

<!--OpenBiz BizView metadata DTD-->

<!ELEMENT BizView (ControlList, Parameters) >
<!ATTLIST BizView Name CDATA #REQUIRED >
<!ATTLIST BizView Description CDATA #REQUIRED >
<!ATTLIST BizView Package CDATA #IMPLIED >
<!ATTLIST BizView Class CDATA #IMPLIED >
<!ATTLIST BizView Template CDATA #IMPLIED >

<!ELEMENT ControlList (Control+) >
<!ELEMENT Control EMPTY >
<!ATTLIST Control Name CDATA #REQUIRED >
<!ATTLIST Control Form CDATA #REQUIRED >
<!ATTLIST Control SubCtrls CDATA #IMPLIED >

<!ELEMENT Parameters (Parameter+) >
<!ELEMENT Parameter EMPTY >
<!ATTLIST Parameter Name CDATA #REQUIRED >
<!ATTLIST Parameter Value CDATA #IMPLIED >
<!ATTLIST Parameter Required CDATA #IMPLIED >
<!ATTLIST Parameter InOut CDATA #IMPLIED >

BizForm metadata DTD file.

<!--OpenBiz BizForm metadata DTD-->

<!ELEMENT BizForm (BizCtrlList, DisplayModes, Toolbar, Navbar, Parameters) >
<!ATTLIST BizForm Name CDATA #REQUIRED >
<!ATTLIST BizForm Description CDATA #REQUIRED >
<!ATTLIST BizForm Package CDATA #IMPLIED >
<!ATTLIST BizForm Class CDATA #REQUIRED >
<!ATTLIST BizForm InheritFrom CDATA #IMPLIED >
<!ATTLIST BizForm jsClass CDATA #REQUIRED >
<!ATTLIST BizForm Title CDATA #REQUIRED >
<!ATTLIST BizForm BizDataObj CDATA #REQUIRED >
<!ATTLIST BizForm PageSize CDATA #REQUIRED >
<!ATTLIST BizForm SearchRule CDATA #IMPLIED >

<!ELEMENT BizCtrlList (BizCtrl+) >
<!ELEMENT BizCtrl (EventHandler+) >
<!ATTLIST BizCtrl Name CDATA #REQUIRED >
<!ATTLIST BizCtrl Class CDATA #IMPLIED >
<!ATTLIST BizCtrl FieldName CDATA #IMPLIED >
<!ATTLIST BizCtrl DisplayName CDATA #IMPLIED
>
<!ATTLIST BizCtrl Type CDATA #IMPLIED >
<!ATTLIST BizCtrl Width CDATA #IMPLIED >
<!ATTLIST BizCtrl Height CDATA #IMPLIED >
<!ATTLIST BizCtrl HTMLAttr CDATA #IMPLIED >
<!ATTLIST BizCtrl Link CDATA #IMPLIED >
<!ATTLIST BizCtrl Image CDATA #IMPLIED >
<!ATTLIST BizCtrl Hidden CDATA #IMPLIED >
<!ATTLIST BizCtrl Enabled CDATA #IMPLIED >

<!ATTLIST BizCtrl Sortable (Y|N) "" >
<!ATTLIST BizCtrl Order CDATA #IMPLIED >
<!ATTLIST BizCtrl Style CDATA #IMPLIED >
<!ATTLIST BizCtrl ValuePicker CDATA #IMPLIED >
<!ATTLIST BizCtrl SelectFrom CDATA #IMPLIED >
<!ATTLIST BizCtrl DrillDownLink CDATA #IMPLIED >
<!ATTLIST BizCtrl DisplayMode CDATA #IMPLIED >

<!ELEMENT Toolbar (Control+) >
<!ELEMENT Navbar (Control+) >
<!ELEMENT Control (EventHandler+) >
<!ATTLIST Control Name CDATA #REQUIRED >
<!ATTLIST Control Class CDATA #IMPLIED >
<!ATTLIST Control Image CDATA #IMPLIED >
<!ATTLIST Control Caption CDATA #IMPLIED >
<!ATTLIST Control Type CDATA #IMPLIED >
<!ATTLIST Control Width CDATA #IMPLIED >
<!ATTLIST Control Height CDATA #IMPLIED >
<!ATTLIST Control HTMLAttr CDATA #IMPLIED >
<!ATTLIST Control Style CDATA #IMPLIED >
<!ATTLIST Control Hidden CDATA #IMPLIED >
<!ATTLIST Control Enabled CDATA #IMPLIED >
<!ATTLIST Control SelectFrom CDATA #IMPLIED >

<!ATTLIST Control DisplayMode CDATA #IMPLIED >

<!ELEMENT EventHandler EMPTY >
<!ATTLIST EventHandler Name CDATA #REQUIRED >
<!ATTLIST EventHandler Event CDATA #REQUIRED >
<!ATTLIST EventHandler Function CDATA #REQUIRED >
<!ATTLIST EventHandler FunctionType CDATA #IMPLIED >
<!ATTLIST EventHandler ShortcutKey CDATA #IMPLIED >
<!ATTLIST EventHandler PostAction CDATA #IMPLIED >
<!ELEMENT DisplayModes (Mode+) >
<!ELEMENT Mode EMPTY >
<!ATTLIST Mode Name CDATA #REQUIRED >
<!ATTLIST Mode TemplateFile CDATA #REQUIRED >
<!ATTLIST Mode DataFormat CDATA #REQUIRED >
<!ATTLIST Mode FormatStyle CDATA #IMPLIED >

<!ELEMENT Parameters (Parameter+) >
<!ELEMENT Parameter EMPTY >
<!ATTLIST Parameter Name CDATA #REQUIRED >
<!ATTLIST Parameter Value CDATA #IMPLIED >
<!ATTLIST Parameter Required CDATA #IMPLIED >
<!ATTLIST Parameter InOut CDATA #IMPLIED >

Plugin service metadata DTD file.

<!--OpenBiz Plugin service metadata DTD-->

<!ELEMENT PluginService ANY >
<!ATTLIST PluginService Name CDATA #REQUIRED >
<!ATTLIST PluginService Description CDATA #IMPLIED >
<!ATTLIST PluginService Package CDATA #REQUIRED >
<!ATTLIST PluginService Class CDATA #REQUIRED >