Skip to content

Instantly share code, notes, and snippets.

@vlad-ghita
Last active December 1, 2018 16:48
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save vlad-ghita/4006891 to your computer and use it in GitHub Desktop.
Save vlad-ghita/4006891 to your computer and use it in GitHub Desktop.
Symphony, meet Resources!

1 Intro

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.

2 It all starts with a requirement

Client says: "I have some events comming up and I want to display the next one on Home and Contact pages."

2.1 Get some Resources

Let's take an Events section containing three fields

  • Title (Textbox field) - title of the event
  • Body (Textbox field) - body text
  • Date (Date field) - date when it will take place

two Pages:

  • Home
  • Contact

and a Datasource that grabs next event

  • Next event

3 Classic workflow

Workflow Classic to display data in frontend:

  1. Attach required Datasources & Events to Page
  2. Write XSL code in page.xsl
  3. Write CSS & JS in some files

Now let's display our event on Home Page:

  1. Attach Next event Datasource to Home Page
  2. Write XSL code in home.xsl
  3. Write CSS & JS in some files

Now, the same thing for Contact Page:

  1. Attach Next event Datasource to Contact Page
  2. Copy + paste the required code from home.xsl to contact.xsl
  3. Copy + paste the CSS and JS as well

Horray, client is happy. But ...

We are repeating ourselves:

  1. Attach Next event Datasource to yyy Page (DRY problem #1)
  2. Copy + paste the required code from xxx.xsl to yyy.xsl (DRY problem #2)
  3. Copy + paste the CSS and JS (DRY problem #3)

4 Improving workflow (DRY problem #2)

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:

  1. Attach required Datasources & Events to Page
  2. Create required Widgets if not exist, import in Page & call templates provided by Widgets
  3. Write CSS & JS in some files

Now let's display our event on Home Page:

  1. Attach Next event Datasource to Home Page
  2. Create next-event.xsl, import in home.xsl & call w_next-event.xsl template
  3. Write CSS & JS in some files

Now, the same thing for Contact Page:

  1. Attach Next event Datasource to Contact Page
  2. Import next-event.xsl in contact.xsl & call w_next-event.xsl template
  3. 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:

  1. Attach required Datasources & Events to Page (DRY problem #1)
  2. Create required Widgets if not exist, import in Page & call templates from Widgets
  3. Write CSS & JS in some files (DRY problem #3)

5 Improving workflow (DRY problem #1)

Add this widget to other 20 Pages of the site. Soon, you'll find that this step is a PITA:

  1. Attach Next event Datasource to XXX 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:

  1. Create required Widgets:
  • Attach Datasources & Events to Widget
  • Write XSL code in Widget file
  1. Import Widgets in Page & call templates from Widgets
  2. Write CSS & JS in some files

Now let's display our event on Home Page:

  1. Create Next event widget:
    • Attach Next event Datasource to Widget
    • Write XSL code in next-event.xsl
  2. Import next-event.xsl in home.xsl & call w_next-event.xsl template
  3. Write CSS & JS in some files

Now let's display our event on Contact Page:

  1. Next event widget already exists (it includes the Datasources & Events as well)
  2. Import next-event.xsl in contact.xsl & call w_next-event.xsl template
  3. 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:

  1. Create required Widgets:
  • Attach Datasources & Events to Widget
  • Write XSL code in Widget file
  1. Import Widgets in Page & call templates from Widgets
  2. Write CSS & JS in some files (DRY problem #3)

6 Improving workflow (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:

  1. Create a Widget
    • Link the Widget to Datasources & Events
    • Write XSL, CSS & JS in their dedicated files. Include the CSS & JS within XSL
  2. Link the Page to the Widget (similar to linking Datasources & Events)
  3. Include widget.xsl in page.xsl
  4. Call widget template in page.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:

  1. Create Master widget
  2. Create Next event widget
  3. Home & Contact pages already include Master
  4. Link Master to Next event

Ta-da !

P: Home    -----v 
             W: Master -> W: Next Event -> DS: Next event
P: Contact -----^

7 Final words

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment