Providers is a concept that was introduced with Symphony 2.3 which allows extensions to natively provide new Data Source types. This allowed for a more seamless experience for users and opened up a world of possibilities for extension developers. The upcoming Symphony 2.3.1 release brings Providers to Events as well, allowing developers to provide new event types selectable from the native Event editor.
For users, the benefits are more flexible and powerful DataSources and Events that can start to do things that previously required custom code. Extensions such as Cacheable DataSource, Union DataSource and Remote DataSource all bring powerful functionality to the fingertips of every Symphony ninja (and those in training). The addition of Events means that we can now create extensions that abstract common API's (such as Github) to read and write information without any knowledge of the underlying API.
In this article I'll explain the basics of creating a Provider type, using a basic extension that uses this new feature to interact with Github as a reference.
The extension.driver.php
needs to implement the iProvidable
interface, and include it's single method, providerOf(string $type)
to make your Provider classes visible to Symphony. The providerOf
function takes an optional parameter, a string $type
(or null
), and should return all the providers this extension has filtered by $type
as an array where the key's are the class names, and the values are human readable. At this stage, event
and data-sources
are the only two valid types, as implied by the iProvider
constants, DATASOURCE
and EVENT
.
In my example, I'm using another function, [registerProviders
], which is used privately to build an associative array of providable objects. It's up to you if you want to abstract this or just include it as part of providerOf
.
Your extension.driver.php
is responsible for loading your provider classes, giving you the freedom to place the classes where ever you think works best. I've chosen to create two folders, data-sources
and events
, which contain a single class each as this follows usual Symphony convention.
The Data Source and Event classes have their own interface classes, iDataSource
and iEvent
, which specify the minimum functions that your extension needs to implement to create a new provider.
There are a couple of basic functions that are common to the DataSource and Event classes which we will quickly go over. getName
returns a human readable name for your Provider. This will be displayed in the Sources drop down on the Editor pages in Symphony.
getSource
returns an identifier that allows the Event or Datasource editor to know that the submitted form needs to be handled by providers. Both Events and DataSources usually set their source to be the Section ID or in some cases, a string (used by Static XML, Navigation, Author and Dynamic XML datasources). Your provider should return something that is not numeric, I'm using the classname in this extension.
The DataSource and Event Editors work by saving a new file into the your Symphony /workspace
which contains the settings entered in the Editor, saved into a format specified by a template. You may want to look at the default templates for DataSources and Events to give you an idea of the default, and then compare it to Github API extension. Our providable objects will have their own templates and the getTemplate
function returns the file path to this class's template.
After an Event or DataSource is saved it appears in the relevant index table. The getSourceColumn(string $handle)
method is optional, but allows you to populate this column with whatever information you would like. The function is passed the $handle
of your Event/DataSource. If this function is not implemented, Symphony will simply use the value of getSource
function to populate this column.
There are four methods required to make the magic happen for the Symphony Editors, settings
, buildEditor
, validate
and prepare
.
This function allows your Datasource or Event to have any default settings. These will be applied when creating a new DataSource or Event and will be passed to the buildEditor
function.
The buildEditor
function returns nothing, but should populate $wrapper
with the desired markup (using XMLElement
) to create an editor for your providable object. This function should be responsible for:
- Providing the interface for users to configure your Datasource or Event type
- Handle any default settings, or remembering user input (these values as provided by Symphony as the
$settings
parameter). This is an associative array of all the values saved from the Editor. To keep your specific settings abstracted from the Symphony default settings, I'd recommend nesting the settings under a common key. - Error handling, any errors are passed through
$errors
in the same format as$settings
.
If the user is editing a Datasource/Event rather than creating a new one, $handle
will be populated with the object's handle so that you can create an instance if required, or do some alternative logic.
The validate
function allows you to ensure that users have filled in the settings correctly. This function should populate the $errors
variable if an error has occurred and then return false
. If there are no errors, return true
allows the Editor to continue. Remember that your buildEditor
function needs to handle displaying these errors to users!
Finally, this function passes the $settings
array, Symphony set $params
as an array and your $template
as a string. Here you prepare the $template
for saving by populating any placeholders with the required settings. In the Github API example, the template uses placeholders suitable for sprintf
.
Datasources and Events both do the bulk of their work in the execute
function. It is expected that this function return an XMLElement
of the results of the DataSource or Event which will be appended to the Page's XML so that it can be accessed in XSLT.
The DataSource is also passed the current parameter pool by reference which can be populated or accessed. This will contain all the parameters that have been added by DataSources that have been executed before this DataSource.
Page level parameters, for Events and DataSources, can be accessed using Frontend::instance()->Page()->Params()
. Events can set page params, but setting them directly via Frontend::instance()->Page()->_param
. It is likely that this variable will be changed in future, so keep an eye out of that.
Before an Event is executed, the load()
function is called which checks to see if the event should be executed (or __trigger
in the old days). The default is usually detecting if the form action matches this event's action or not, eg. isset($_POST['action']['event-handle'])
. This means that if an Event is attached to a page, the load()
function is always executed, so be mindful of what you put in here. If the Event's load()
function returns true, the Event's execute
function should be called to actually fire the event.
All event's have a magical documentation()
function. In the scenario of a default Symphony event, saving the editor will generate the markup needed on the frontend to populate entries of this section. This markup is generated by the fields in the Event's section using their getExampleFormMarkup
function (oh that's what that does I hear some of you say!) and save the HTML string inside this documentation()
function. When the event is viewed again in the editor, this markup is displayed to the user.
You can also take advantage of this in your Provider events by doing the same thing :) If you don't want to display markup at all, just return false
.
There we have it. Hopefully this short guide gives you an insight into how you can create your own extensions that add new Data source or Event types to Symphony. Happy coding!