Chapter 16. Developing plugins

Table of Contents

The plugin file
Plugin's custom configuration
Using a class
Pluggable applications
Plugin's assets and urls
Manifest.xml
Loading plugins programmaticaly

The plugin file

A plugin is made of one file named the same way. For example the Db plugin is in the file Db.php. Plugin's file must always start with an uppercase letter.

Plugins are loaded at the beginning of a request, just after the configuration. The content of the file is free or it can be a class.

To build more complex plugins you can instead of a file create a folder named after your plugin. Your php file goes into that folder and must be named Plugin.php.

When using folders, it is possible to add a sub folder named libraries which will automatically be added to php's include_path.

A folder must be used when creating pluggable applications.

Plugin's custom configuration

As said in the "Using plugins" section, plugins can have custom configuration. To retrieve this configuration a $config variable is automatically available. It contains the array used in the configuration.

Example 16.1. Retrieving plugin custom configuration

In the configuration file:

				
Atomik::set('plugins', array(
	'MyPlugin' => array(
           'name' => 'Peter'
	)
));
			

In the plugin file:

				
echo 'hello ' . $config['name'];
			

Using a class

For better application design it is advice to use a class to define your plugin. When loading a plugin, it will look for a class named like the plugin suffixed with Plugin.

If this class has a static start method, it will be called with the plugin's custom configuration as argument, when the plugin is loaded.

Example 16.2. Plugin class

The plugin class for a plugin named Db

				
class DbPlugin
{
	public static function start($config)
	{
		// $config['name'] == 'Peter'
	}
}
			

Note

It is a good thing to always provide a default configuration. This can be done by merging a default configuration array with the user's configuration.

The class can contain static methods that will be automatically registered as callback on events. These methods have to start by "on" followed by the event name without the double ":".

Example 16.3. Plugin class with event callback methods

				
class DbPlugin
{
	public static onAtomikDispatchStart()
	{
		// listener for Atomik::Dispatch::Start
	}
}
			

You can prevent automatic callback registration by returning false in the start method.

Pluggable applications

Pluggable applications are really simple to create. Create a normal plugin using a folder. Create your Plugin.php file. Call Atomik::registerPluggableApplication() when the plugin starts using the plugin name as first parameter (and eventually the pattern to trigger the application as the second). Create standards Atomik folders inside your plugin folder: actions, views, helpers and layouts and code your application normally.

Figure 16.1. A pluggable application directory structure

A pluggable application directory structure

Example 16.4. Example of a Plugin.php file registering a pluggable application

				
class PluggAppPlugin
{
	public static $config = array(
		'route' => '/pluggapp/*'
	);
	
	public static start($config)
	{
		self::$config = array_merge(self::$config, $config);
		Atomik::registerPluggableApplication('PluggAp', $config['route']);
	}
}
			

A pluggable application can also have a file named Application.php at the root of the plugin folder. This file act the same way as the bootstrap.php file. It will be called before the pluggable application is dispatched.

If Atomik detects the Application.php file, a Plugin.php file is not necessary and the pluggable application will automatically be registered.

A pluggable application behaves as a normal Atomik application and all features are available. The configuration will be reseted before the dispatch occurs. These applications can provide their own config in their Application.php file like their own routes, default action... The pre_dispatch.php and post_dispatch.php files can also be used.

Note that every url will be relative to the pluggable application root. That is to say you do not have to care of the route used to trigger your application. For this to work properly, read carefully the next section.

Atomik::registerPluggableApplication() as more options which are described in the API reference.

Plugin's assets and urls

When using the default .htaccess file, plugins can have an assets folder which is accessible from the Web. Of course, to use this folder, the plugin must come as a folder.

You can use Atomik::asset() like with a normal application. However in the case of plugins, asset's filename will be prepended with a template defined in atomik/plugin_assets_tpl. The default is app/plugins/%s/assets. The %s sign will be replaced with the plugin name.

Example 16.5. Using Atomik::asset()

				
echo Atomik::asset('css/styles.css');
echo Atomik::pluginAsset('MyPlugin', 'css/styles.css');
// will output app/plugins/MyPlugin/assets/css/styles.css

Atomik::set('atomik/plugin_assets_tpl', 'plugins/%s/assets');
echo Atomik::asset('css/styles.css');
echo Atomik::pluginAsset('MyPlugin', 'css/styles.css');
// will output plugins/MyPlugin/assets/css/styles.css
			

Note

It is not adviced to change the plugin's assets folder name as some plugins may not work with your installation.

Manifest.xml

Once you created your plugin, you might want to share it. The Atomik's website feature a plugin repository where anyone can submit their creations. To ease plugins distribution, you can bundle with your plugin a Manifest.xml file. It contains information about your plugin like name, description, author...

The file is very simple. You can get the XMLSchema at http://www.atomikframework.com/docs/manifest/manifest.xsd. The file's xml namespace is http://www.atomikframework.com/manifest. Below are all available tags:


<manifest xmlns="http://www.atomikframework.com/manifest">
	<author>
		<name></name>
		<email></email>
		<website></website>
	</author>
	<name><!-- plugin name without spaces or special characters (eg. MyPlugin) --></name>
	<displayName><!-- plugin name that will be displayed (eg. My Plugin) --></displayName>
	<version><!-- version (same format as php version number) --></version>
	<category><!-- the category name --></category>
	<minAtomikVersion><!-- the minimum Atomik version that is needed --></minAtomikVersion>
	<description><!-- plugin's short description (in list pages) --></description>
	<longDescription><!-- plugin's long description --></longDescription>
	<link><!-- link to the plugin website --></link>
	<directory><!-- directory inside the archive where the plugin's source code is located --></directory>
	<license><!-- license name --></license>
	<dependencies>
		<!-- list of dependencies (these plugin should also be registered in the atomik plugins repository -->
		<dependency name="pluginName" />
	</dependencies>
</manifest>
		

Note

The name and description tags are mandatory.

The directory tag is special and used by the distribution builder. When you're creating a package for your plugin, you could put the source files into a specific folder. For the distribution builder to work, it's needed to know where the sources are. This is the purpose of the directory tag. It must be relative to the root of your archive and specify which folder contains the files to be extracted to the plugins directory. Leave it blank for the root, which is the default value.

You can create a plugin file and the associated manifest online at http://www.atomikframework.com/plugins/create. To submit your plugin, browse to http://www.atomikframework.com/plugins/submit

Loading plugins programmaticaly

It is of course possible to load plugins at runtime. Atomik provides a bunch of loading methods so it's simpler for plugins to load dependency plugins or to create custom plugins.

The most common method is Atomik::loadPlugin() which will load a plugin and use the user plugin's configuration (from the plugins key) if one is available.

If a plugin is not available, loading it will throw an exception. To prevent that you can use Atomik::loadPluginIfAvailable().

Example 16.6. Loading a plugin

				
Atomik::loadPlugin('Db');
			

You can also load plugins by specifying custom configuration. This is done using Atomik::loadCustomPlugin(). As it's name imply, this method can also be used to load custom plugins, which can be named differently, follow other development guidelines...

Example 16.7. Loading a plugin at runtime with some configuration

				
Atomik::loadCustomPlugin('Db', array('dbname' => 'test'));
			

Example 16.8. More advance use of Atomik::loadCustomPlugin()

				
// load plugins from a custom directory
Atomik::loadCustomPlugin('MyPlugin', array(), array('dirs' => '/custom/plugins/directory'));

// using a custom plugin class name (in this case the class name will be MyPluginCustomPlugin)
Atomik::loadCustomPlugin('MyPlugin', array(), array('classNameTemplate' => '%CustomPlugin'));

// do not call the start() method when loading plugins
Atomik::loadCustomPlugin('MyPlugin', array(), array('callStart' => false));
			

Atomik::loadCustomPluginIfAvailable() is also available.

Note

Be aware that some plugins may need to listen to some specific events. If you register your plugin too late, the event may have already occured, making the plugin malfunction.

You can check if a plugin is already loaded using Atomik::isPluginLoaded() or if it's available using Atomik::isPluginAvailable().

Example 16.9. Checking if a plugin is already loaded

				
if (Atomik::isPluginLoaded('Db')) {
	// ...
}
			

Finally, you can retreive all loaded plugins using Atomik::getLoadedPlugins().