DocEngine is designed to implement custom modules without much hassle. Do you want to have a user system where people can login to do stuff? Just implement a module. Do you need to have fancy graphs rendered or want LaTEX to be interpreted and rendered? Its just a small module away.
The source of your module muse be saved in the folder
lib/php/DocEngine/Modules/. Thats the folder that
is being scanned by DocEngine and all of the PHP files inside it are loaded as modules.
Your module code needs to be a class that offers only static methods and properties. It will never be instanciated and only called statically.
Your class is required to have the static properties
$conf defined - everything else is optional.
Right now, any additional stuff for modules is stored inside the theme folder. If you need sub-templates,
like the inlineDemo and quickNavigation modules do, those go to
The same applies for JS, CSS and images. This makes installing / removing of modules a bit af a hassle, but
since the output of modules might be different, based on the current theme, I haven't figured out a better
way of storing additional module files, yet. If you have an idea, please contact me.
Understanding a example module
Have a look at one of the most basic modules for DocEngine: the already bundled module that adds googles code prettifier to the documentation to make your code examples (including this one) look beautiful.
We will explain it in detail below the code block:
The class is being loaded by docEngine in docEngines'
init() method. DocEngine looks for the
$hooks property and
registers each given hook to a static method inside the class. In our example class here,
prettifyAll method is hooked against the
contentParsed hook is called after the current pages' markdown file has been loaded and interpreted,
the HTML result is passed over to all methods that have been registered to the
contentParsed hook - including
prettifyAll method of our class is being called and handed over the HTML code that is about to be passed
to the current themes template and then to the browser. We want to inject googles prettify library, so we need
to do two things:
- Adding the css class
prettyprint class to all
pre tags is done easily:
$result = str_replace('<pre>', '<pre class="prettyprint' . $conf . '">', $source, $count);
We even do something more. You can command the prettyprint library to display line-numbers or not
by adding the additional css-class
linenumbers to the
pre tag as well.
So by checking the modules config object if linenumbers are wanted, we can decide here to include
linenumbers class here as well, or not. More about module configs below.
After the result has been modified, we are checking the
$count property, if any replacements have
library is being loaded into the page via
The modified result is returned at the end of the method so docEngine can finish rendering the page and display it to the user. It wasn't that complicated, wasn't it?
The hooks system works very similar to the event system in other programming languages. Hooks are being called
at certain points in the program flow and modules can register methods against hooks to be called from elsewhere.
Modules can even call hooks themselves by calling
$docEngine->callHook('hookname', $modificator) where
a property that gets passed to ALL methods registered to this hook. If all hooks have been called, the final modificator
property is returned from the
callHook() method. This approach enables several modules to modify the same content before
its getting rendered.
This is the current list of system hooks, being called in the page generation flow (in this order):
First hook to be called right after the loading of all module classes. Page generation might be canceled after this point, since the routing hasn't been done.
Called after docEngine has analyzed if there is any possible content to be displayed for the requested URL. This means language detections and/or page redirects have already been made. After this point, docEngine will build the local and global config objects and will define the module config objects if any presets have been made in the global config file. Gets the generated page object passed in.
Called before the markdown content area is being parsed and transformed into HTML. Gets the markdown code passed in.
Called after the markdown content area has been parsed to HTML. Gets the final HTML result passed in.
Called before the parsed content is passed to the twig theme file and the final page being rendered.
- afterRender Called after the final page has been rendered. Gets the final HTML result passed in, right before its handed to the browser.
See module exclusive page routing
- renderHeader Called from within the default theme during the final page rendering. Gets a string passed in. Modify the string if you want to add something to the theme header.
- renderFooter Called from within the default theme during the final page rendering. Gets a string passed in. Modify the string if you want to add something to the theme footer.
You most certainly already noticed the
$conf property of the module. This is where you can set some
options to modify the modules behaviour. You can pre-define some default values from inside the module
code (like you can see above), but the properties here will be overwritten if other values have been
defined either in the global config, or local config.
If you want to modify the default skin to be used by the prettifier, you need to set the property
modules.PrettifySources.skin inside the global config file
Each module can get a configuration assigned if you define a object with the modules' name inside the
modules object inside the global config.
The same behaviour can be achieved if you define a
modules object inside the markdown files' config
block and create a sub-object with the modules name.
This is useful if you want to disable some modules for certain pages completely (setting active to false), or want to use different skins, or whatever.
Module exclusive page routing
If you need to output some module-data and nothing else, you can utilize the following route:
/module route is reserved for direct-to-module calls inside docEngine, so calling this route will
trigger a hook and no theme template is being rendered around any data you echo to the browser.
In the example above, docEngine will call the hook
module:myCoolHook with the remaining URL parameters
passed into the hook as an array. In our case
["what", "ever", "you", "want"].
If you register a method of your module to it, everything that is being returned from the method
is ignored, so you have to echo your data directly.
After the hook is processed, docEngine stops the execution flow and will output nothing else. This makes the construct perfect for performing AJAX calls, or render completely independend pages out of a module.
The inlineDemo module uses this construction to save data for editable demos.