ocPortal Tutorial: The ocPortal programming framework
ocPortal has a well documented API (code)
It should be noted that ocPortal can be heavily customised without any programming, via editing the templates, but this will mostly only adjust layout and appearance, rather than adding-to or modifying ocPortal behaviour.
It is also important to note, that programming tasks are inherently technical, and requires some combination of some of these elements:
- a technical mind
ocPortal has a well documented API
Table of contents
Open sourceocPortal is Free Software and Open Source, meaning it's completely open and customisable.
The ocPortal APIEvery function in ocPortal is documented using a system based on phpdoc (itself based on 'javadoc'). One purpose in this documentation is that it makes it easy for a programmer to program for ocPortal: they have a few hundred fully documented ocPortal functions available to them.
With phpdoc and the function header-line itself, every function has the following:
- A description
- A list of all parameters
- The code-name of the parameter
- The type of the parameter (including whether false [~type] or NULL [?type] values are accepted)
- A description of the parameter
- Whether the parameter is optional
- The return type (if any), and a description of it
Extending ocPortalocPortal is not just a lump of code like most software: a lot of effort has gone into structuring the system so that code may be cleanly hooked in, via various methods.
These methods include:
- Overriding of existing source files with modified versions. Every directory that holds effective source code (as opposed to the shell files such as index.php or dload.php that just provide entry points into ocPortal) support a system of overriding: in other words, every ocPortal source code file can be replaced with a customised version, cleanly, without damaging the existing code and without the changes getting buried. This is done via elevation of a file to a _custom suffixed directory of where the file originally was
- An ocPortal editor (the code editor) is provided to provide a simple (password protected) editor for your site, and does this automatically
- New Module s can be added just by writing a file and placing it in the modules_custom directory for the zone that it is to run in. In addition, there is support for a simple form of module, called a Mini-module that can be added in a similar way, but is much easier to write for amateur programmers
- New Block s can be added just by writing a file and placing it in the sources_custom/blocks directory. In addition, there is support for a simple form of module, called a 'mini-block' that can be added in a similar way, but is much easier to write for amateur programmers
- New API source code files can be added just by writing a file and placing it into the sources_custom directory
- 'Hooks' to add features into a hooked area can be written. For example, a 'search hook' can be written by writing a file and placing it into the sources_custom/hooks/modules/search directory
An example of a new module
ocPortal templates for the tester mod
ocPortal language files for the tester mod
The process of writing the module went along this basic route:
- The functionality of the module was decided upon, and tests designed that would allow us to test all this functionality worked once the module was finished (we usually define tests first, write a module in one go, and then carry out all the tests: it usually is the most efficient and robust way for us to write the code)
- The database schema was designed for the module, by consideration and then simply listing of the tables and fields that would be needed to adequately (and consistently with our standards and the guidance of our expertise)
- The shell for the main module was written, based on that which all other modules (other than minimodules and abstracted AED modules) uses
- It was decided what screens that module would use, and these were all assigned code-names. Functions were created for these code-names, and the run function was filled in to call them up according to the 'type' parameter (as featured in all other modules)
- Install and uninstall functions were written for the module, according to the database schema
- Add, edit, and delete backend functions were written for the data of the module
- Add, edit, and delete screens were written for the data of the module (including definition of associated language strings for the standard ocPortal field inputting interface [wherever possible, referencing existing ones, to reduce the burden for anyone wishing to translating the module once we release it publicly as an ocPortal addon])
- The screens for the main interface were written
- The module was tested, and then deployed
ocPortal module for the tester mod
Some of the API functions used in the module include:
OverridesThere are 3 different kinds of PHP override in ocPortal:
- Extending a module
- Replacing/supplementing a file
- Replacing/supplementing a file, with support for progmattic alteration of the original code
It's important to note that as well as overrides you can place entirely new files in the *_custom directories, and ocPortal will be able to reference them as if they were original files.
All these techniques are handled inside the ocPortal sources/global.php file. If you are a good programmer but still can't work out how to do all this stuff (it's easy once you know how, but a bit unorthodox compared to normal techniques), look at the code of this file. As sources/global.php is the file that does the magic it's the only file that you can't override; it is therefore kept minimal, hence why we have a sources/global2.php which picks up where sources/global.php leaves off.
Extending a moduleThis form of overriding works via class inheritance. All you need to do is to make a modules_custom directory version of an original modules directory file, with two differences:
- Instead of just naming the module class Module_<modulename>, rename it and inherit using Mx_<modulename> extends Module_<modulename>
- As this works via standard class inheritance you are at liberty to, and should, only re-define methods in your override when those methods are actually different from the original ones. i.e. start with a shell of a class and only re-define methods that you are actually wanting to change
Replacing/supplementing a fileIf you override a file to the sources_custom directory then that file will essentially be overlaid on top of its equivalent in the sources directory. (You can use this technique in other *_custom directories too, such as modules_custom directories – although in this case it is less useful, as there is less granularity due to a module only containing a single class)
You can redefine any existing function or class, and you can define new functions or classes. ocPortal does some magic so that you can reference the old versions of the functions or classes by prepending non_overrided__ to their names (e.g. example_function would become non_overrided__example_function). This is very useful if you can write your overridden function without having to completely replace the original function. For example, if we just want to add some logging to example_function…
some_logging_function('call to example_function with '.$a.' and '.$b);
some_logging_function('leaving example_function returning '.$ret);
class example extends non_overrided__example
some_logging_function('call to example::mymethod with '.$a.' and '.$b);
some_logging_function('leaving example::mymethod returning '.$ret);
One word of caution – if you are not supplementing a code files 'init' function, then you will want to strip out the init function from your override, otherwise both it and the original will be called in sequence. This is unavoidable, because the modified file is loaded first and thus cannot call the original init function itself – and thus responsibility for that stays with the ocPortal code. There are two exceptions:
- If your override contains every class or function the original file has (i.e. you overrode the whole file by copy&pasting) then the original init function will not be called as ocPortal assumes you copy&pasted all that code into your own init function.
- If you want a partial override but don't want the original init function to run, you need to use progmattic alteration to mask the original init function. This is explained in the last paragraph of the next section.
Progmattic alterationSometimes you want to override something in the middle of a function and thus there is no neat way to do it without copy&pasting the whole function.
In theory, good software architecture (modularity etc) is meant to prevent this situation happening, but in practice:
- its completely impossible for an original programmer to predict what changes someone might want to make to their code
- programming languages have no inbuilt features to work around problems stemming from this lack of foresight (even the most heralded OOP techniques cannot do it)
- Alter the original ocPortal code. This is a very bad idea because you then have a very hard time identifying your changes, and performing even patch upgrades
- Override whole functions. This is a bad idea for non-trivial functions because it makes feature/major upgrades much more problematic
- Use a mechanism that goes beyond what programming languages can normally do
We took approach '3', and thus have written a special feature into ocPortal for it. Its admittedly a bit messy but in practical terms it works almost flawlessly.
In ocPortal it works as thus:
- First you create a sources_custom file
- Next you define an init function of this file. If you were overriding sources/example.php you would define a init__example function. If you were overriding sources/forum/example.php you would define a init__forum__example function (i.e. any slashes get changed to '__' in the function name)
- The init function should take a single parameter, and return something based upon that parameter. The value of this parameter will be the string value of the code you're overriding, after any function/class renaming has happened (see 'Replacing/supplementing a file' above). i.e. your function is taking a huge lump of PHP code as its parameter. In-between taking the parameter and returning it you can perform any changes you like. You can use any string functions like preg_replace or strpos; or use the handy ocPortal get_function_hash / insert_code_before__by_linenum / insert_code_after__by_linenum / insert_code_before__by_command / insert_code_after__by_command / remove_code functions
There is one important rule when it comes to progmattic alteration: you are not allowed to call non_overridded__init__<whatever> from your init__<whatever> function. You cannot do this because the PHP code containing that function has not been evaluated at that point and thus the function is not yet defined. If you try and do it then ocPortal will disable progmattic alteration and hence revert to the more basic 'Replacing/supplementing a file' technique. ocPortal will automatically call non_overridded__init__<whatever> as soon as it becomes available so you do not need to copy&paste its contents to your own function. If you do not want non_overridded__init__<whatever> to be automatically called then you need to rename it in your own init function so that ocPortal cannot find it.
Exporting an addon (1)
- Language packs (for any new language translation)
- Themes (for any new theme)
- Code modifications (defined by manual selection of files)
ocPortal addons are TAR files which include a special definition file. They may be constructed manually if an author wishes to have more control over the construction process.
Exporting an addon (2)
Importing an addon (2)
Importing an addon (1)
Since version 3 of ocPortal, overridden PHP files may override on a per-function/per-class level. In other words, if you overrode a PHP file then you could make your sources_custom file such that the only functions/classes it contains are the ones that you changed.
The Code Editor
A password is obviously needed to use the code editor
Choosing a code file to edit
Using the code editor
ocPortal provides a very simple code editor for editing of existing ocPortal code files, or creation of new files. The code editor has inbuilt, automated, support for the ocPortal file override system: editing an original ocPortal file will save the edited version in the equivalent '_custom' suffixed directory where possible.
The code editor is very useful for making adhoc changes to a live-site, but is not intended as a full development environment.
PHP programming help
PHP has an excellent reference manual
The ocPortal API guide does actually include a PHP reference that defines a subset of PHP that we allow ourselves to use in ocPortal. The subset is specially limited so as to avoid PHP version conflicts, and the need for PHP extensions that may not be installed.
Other advantages to our frameworkIf you still are not convinced that ocPortal is the right choice for you, consider some of these:
- There are many frameworks for creating web applications available (such as Typo3 or Ruby-On-Rails), but few true frameworks like ocPortal are also 'out of the box' systems
- In addition to the above, few pure frameworks provide the dimensions of functionality that ocPortal can provide
- ocPortal's framework has excellent security. For example,
- the database abstraction system allows relational databases to be accessed without concern of SQL-injection
- The template system is written to make XSS injection virtually impossible (where the vast majority of programmers write code that is full of XSS vulnerabilities, without even knowing what they are)
- ocPortal's framework is of professional quality, managed by a single company that keeps every aspect of it to high standards, and compatible with each other. If you opt for frameworks which are incomplete, and end up using addon libraries to achieve additional functionality, you will soon realise, both immediately and after-time, that the lack of central control results in:
- major compatibility problems
- messy feature overlap
- inconsistent philosophies for code
- inconsistent philosophies for documentation
- a large number of agents to contact for different kinds of problem
- no central authority for you to agree licensing with, should you need to do so (and this is not unlikely, as many projects flower to unexpected ends)
- orphaned projects that die