Modules
Note: this page is derived from the concept of A Database less approach to Symphony's structre, and summarizes it to a concrete functional design. Therefore it is already written in how Symphony 'should' work.
Symphony stores the structure of Sections, Fields, Datasources, Events and example markup in modules. These are self-contained packages which allow for some interchangeable functionality across multiple Symphony installations. Therefore a webdeveloper doesn't constantly has te be re-inventing the wheel when creating a new site. Each time a new site is made the same modules can be used over and over again; news, image gallery, jobs, links, faq items, etc. Including their corresponding fields, datasources, events, attachment to pages, etc.
For example, a newsmodule consists of:
- A news-section, with fields like 'title', 'date' and 'content'.
- Some datasources for showing the index, archive and a isolated news item.
- Some XSLT-utilities, transforming the datasources' output to HTML displaying the news.
- The pages, displaying the news whilst using the XSLT-utilities (included as example).
- Some CSS and JavaScript-files (inclded as example).
A complete module as described above can be picked up and inserted in another Symphony site without all too much configuration/customization. Modules are generic and can be shared between the community.
Only the storage of data is done in the database. This means only the following is stored in the database:
- Authors
- Cache
- Entries
- Entry data
- Sessions
The following is stored in XML-files in the workspace
-folder:
- Sections
- Pages configuration
- Datasources
- Events
More information on the workspace file structure
Since modules are site-independent, we can't work with ID's to tie it all together. Therefore, we provide each section, field and page with a unique hash. This hash is the timestamp + name when the section, field or page was created. This unique hash is stored in the XML file and get's never changed again.
In the database there are 3 lookup tables on how the sections, fields and pages are matched with ID's. The ID's are thus used purely internally by Symphony for making the correct relations.
The structure of the lookup table looks like this (in this case, for sections):
| ID_SECTION | HASH | FILE_HASH | XML_DATA |
|------------+----------------------------------+----------------------------------+-----------------|
| 1 | 97dcae5e3bd3c9fb78fa302c0a083947 | b747b6e5ffa3db6bff396b6759fddcd7 | (some xml ...) |
| 2 | bb2c28e57b6f2cd75723f67948e3c73c | 61c00b1e696c954ff681558938a44d1d | (some xml ...) |
- ID_SECTION: This is the ID used internally by Symphony to match the data stored to the correct section.
- FILE_HASH: This is a hash of the corresponding file stored in the database. This is to determine if the content of the XML-file has been changed outside of the UI. This could otherwise cause issues (think about typo's, duplicate unique hashes, or accidentally the removal of sections/fields). When the XML-files and the hash in the database don't match, the developer gets a notification about this, and goes to a difference-page to synchronize the sections/fields.
- XML_DATA: The XML content is also stored in the database, for when a mismatch is found, the stored XML could be used instead of the external file.
Our dear friend XML stores the structure of sections, fields and pages. Here an example of how these XML-files look like:
<section>
<name>News items</name>
<sortorder>1</sortorder>
<hidden>false</hidden>
<navigation_group>Content</navigation_group>
<unique_hash>bb2c28e57b6f2cd75723f67948e3c73c</unique_hash>
<fields>
<field>
<label element_name="name">Name</label>
<unique_hash>97dcae5e3bd3c9fb78fa302c0a083947</unique_hash>
<type>input</type>
<required>true</required>
<sortorder>1</sortorder>
<location>main</location>
<show_column>true</show_column>
<configuration>
<validator />
</configuration>
</field>
<field>
<label element_name="date">Date</label>
<unique_hash>61c00b1e696c954ff681558938a44d1d</unique_hash>
<type>date</type>
<required>true</required>
<sortorder>2</sortorder>
<location>side</location>
<show_column>true</show_column>
<configuration>
<pre_populate>true</pre_populate>
</configuration>
</field>
<field>
<label element_name="content">Content</label>
<unique_hash>b747b6e5ffa3db6bff396b6759fddcd7</unique_hash>
<type>textarea</type>
<required>true</required>
<sortorder>3</sortorder>
<location>main</location>
<show_column>false</show_column>
<configuration>
<formatter>CK_Editor</formatter>
<size>25</size>
</configuration>
</field>
</fields>
</section>
To provide a hook for extensions or other code to refer to a specific page, a page also has a unique hash.
<page>
<title handle="news">News</title>
<unique_hash>b747b6e5ffa3db6bff396b6759fddcd7</unique_hash>
<parent>3b42206b9fe82adaa1066f0756c27213</parent>
<path>media</path>
<params>page</params>
<datasources>
<datasource>news-archive</datasource>
</datasources>
<events />
<types>
<type>hidden</type>
</types>
<sortorder>1</sortorder>
</page>
When editing a section from Symphony's UI, the XML is saved. However, when editing the XML externally (or in a same scenario, using a module from another Symphony installation in your own), the system will show a message that the XML is modified, and send the administrator to a page showing the differences. On this page you could accept/synchronise the changes, or reject them.
Some fields store relations to other fields, like Select Box Link for example. This is relation is stored by refering to the unique hash of the related field in the XML. For example, a Selectbox Link Field looks like this:
<field>
<label element_name="category">Category</label>
<unique_hash>b747b6e5ffa3db6bff396b6759fddcd7</unique_hash>
<type>selectbox_link</type>
<required>true</required>
<sortorder>4</sortorder>
<location>sidebar</location>
<show_column>false</show_column>
<configuration>
<allow_multiple_selection>false</allow_multiple_selection>
<show_association>true</show_association>
<related_field_hash>61c00b1e696c954ff681558938a44d1d</related_field_hash>
<limit>20</limit>
</configuration>
</field>
When a section is initialized, Symphony checks for each field if it has a corresponding data-table (tbl_entries_data_n
) in the database. This is done by checking if the hash already exists in the lookup table. If not, then the initialization/installation-method of the specific field should be executed, followed by inserting its unique hash into the database.
The deletion of fields follows a similar pattern. When a unique hash is detected in the database, and no corresponding field is found, it means that the field is removed from the XML-file. The data-table of the field is then dropped.
Now, to be sure that we're not accidentally dropping data from the database, an extra security measure is made. This is done on the difference page when synchronizing the section.
The XML-approach makes it theoretically possible to change the type of a field, whilst retaining its data. You could for example change a field from type upload
to unique_upload
. This situation is not yet implemented, since Symphony has no solution for mutation of field types. In this scenario, Symphony will show a notification that there is a type mismatch and cannot synchronize the XML.
On initialization, the section manager creates an internal list of all sections and iterates through them with the following logic:
Datasources and events use the unique hash of the section and the unique hash of the field for filtering. This reference is made in the getSource()
-function and in the $dsParamFILTERS
-parameter.
Your workspace-folder might look something like this:
workspace
data-sources <!-- datasources folder -->
events <!-- events folder -->
sections <!-- sections folder -->
pages
my-page.xsl <!-- stylesheet -->
my-page.xml <!-- configuration file -->
utilities
assets
css
js
In retrospect, our news-module example could look like this:
workspace
data-sources
data.news-index.php
data.news-archive.php
data.news-detail.php
events
sections
news.xml
utilities
format-date.xsl
pages
news.xsl
news.xml
news-archive.xsl
news-archive.xml
news-detail.xsl
news-detail.xml
assets
css
news.css
js
news.js
Extensions are a bit of a strange entity in this complete picture. Some sections could depend on it, since they might use field-types which are provided by extensions. If a fields' type cannot be found, the system will show a message that the field-type is not available and that they need to install the extension for it. In other words: a synchronization cannot be done when trying to install fields which are not available in the Symphony installation.