Symphony 很棒,讓我們來讓它更好。
這文章與建立網站的前端相關,維持模板(templates)能夠重複利用,關聯資料來源(Datasources)、事件(Events)以及其他資源到你的頁面(Pages),程式碼的架構,還有更多。這文件的起心動念,是因為發現自己不停的重複再重複相同流程,才有了改良的意圖。
我假設你已經知道 Symphony CMS 的 master.xsl 是什麼,同時也已經用過它。如果你還不明瞭,請先參考 Symphony 的預設 workspace.
客戶(或是你自己)說:「我有一些活動即將開始,我想讓這些資訊出現在首頁與聯繫頁面。」
我們已經有一個「活動」的資料表(section)記錄了三個欄位:
Title (Textbox field)
- 活動的標題Body (Textbox field)
- 內文Date (Date field)
- 開始的日期時間
兩個頁面:
Home
Contact
還有一個資料來源,擷取了下一個活動
Next event
將資料呈現於前端的傳統工作流程:
- 加附需要的
Datasources
與Events
到Page
上 - 在
page.xsl
模板中寫 XSL 代碼 - 將 CSS 與 JS 寫進一些檔案中
現在我們要在首頁呈現接下來的活動資訊:
- 加附
Next event
Datasource 到Home
頁面 - 寫 XSL code 到
home.xsl
- 將 CSS 與 JS 寫進一些檔案中
對 Contact
頁面要重複相同的事:
- 加附
Next event
Datasource 到Contact
頁面 - 從
home.xsl
拷貝、貼上一些 XSL 代碼到contact.xsl
- 同樣拷貝 CSS 與 JS(這些檔案不是應該可以沿用?)
客戶高興了,但是...
我們做了很多重複的工:
- 加附
Next event
Datasource 到yyy
頁面 (重複工作問題 #1) - 從
xxx.xsl
重複拷貝、貼上到yyy.xsl
(重複工作問題 #2) - 拷貝與貼上 CSS 和 JS (重複工作問題 #3)
重複的 XSL 代碼不是件好事。為了避免重工,重新架構是必要的。一般來說,可以在 /workspace/utilities
目錄下建立一個新的 XSL 檔案擺放這些代碼;但為了達成這目的,我會建立 Widget
,讓 Utilities
真的只控管「工具碼」,像是 form-controls.xsl
、date-format.xsl
這類代碼。
一個 Widget
不只是一個單純的 XSL 工具碼,稍後會解釋這點。現在,我會建立一個 XSL 檔案,擺在 /workspace/widgets/next-event/xsl/next-event.xsl
,然後只放必要的 XSL 代碼進去。
<xsl:template name="w_next-event">
<!-- Code to display the widget -->
</xsl:template>
注意: 根據我的理論,masterl.xsl
也應該是個 Widget
,而不是一個 Utility
。
工作流程改善 #1 在前端呈現內容:
- 加附需要的
Datasources
與Events
到Page
- 如果還沒有需要的
Widgets
,就新建它;若是已經存在,匯入到Page
然後呼叫那些由Widgets
提供的 templates(指 XSL template) - 將 CSS 與 JS 寫進一些檔案中
現在就來在 Home
頁面呈現我們的活動:
- 加附
Next event
資料來源到Home
頁面 - 建立
next-event.xsl
,匯入到home.xsl
接著呼叫w_next-event.xsl
template - 將 CSS 與 JS 寫進一些檔案中
Now, the same thing for Contact
Page:
- 加附
Next event
資料來源到Contact
頁面 - 將
next-event.xsl
匯入到contact.xsl
並呼叫w_next-event.xsl
template - 拷貝與貼上 CSS 和 JS
簡單明瞭。我想你正在這樣做,對吧?:)
這改善了 XSL 代碼重複的問題,但是...
還有兩個問題需要修正:
- 加附需要的
Datasources
與Events
到Page
(重工問題 #1) - 若沒有需要的
Widgets
,建立它;匯入到Page
並從Widgets
呼叫 templates - 將 CSS 與 JS 寫進一些檔案中 (重工問題 #3)
當需要把這個 widget 加入到網站內20個頁面時,就會發現這步驟很惱人:
- 加附
Next event
資料來源到XXX
頁面
萬一我們的 Next event
Widget 需要四個資料來源?然後還有一個表單、兩個事件也要處理?
在每一頁你都需要手動加入四個資料來源和兩個事件,一直重複這些工作?能不能讓 Next event
Widget 也有類似頁面的能力,就是可以加附資料來源和事件上去...
Widget 關聯到四個資料來源和兩個事件:
Next event -> Datasource #1
-> Datasource #2
-> Datasource #3
-> Datasource #4
-> Event #1
-> Event #2
頁面包含 Widget:
Home -> Next event
Contact -> Next event
如此一來,開發者只需要串聯一個頁面到一個 Widget
,收工。想要嗎?繼續讀下去就有了。
工作流程改善 #2 在前端顯示資料:
- 建立需要的
Widgets
:
- 加附
Datasources
與Events
到Widget
- 寫 XSL 代碼到
Widget
檔案
- 匯入
Widgets
到Page
並從裡面呼叫需要的 templates - 將 CSS 與 JS 寫進一些檔案中
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.