Symphony is great. Let's make it better.
This article is about the process of building your website's frontend, keeping templates DRY, relating Datasources, Events and other Resources to your Pages, code structure and much more. The following haven arisen, in time, from finding myself repeating the same things over and over again.
I assume you know what master.xsl is and you are using it. If you don't know, check the default Symphony workspace.
Client says: "I have some events comming up and I want to display the next one on Home and Contact pages."
Let's take an Events
section containing three fields
Title (Textbox field)
- title of the eventBody (Textbox field)
- body textDate (Date field)
- date when it will take place
two Pages:
Home
Contact
and a Datasource that grabs next event
Next event
Workflow Classic to display data in frontend:
- Attach required
Datasources
&Events
toPage
- Write XSL code in
page.xsl
- Write CSS & JS in some files
Now let's display our event on Home
Page:
- Attach
Next event
Datasource toHome
Page - Write XSL code in
home.xsl
- Write CSS & JS in some files
Now, the same thing for Contact
Page:
- Attach
Next event
Datasource toContact
Page - Copy + paste the required code from
home.xsl
tocontact.xsl
- Copy + paste the CSS and JS as well
Horray, client is happy. But ...
We are repeating ourselves:
- Attach
Next event
Datasource toyyy
Page (DRY problem #1) - Copy + paste the required code from
xxx.xsl
toyyy.xsl
(DRY problem #2) - Copy + paste the CSS and JS (DRY problem #3)
Duplicating XSL code is not a good thing. To keep things DRY, some refactoring will take place. Normally, one would create a new XSL file in /workspace/utilities
to hold this code. Instead, I'll create a Widget
for this purpose. Utilities
will hold only the utilities
like: form-controls.xsl
, date-format.xsl
& all.
A Widget
is more than a plain XSL utility. We'll see later. For the moment, I create an XSL file in /workspace/widgets/next-event/xsl/next-event.xsl
and put the necessary XSL code there.
<xsl:template name="w_next-event">
<!-- Code to display the widget -->
</xsl:template>
NB: masterl.xsl
should a Widget
, not a Utility
.
Workflow Improved #1 to display data in frontend:
- Attach required
Datasources
&Events
toPage
- Create required
Widgets
if not exist, import inPage
& call templates provided byWidgets
- Write CSS & JS in some files
Now let's display our event on Home
Page:
- Attach
Next event
Datasource toHome
Page - Create
next-event.xsl
, import inhome.xsl
& callw_next-event.xsl
template - Write CSS & JS in some files
Now, the same thing for Contact
Page:
- Attach
Next event
Datasource toContact
Page - Import
next-event.xsl
incontact.xsl
& callw_next-event.xsl
template - Copy + paste the CSS and JS
Plain clear. I'm sure you're doing it this way, right? :)
This fixes the duplication of XSL code. But ...
Still there are 2 things to fix:
- Attach required
Datasources
&Events
toPage
(DRY problem #1) - Create required
Widgets
if not exist, import inPage
& call templates fromWidgets
- Write CSS & JS in some files (DRY problem #3)
Add this widget to other 20 Pages of the site. Soon, you'll find that this step is a PITA:
- Attach
Next event
Datasource toXXX
Page
What if our Next event
Widget requires 4 Datasources? And it has a form and requires 2 Events as well?
On each page you will have to manually add 4 Datasources and 2 Events. Repeating yourself? What if the Next event
Widget would have the capabilities of a Page? Attaching Datasources & Events to it ...
Widget relates to 4 Datasources and 2 Events:
Next event -> Datasource #1
-> Datasource #2
-> Datasource #3
-> Datasource #4
-> Event #1
-> Event #2
Page includes Widget:
Home -> Next event
Contact -> Next event
This way, a developer has to link a Page
to a Widget
and that's all. Want it? Read on & grab it.
Workflow Improved #2 to display data in frontend:
- Create required
Widgets
:
- Attach
Datasources
&Events
toWidget
- Write XSL code in
Widget
file
- Import
Widgets
inPage
& call templates fromWidgets
- Write CSS & JS in some files
Now let's display our event on Home
Page:
- Create
Next event
widget:- Attach
Next event
Datasource to Widget - Write XSL code in
next-event.xsl
- Attach
- Import
next-event.xsl
inhome.xsl
& callw_next-event.xsl
template - Write CSS & JS in some files
Now let's display our event on Contact
Page:
Next event
widget already exists (it includes the Datasources & Events as well)- Import
next-event.xsl
incontact.xsl
& callw_next-event.xsl
template - Copy + paste the CSS and JS
Neat, right? If the project has more than 10 pages, this workflow is a time-saver. But ...
There is still one duplication problem:
- Create required
Widgets
:
- Attach
Datasources
&Events
toWidget
- Write XSL code in
Widget
file
- Import
Widgets
inPage
& call templates fromWidgets
- Write CSS & JS in some files (DRY problem #3)
This code duplication affects assets like CSS
& JS
. In my projects I found it very useful to have a CSS file and a JS file for each Page.
Looking above, it is logical to have a CSS file and a JS file for each Widget. This way, a Widget will include the Datasources & Events and some XSL, CSS and JS files.
I find it VERY handy to group all these files together. In Symphony's default workspace the CSS and JS for all pages and resources are kept together (CSS in /workspace/css
, JS in/workspace/js
). I decided to group them related to functionality and came up with this structure:
/workspace
/css
library files like bootstrap.css
...
/datasources
next_event.php
...
/events
...
/js
library files like bootstrap.js
...
/pages
/home
/config
home.xml
/css
home.css
/js
home.js
/xsl
home.xsl
...
/utilities
date-format.xsl
form-controls.xsl
...
/widgets
/master
/config
master.xml
/css
master.css
/js
master.js
/xsl
master.xsl
/next-event
/config
next-event.xml
/css
next-event.css
/js
next-event.js
/xsl
next-event.xsl
...
Workflow final for meeting the requirement from our client requires this:
- Create a
Widget
- Link the
Widget
toDatasources
&Events
- Write XSL, CSS & JS in their dedicated files. Include the CSS & JS within XSL
- Link the
- Link the
Page
to theWidget
(similar to linkingDatasources
&Events
) - Include
widget.xsl
inpage.xsl
- Call
widget
template inpage.xsl
Have I told you that a Widget can be linked to another Widget? Yes, they can be linked. So, the final solution to our problem would be:
- Create
Master
widget - Create
Next event
widget Home
&Contact
pages already includeMaster
- Link
Master
toNext event
Ta-da !
P: Home -----v
W: Master -> W: Next Event -> DS: Next event
P: Contact -----^
I'm successfully using this workflow so far and developing time for a given feature reduced drastically. My Widgets
library keeps growing from project to project. I hope yours will as well.
Food for thought: How hard would it be to port functionality from one site to another using this structure?
If you're interested, make sure you follow the Resources repository on GitHub. If you can't find it, it means I didn't create it, yet, but will do it soon enough. This repository is the base implementation to make the above idea possible.
#8 Full ensemble available
There's an ensemble available containing some examples of the workflow. See the Readme for details.