Introduction
Photon is a PHP library built by Jadu to power templates for Jadu CMS.
New template sets are implemented as Symfony bundles and registered with the CMS by either amending the bundles.xml
configuration file or running the register theme terminal command.
Templates are extensible and can be overridden easily. In common with many Symfony applications, routes are defined in the configuration file routes.yml
, controller dependencies are set in the configuration file services.yml
.
Photon is built upon the Symfony framework, so having a good knowledge of the framework and Twig template language is beneficial. The following guides from the Symfony documentation are a good starting point:
Extensive documentation is also provided for Twig:
Themes
Each theme within Photon is defined as a Symfony bundle.
Whats in a theme bundle?
Each theme bundle contains a single theme.
Themes extend one another, so a theme bundle need not be exhaustive.
Typically a theme will contain:
- Pages: controllers responsible for fetching the content from a Repository and redering a Template
- Components: controllers responsible for rendering a fragment to be embedded within a Template
- Theme: A simple PHP class that registers the theme and specifies paths to Resources
- Resources: a colletion of Twig templates, configuration files and static assets
- Widgets: controllers responsible for rendering a widget
Further information on the Bundle system is available in the Symfony documentation - The Bundle System.
Registering a theme
A command is provide to easily register Galaxies site themes with the CMS.
php cli.php cms:theme-register /absolute/path/to/theme
Themes must be registered with the CMS so that they are loaded by the Symfony kernel when it is booted. This can be done via running the cms:theme-register
command.
Limiting themes for Galaxies sites
When developing a theme for use within a Galaxies site, you may want to limit the loaded theme bundles to prevent unwanted resources being available for that Galaxies site (e.g. a custom theme route).
This is possible by adding an XML element galaxy<GALAXY_DATABASE_NAME>
to your bundles.xml
configuration, which will limit the theme bundles loaded by the Symfony kernel for that Galaxies site.
For example, to ensure galaxy with database 'ms_jadudb_1' only loads 'MyGalaxyThemeBundle'.
<?xml version="1.0" encoding="utf-8" ?>
<bundles xmlns:config="http://www.jadu.co.uk/schema/config">
<!-- ... -->
<galaxyms_jadudb_1 config:type="array">
<item key="my-galaxy-theme">MyGalaxyTheme\MyGalaxyThemeBundle</item>
</galaxyms_jadudb_1>
</bundles>
Controllers
Page controllers
Pages are registered within the theme
services.yml
configuration file.
photon_cms_project.page.document_category:
class: DocumentCategoryController
parent: photon.controller.page
arguments:
- '@photon.repository.category'
- '@photon.repository.document'
- '@photon.repository.homepage'
- '@photon.repository.homepage_category_default'
- '@photon.repository.supplement'
- '@sdk.configuration.constant_repository'
- '@router'
tags:
- { name: photon.page, page_name: document_category }
Page services must be tagged with
photon.page
.
Page controllers are responsible for fetching the content from a respository and rendering a template. A simple invokable controller is defined per Page
class. Page components are invoked by a route.
Each page controller extends the Photon\Core\Controller\Page
class of the PhotonCoreBundle
project.
Photon\Core\Controller\Page
itself extends the Symfon framework Controller
class. Further details are available in the Symfony documentation - Controller.
Component controllers
Components are registered within the theme
services.yml
configuration file.
photon_cms_project.component.category_navigation:
class: CategoryNavigationController
parent: photon.controller.component
arguments:
- '@ohoton.repository.category'
- '@router'
- '@sdk.configuration.constant_repository'
tags:
- { name: photon.component, component_name: category_navigation }
Component services must be tagged with
photon.component
.
Component controllers, like page controllers, are responsible for fetching the content from a respository and rendering a template.
A simple invokable controller class is defined per component.
Page controllers have no knowledge of the action of the component controller, components are rendered within a page template as sub-requests.
As with Pages, Components can be extended and overridden by other themes.
Additional information on sub-requests is provided in the Symfony documentation - Sub Requests.
Invoking components
{{ component('announcement') }}
{{ component('announcement', {name: 'Tom'}) }}
Components are not invoked by a route, but instead by using the component()
Twig function
Parameters can be passed to components at render time, which are passed to the __invoke()
method of the Component.
<?php
namespace Spacecraft\DemoProject\Component;
use Photon\Core\Controller\Component;
use Symfony\Component\HttpFoundation\Response;
class CategoryNavigationController extends Component
{
/**
* @param string $name
*
* @return Response
*/
public function __invoke($name)
{
return $this->render(
'announcement.html.twig',
[
'name' => $name,
]
);
}
}
Widget controllers
Widgets are registered within the theme
services.yml
configuration file.
photon_cms_project.widget.website_statistics:
class: WebsiteStatisticsWidget
parent: photon.controller.widget
arguments:
- '@photon.repository.website_statistics'
tags:
- { name: photon.widget, widget_id: 31 }
Widget services must be tagged with
photon.widget
and with the parameterwidget_id
. The id must match the corresponding database entry inJaduHomepageWidgets
.
Widget controllers are specialised component controllers. They interact with the Homepage designer feature of Jadu CMS.
Invoking widgets
{{ widget(widgetRecord) }}
Widgets are not invoked by a route, but instad by using the widget()
Twig function.
A widget record must be passed as a parameter to the widget()
function.
Interacting with the request
<?php
if (
$this->getRequestStack()->request->has('period')
&& $this->getRequestStack()->request->get('period') == 'today'
) {
// ...
}
The Page
class within PhotonCoreBundle
initialises the Symfony Request
object in its constructor.
The Request stack object can be retrieved in classes that extend Page
by calling getRequestStack()
method.
Further details on how to interact with data held in the Request object are provided in the Symfony documentation - Accessing Request Data.
Returning a response
<?php
return $this->render(
'article.html.twig',
[
'page' => $page,
'page_categoryId' => $categoryId,
'page_contentType' => 1,
'page_translationItem' => $document->getId(),
'page_translationType'=> 'document',
'page_structure' => $pageStructure,
]
);
All controller classes contain an __invoke()
method that is called when a request terminates at that controller. The __invoke()
method must return a Response
object.
The Photon\Core\Controller\Page
class of the PhotonCoreBundle
project that all Photon Page controllers extend provides a method render()
that returns a formatted Response
object.
render()
generally takes two arguments:
- the path to the Twig template to be rendered
- an array of values to be supplied to the template
Further details on Response objects are provided by the Symfony documentation - Response.
Core Page controller methods
The Photon\Core\Controller\Page
class provides a number of useful functions to the controllers that extend it.
Method | Description |
---|---|
render() |
Render a twig template and return a Response |
getMetaElement() |
Create and return a Meta object |
getRequestStack() |
Get the Symfony Request object for this request |
getMetadata() |
Populate and return a Metadata object for this page |
isPreview() |
Check if this page is currently being accessed as a preview |
getTranslatedString() |
Get the translated string for a given key based on the site's locale value |
isPasswordProtected() |
Check if the site is currently behind password protection |
isAuthenticated() |
Check if the user has a current session for viewing a site behind password protection |
Routes
Routes are defined in the theme
routing.yml
config file.
homepage:
path: /homepage/{homepageId}/{homepageSlug}
defaults:
_controller: photon.page.homepage
atoz_list:
path: /a_to_z/{startsWith}
defaults:
_controller: photon.page.atoz_list
startsWith: ~
atoz_article:
path: /a_to_z/service/{serviceId}/{serviceSlug}
defaults:
_controller: photon.page.atoz_article
requirements:
serviceId: \d+
Routes within Photon are based on the Symfony router.
Where a {placeholder}
is placed in the route path, that portion becomes a wildcard. The corresponding controller must now have an argument called $placeholder
.
Each route has an internal name. For example homepage
, atoz_list
and atoz_article
. These must be unique and are used to generate URLs in controllers and templates.
Further information on routing is available in the Symfony documentation - Routing.
Generating URLs
<?php
$link->setUrl($this->generateUrl(
'news_article',
[
'articleId' => $newsArticle->getId(),
'articleSlug' => $newsArticle->getSlug(),
]
));
To generate a URL, you must specify the name of the route, and any parameters used in the path for that route.
Instead of hardcoding URLs into templates, the path
Twig function can be used to generate URLs based on the routing configuration. Changing the route will then update all template instances where that route is used.
<a href="{{ path('welcome') }}">Home</a>
Further information on generating URLs is provided in the Symfony documentation - Generating URLs
Redirecting
<?php
// redirect to the "homepage" route
return $this->redirectToRoute('homepage');
// do a permanent - 301 redirect
return $this->redirectToRoute('homepage', [], 301);
// redirect to a route with parameters
return $this->redirectToRoute(
'blog_show',
[
'slug' => 'my-page',
]
);
// redirect externally
return $this->redirect('http://symfony.com/doc');
A number of redirect options are provided via Symfony.
Further information on redirecting is provided in the Symfony documentation - Redirecting.
Models
<?php
namespace Photon\CmsEngine\Model\Element;
class Article
{
/**
* @var Link
*/
private $link;
/**
* @param Link $link
*
* @return Article
*/
public function setLink($link)
{
$this->link = $link;
return $this;
}
/**
* @return Link
*/
public function getLink()
{
return $this->link;
}
}
You can use a dot (.) to access attributes of a model variable in twig
{{ article.title }}
{{ article.link.url }}
A number of model classes are provided to format data for pages and ensure a consistent interface when accessing data from different areas of the CMS.
The attributes of the model are accessed using getter and setter functions in PHP. Calls to setter methods can be chained for ease of use.
Article
<?php
use Photon\CmsEngine\Model\Element\Article;
$article = new Article();
$article->setTitle($item->getTitle());
$article->setSummary($item->getSummary());
$article->setBody($item->getDescription());
$article->setImage($item->getImage());
$article->addMeta(
$this->getTranslatedString('date-label'),
$this->getMetaElement(
$this->getTranslatedString('date-label'),
$item->getEventDate(),
'string'
)
);
This model defines a generic article page.
Classname
Photon\CmsEngine\Model\Element\Article
Attributes
Attribute | Type | Description |
---|---|---|
$image | Image | Featured image of the article |
$title | string | Title of the article |
$subTitle | string | Subtitle of the article |
$summary | string | A brief summary of the article |
$body | string | Rich text content that makes up the body of the article |
$meta | array | Array of metadata on this article |
$supplements | array | Array of supplements associated with this article |
$passwordProtected | boolean | Whether this content is password protected |
$restricted | boolean | Whether access to this content is restricted |
$navigation | array | Array of navigation links |
$pagination | array | Array of pagination links |
$link | Link | Link to this article |
Form
<?php
use Photon\CmsEngine\Model\Element\Form;
use Photon\CmsEngine\Model\Element\FormControl;
$form = new Form();
$form->setTitle($title);
$form->setMethod('post');
$control = new FormControl();
$control->setName('_token');
$control->setType('hidden');
$form->addControl($control);
$control = new FormControl();
$control->setLabel($emailLabel);
$control->setName('email');
$control->setType('email');
$control->setValue('');
$control->setMandatory(true);
$control->setAutocomplete(false);
$form->addControl($control);
$control = new FormControl();
$control->setLabel($passwordLabel);
$control->setName('password');
$control->setType('password');
$control->setValue('');
$control->setMandatory(true);
$control->setAutocomplete(false);
$form->addControl($control);
$control = new FormControl();
$control->setLabel($signinButtonLabel);
$control->setName('jaduSignInButton');
$control->setType('submit');
$form->setPrimaryAction($control);
This model defines a form, including a list of form controls to submit data to the page.
Classname
Photon\CmsEngine\Model\Element\Form
Attributes
Attribute | Type | Description |
---|---|---|
$id | integer | The id of this form in the database, where the form is content managed |
$title | string | The title of the form |
$controls | array | An array of form controls that make up this form page |
$errors | array | An array of errors found in the form following validation |
$action | string | The content of the action attribute of the form HTML element |
$method | string | The content of the method attribute of the form HTML element |
$formHeading | string | The title of this form page |
$instructions | string | Rich text content that makes up the instructions of the form page |
$primaryAction | FormControl | The form control that forms the primary action of the form, often a submit button |
$secondaryAction | FormControl | The form control that forms the secondary action of the form, often a cancel or back button |
FormControl
<?php
use Photon\CmsEngine\Model\Element\FormControl;
$control = new FormControl();
$control->setLabel($passwordLabel);
$control->setName('password');
$control->setType('password');
$control->setValue('');
$control->setMandatory(true);
$control->setAutocomplete(false);
A single form control and its associated values, such as label and help text.
Classname
Photon\CmsEngine\Model\Element\FormControl
Attributes
Attribute | Type | Description |
---|---|---|
$id | integer | The id of this form control in the database, where the form is content managed |
$label | string | The label of the form control |
$options | array | An array of form control options, for example in a select or radio button group |
$name | string | The content of the name attribute of the form control's HTML element |
$value | string | The content of the value attribute of the form control's HTML element |
$type | string | The type of form control HTML element to use in the template |
$error | boolean | Whether validation found an error in this control |
$autocomplete | boolean | Whether the autocomplete attribute should be disabled for this control |
$disabled | boolean | Whether this control is disabled in the user interface |
$help | string | The help text to display with this form control |
$maxlength | integer | The content of the maxlength attribute of the form control's HTML element |
$mandatory | boolean | Whether this control must be completed prior to successful submission |
$className | string | Additional CSS class name data associated with this control |
$placeholder | string | The content of the placeholder attribute of the form control's HTML element |
FormControlOption
<?php
use Photon\CmsEngine\Model\Element\FormControlOption;
$option = new FormControlOption();
$option->setValue('')
->setText('All Categories');
$options[] = $option;
foreach ($topLevelCategories as $topLevelCategory) {
$option = new FormControlOption();
$option->setValue($topLevelCategory->getId())
->setText($topLevelCategory->getTitle());
$options[] = $option;
}
A single option for a form control, such as a select or radio button group.
Classname
Photon\CmsEngine\Model\Element\FormControlOption
Attributes
Attribute | Type | Description |
---|---|---|
$value | string | The content of the value attribute of the form control's HTML element |
$text | string | The label for this option |
Link
<?php
use Photon\CmsEngine\Model\Element\Link;
$azLink = new Link();
$azLink->setTitle($char);
$azLink->setUrl(
$this->urlGenerator->generate(
'atoz_list',
[
'startsWith' => $char,
]
)
);
$azLink->setDisabled($count > 0);
A link element, including the link destination and label text.
Classname
Photon\CmsEngine\Model\Element\Link
Attributes
Attribute | Type | Description |
---|---|---|
$url | string | The content of the href attribute of the link's HTML element |
$title | string | The text the link will be applied to |
$subtitle | string | Additional text that the link will be applied to, commonly used to split the title to allow additional HTML elements to be applied and styled differently |
$active | boolean | The link has been selected |
$disabled | boolean | The link should be displayed as disabled in the user interface |
Listing
<?php
use Photon\CmsEngine\Model\Element\Listing;
$listing = new Listing();
$listing->setTitle($azPageTitle);
$listItems = $this->getRecordList($items, $aliasitems);
if ($listItems) {
$listing->addList($listItems);
}
$listing->setAZLinkList(
$this->buildAZLinkListBar()
);
A generic list page.
Classname
Photon\CmsEngine\Model\Element\Listing
Attributes
Attribute | Type | Description |
---|---|---|
$filterBar | Form | A form for filtering the content of this list |
$pagination | array | Array of pagination links |
$feature | Article | Featured article from the list on this page |
$title | string | The title of the page |
$azLinkList | array | Array of A to Z navigation links for filtering the content of this list |
$lists | array | Array of lists to display on this page |
ListItem
<?php
use Photon\CmsEngine\Model\Element\ListItem;
$list = new ListItem();
$list->setType('record');
$list->setItems($records);
An array of records or articles.
Classname
Photon\CmsEngine\Model\Element\ListItem
Attributes
Attribute | Type | Description |
---|---|---|
$title | string | The title of the list |
$items | array | Array of article or link objects that make up this list |
$type | string | The type of list, for example "record" or "article" |
Meta
<?php
use Photon\CmsEngine\Model\Element\Meta;
$meta = new Meta();
$meta->setTitle($title);
$meta->setValue($value);
$meta->setType($type);
A snippet of content related to an article, for example the published date.
Classname
Photon\CmsEngine\Model\Element\Meta
Attributes
Attribute | Type | Description |
---|---|---|
$value | string | The value of the metadata defined |
$title | string | The label for the metadata defined |
$type | string | The type of the value, for example "string" or "date" |
Modular
<?php
use Photon\CmsEngine\Model\Element\Modular;
$modular = new Modular();
$modular->setHomepage($homepage);
$modular->setTitle($homepage->getTitle());
$modular->setSupplements($this->getSupplements($homepage));
Generic modular page for use with Jadu CMS Homepage content type.
Classname
Photon\CmsEngine\Model\Element\Modular
Attributes
Attribute | Type | Description |
---|---|---|
$title | string | The title of the page |
$homepage | Homepage | The modular content block of the page |
$supplements | array | Array of supplements associated with this article |
$navigation | array | Array of navigation links |
$documents | array | Array of document records associated with this page |
Page
<?php
use Photon\CmsEngine\Model\Element\Page;
$page = new Page();
$page->setContent($article);
$page->setBreadcrumb($this->getBreadcrumb());
$page->setMetadata($this->getMetadata());
$page->setBodyClass('councillor-article');
A generic page, including elements such as metadata and breadcrumb.
Classname
Photon\CmsEngine\Model\Element\Page
Attributes
Attribute | Type | Description |
---|---|---|
$breadcrumb | array | Array of breadcrumb links |
$navigation | array | Array of navigation links |
$content | Modular/Listing/Article/Form | The main content block of the page |
$metadata | array | HTML metadata values |
$attributes | array | Array of key value pairs associated with the page |
$bodyClass | string | Additional CSS class name to be printed on the body HTML element |
Default theme
The default theme implements all functionality provided with Jadu CMS, and provides a base from which to extend when creating a custom theme.
The default theme is maintained, and any updates available will be added either:
- when you next use Composer to update your dependencies
- when your site is patched with an updated Jadu CMS release
CSS classes
The default theme uses Block Element Modifier (BEM)naming conventions for its class names.
Uniquely classes are set on each page of the default theme.
Partials
The partials in the default theme are organised according to atomic design principles.
Further information on atomic design is available in the Atomic design blog post.
Hard coded text
{{
getTranslatedString(
'password-reset-email-ip-statement',
[app.request.getClientIp()]
)
}}
Within page and component controllers, translated text can be retrieved using the function
getTranslatedString()
ofPhoton\Core\Controller\Page
.
<?php
$crumb->setTitle($this->getTranslatedString('az-page-link'));
Hard coded text in templates is managed using the Language Pack module in Jadu CMS.
A non-technical user interface is provided to add, update and remove text in the language pack.
Photon provides functions to retrieve the appropriate text based on the locale associated with the site.
The function to retrieve text takes two arguments:
- the reference for the string to retrieve.
- an array of parameters to replace placeholders in the text (optional).
Site locale
The locale of a site is set within the JaduLanguagePacksToSites database table. Where no matching record is found, requests for text fallback to the language pack installed with the CMS.
New language packs can be defined within the CMS and are associated with a locale. Available locales are defined within the JaduLanguageLocales database table.
Layouts
The default template set makes use of template inheritance in Twig to reduce repetition and ease maintenance.
The primary template is base.html.twig
. The base template defines the HTML skeleton of the page and a number of block tags that a child template may override or extend.
Further information on extending templates can be found in Twig documentation.
Article
A page on a single topic with a title and body of content.
- A to Z article
- Councillor article
- Meeting article
- News article
- Event article
- Download article
- Document article
- Directory article
- Directory record article
- Offline page
List
A list of records or articles, that may be paginated or filterable.
- A to Z list
- Councillor list
- Meeting list
- User home
- News list
- Default category homepage
- Event list
- Directory search results
- Directory record list
- Search result list
Modular
A page of content made up of blocks of widgets.
- Index
- Standalone homepage
- Category homepage
Form
A HTML form.
- API apply
- Change details
- Forgot password
- Password reset
- Registration
- Sign in
- Unsubscribe
- Event submission
- Directory submission
- Accessibility settings
Default routes & pages
The default theme consists of the following routes and associated page controllers that output their response in a template. Page controllers are found in the theme Page
directory.
A to Z article
A single A to Z of services entry and any associated contact details.
Route name
atoz_article
URL pattern
/a-to-z/service/{serviceId}/{serviceSlug}
Layout
Article
Module
EGov
Page class
atoz-article
Acceptance criteria
- Page errors if an invalid service ID is passed - 404 response
- Page errors if the service is offline - 404 response
- Page redirects to appropriate URL if service has redirect set
- Breadcrumb includes A-Z list
- A to Z record metadata is included in the page
- Title, content, eligibility, accessibility and availability content is rendered on the page
- Multimedia items are rendered in service document editor content
- Eligibility section is only shown if it has been completed
- Accessibility section is only shown if it has been completed
- Availability section is only shown if it has been completed
- Contacts section is only shown if it has been completed
- Each contact assigned to service is printed
- Contact name is only printed if it has been completed
- Contact department is only printed if it has been completed
- Contact email is only printed if it has been completed
- Contact telephone is only printed if it has been completed
- Contact mobile is only printed if it has been completed
- Contact fax is only printed if it has been completed
- Contact URL is only printed if it has been completed
- Contact address is only printed if it has been completed
- Contact email is rendered as a mailto: link
- Contact telephone is rendered as a tel: link
- Contact mobile is rendered as a tel: link
- Contact URL is rendered as a link
- Approved version is shown
- HTML content is rendered unencoded
A to Z list
Filtered list of A to Z entries and aliases.
Route name
atoz_list
URL pattern
/a-to-z/{startsWith}
Layout
List
Module
EGov
Page class
atoz-list
Acceptance criteria
- I can view a list of A to Z records starting with the selected letter
- Each list item links to the correct A to Z article path
- A to Z record aliases are included in the list of records
- List of records appears in alphabetical order
- All records starting with a letter are shown on one page (no pagination)
- List of records can be filtered by a different letter by clicking a letter in A-Z bar
- Letters with no records are shown as disabled
- Letters with records link to the correct A to Z list path
- Message shown if no services in system
Accessibility settings
Form to customise the appearance of the site in line with a user's accessibility needs.
Route name
accessibility_settings
URL pattern
/accessibility/settings
Layout
Form
Module
Utilities
Page class
accessibility-form
Accessibility criteria
- Colour scheme setting is saved to session when form is submitted
- Font size setting is saved to session when form is submitted
- Font setting is saved to session when form is submitted
- Using the reset button clears saved session values
- Form can be navigated by keyboard only
API apply
Form to apply for an API key linked with a user's account.
Route name
user_account_api_apply
URL pattern
/account/api/apply
Layout
Form
Module
MyAccount
Page class
api-form
Acceptance criteria
- Must have valid user session to view
- Redirects to index if no valid user session
- Form includes description field, terms checkbox and submit button
- An error is highlighted if terms is not checked on submission
- On successful submission a api key submission is generated, redirected to user home, success message shown
Category
Landing page of a category, including navigation to subcategories and documents relating to a single category of the site's taxonomy.
Route name
document_category
URL pattern
/{categorySlug}
Layout
Modular
Module
Publishing
Page class
category-modular
Acceptance criteria
- Category specific stylesheet is used
- Page does not error if no homepage is assigned
- Page errors if an invalid category ID is passed - 404 response
- Page errors if no documents, no subcategories or no homepage assigned - 404 response
- Breadcrumb includes category path
- Modular homepage widget block is rendered as in CMS
- Approved version is shown
- List of documents assigned to category shown
- Homepage specific metadata is not used
- Modular content only rendered if homepage assigned
- Page supplements are shown
- HTML content is rendered unencoded
Change details
Form to update the details of a user.
Route name
user_account_change_detail
URL pattern
/account/change-detail
Layout
Form
Module
MyAccount
Page class
change-details-form
Acceptance criteria
- Redirects to https if ssl is enabled
- Redirects to appropriate url if user adapter change details page is specified
- Must have valid user session to view
- Redirects to index if no valid user session
- Redirects to user home if user adapter change details is disabled
- Redirects to register authorisation if email has not been authorised
- Breadcrumb includes user home
- Form includes csrf token, email address field and save changes submit button
- Salutation field, forename, surname, birthday, age, sex, occupation, company, address, city, county, postcode, country, telephone, mobile, fax, website, data protection and targetting question fields when enabled in register preferences
- Fields are prefilled with user’s current details
- Error message is shown if CSRF token invalid on submission
- Error message is shown if email address is not a string in email address format
- Error message is shown if email address matches a different registered user
- Error message is shown if salutation is not one of Mr, Miss, Mrs, Ms, Mx, Dr or other
- Error message is shown if forename is blank
- Error message is shown if surname is blank
- Error message is shown if birthday is not a valid date
- Error message is shown if birthday is not in the past
- Error message is shown if age is not a number
- Error message is shown if sex is not one of “Male” or “Female”
- Error message is shown if address is blank
- Error message is shown if city is blank
- Error message is shown if postcode is blank or includes non alphanumeric characters
- Error message is shown if country is blank
- Error message is shown if an answer is not supplied for targetting question
- If errors are found, submitted values are shown in form fields
- If no errors found, user details are updated
- If user email is updated and email authentication is enabled, authentication email is sent
- If user is updated, redirected to user home and success message shown
- Breadcrumb includes user account link
Change password
Form to update the password of a user.
Route name
user_account_change_password
URL pattern
/account/change-password
Layout
Form
Module
MyAccount
Page class
password-reset-form
Acceptance criteria
- Must have valid user session to view
- Redirects to https if ssl is enabled
- Redirects to appropriate url if user adapter change password page is specified
- Redirects to index and error message shown if user not logged in
- Form includes old password field, new password field, new password confirmation field and submit button
- Error message is shown if password is less than 6 characters
- Error message is shown if password is greater than 30 characters
- Error message is shown if new password is not the same as new password confirmation
- If no errors found, password is updated
- If password is updated, reset code is disabled.
- If password is updated, redirects to user home, success message shown
- Breadcrumb includes user account link
Councillor article
Details of a single Councillor, including their contact details and associated image.
Route name
councillor_article
URL pattern
/councillors/{councillorId}/{councillorSlug}
Layout
Article
Module
EGov
Page class
councillor-article
Acceptance criteria
- Approved version is shown
- Page errors if invalid councillor ID is passed - 404 response
- Page errors if councillor is offline - 404 response
- Breadcrumb includes councillors list
- First name, second name, image, party, ward, position, address, telephone, fax, email, content are rendered
- Page does not error if party deleted
- Page does not error if ward deleted
- Multimedia is rendered in document editor content
- Image is only printed if completed
- Image Caption is rendered if completed
- Position is only printed if completed
- Address is only printed if completed
- Telephone is only printed if completed
- Telephone is rendered as a tel: link
- Fax is only printed if completed
- Email is only printed if completed
- Email is rendered as a mailto: link
- Content is only printed if completed
- HTML content is rendered unencoded
Councillor list
Filtered list of councillors.
Route name
councillor_list
URL pattern
/councillors
Layout
List
Module
EGov
Page class
councillor-list
Acceptance criteria
- I can view a list of councillors
- List is not paginated
- List can be filtered by party, ward
- List of records is sorted by alphabetical order
- Each item links to valid councillor path and includes first name and surname
- Message shown if no councillors in system
Directory article
Directory home page including description and links to A to Z of records.
Route name
directory_article
URL pattern
/directory/{directoryId}/{directorySlug}
Layout
Article
Module
Publishing
Page class
directory-article
Acceptance criteria
- Page errors if an invalid directory ID is passed - 404 response
- Page errors if directory is offline - 404 response
- Directory specific metadata is used
- Directory title, description are rendered
- Description is only printed if completed
- Call to action to directory a to z is included
- Call to action to directory submission is included
- List of directory subcategories is included
- List item includes directory name, valid path to directory category
Directory A to Z list
List of directory records begining with a particular letter.
Route name
directory_atoz
URL pattern
/directory/{directoryId}/a-to-z/{startsWith}
Layout
List
Module
Publishing
Page class
directory-record-list
Acceptance criteria
- Page errors if an invalid directory id is passed - 404 response
- Page errors if directory is offline - 404 response
- Directory specific metadata is used
- I can view a list of A to Z records starting with the selected letter
- Each list item links to the correct record path
- List of records appears in alphabetical order
- All records starting with a letter are shown on one page (no pagination)
- List of records can be filtered by a different letter by clicking a letter in A-Z bar
- Letters with no records are shown as disabled
- Letters with records link to the correct A to Z list path
- Message shown if no records in directory
- Breadcrumb includes directory article
Directory record article
Details of a particular directory record article.
Route name
directory_record_details
URL pattern
/directory-record/{recordId}/{recordSlug}
Layout
Article
Module
Publishing
Page class
directory-record-article
Acceptance criteria
- Page errors if an invalid directory id is passed - 404 response
- Page errors if directory is offline - 404 response
- Page errors if an invalid record ID is passed - 404 response
- Page errors if record is offline - 404 response
- Directory record specific metadata is used
- Breadcrumb includes directory article
- Breadcrumb includes directory category path
- Record title, and fields are rendered
- If an optional field is not completed, it is not rendered
- Multimedia in document editor content is rendered
- Google map is rendered, and pin includes fields configured within directory settings
- Link fields are rendered as a link
- Email fields are rendered as a mailto: link
- ESRI map is rendered
- HTML content is rendered unencoded
- Image is rendered
- Image includes valid alt attribute
Directory search result list
List of records matching a search term in a directory.
Route name
directory_search
URL pattern
/directory/search
Layout
Article
Module
Publishing
Page class
directory-result-list
Acceptance criteria
- Page errors if an invalid directory id is passed - 404 response
- Page errors if directory is offline - 404 response
- Directory specific metadata is used
- Breadcrumb includes directory article
- List of results is paginated
- 50 results are shown per page
- If page number is greater than 1, a previous link is shown
- If more pages exist than the current page number, a next link is shown
- List of results matches the criteria submitted
- List item includes record title and link to valid record path
- If location search, results shown on map
- Pins include fields configured within directory settings
- Message shown if no results found
- Search form is shown
Directory record list
List of directory records in a particular category.
Route name
directory_category
URL pattern
/directory/{directoryId}/{directorySlug}/category/{categoryId}/{pageNumber}
Layout
List
Module
Publishing
Page class
directory-record-list
Acceptance criteria
- Page errors if directory is offline - 404 response
- Page errors if an invalid category id is passed - 404 response
- Directory specific metadata is used
- Breadcrumb includes directory article
- Breadcrumb includes directory category path
- Category adverts are included
- Category description is only rendered if completed
- List of records in category is shown
- List item includes record title and link to valid directory record path
- List of subcategories is shown
- List item includes category name and link to valid directory category path
- List of records is paginated
- 50 records shown per page
- If page number is greater than 1, a previous link is shown
- If more pages exist than the current page number, a next link is shown
Directory record submission
Form for public submission of a new record to a directory.
Route name
directory_submit
URL pattern
/directory/{directoryId}/{directorySlug}/submit
Layout
Form
Module
Publishing
Page class
directory-submit-form
Acceptance criteria
- Page errors if an invalid directory id is passed - 404 response
- Page errors if directory is offline - 404 response
- Directory specific metadata is used
- Breadcrumb includes directory article
Document article
A single page of a document with navigation to all other pages in that document.
Route name
document_page
URL pattern
/{categorySlug}/{documentSlug}/{pageNumber}
Layout
Article
Module
Publishing
Page class
document-article
Acceptance criteria
- Category specific stylesheet is used
- Document specific metadata is used
- Breadcrumb includes category path
- I can preview a document page
- Preview includes accessibility check javascript
- Approved version is shown
- Page errors if an invalid document ID is passed - 404 response
- Page errors if a category ID not assigned to document is passed - 301 response, redirect to valid category
- Page errors if an invalid page number is passed - 404 response
- If no page number passed, default page number 1 is used
- If password protected and not authenticated, message and password form shown
- Submitting valid password in password form is saved against session
- If password protected and authenticated, or not password protected, document content is shown
- If access level is greater than current session, permission denied message shown
- If access level is less than or equal to current session, document content is shown
- Document title, page title, image, page content are rendered on page
- If document title is the same as page title, only document title is shown
- Image is only shown when completed
- Caption is rendered when completed
- Multimedia content is rendered in document editor content
- List of pages is shown if there are more than one page in document
- Current page is highlighted as active in the list
- Each list item is page title and link to valid document page path
- If page number is greater than 1, previous link is shown
- If page number is less than total number of pages, next link is shown
- Page supplements are shown
- HTML content is rendered unencoded
Download article
Details of a single download, with a links to download all associated files.
Route name
download_article
URL pattern
/downloads/download/{downloadId}/{downloadSlug}
Layout
Article
Module
Publishing
Page class
download-article
Acceptance criteria
- Category specific stylesheet is used
- Page errors if an invalid download id is used - 404 response
- Page errors if download is offline - 404 response
- Page does not error if download if not visible - 200 response
- Approved version is shown
- If password protected and not authenticated, message and password form shown
- Submitting valid password in password form is saved against session
- If password protected and authenticated, or not password protected, download content is shown
- Download title, description, list of files is rendered
- Each uploaded file includes filename, file size, extension and link to valid download path
- Each linked file includes filename and link to external path
- Description is only shown if completed
Download file
Stream a file.
Route name
file_download
URL pattern
/downloads/file/{fileId}/{fileSlug}
Layout
n/a - no HTML output
Module
Publishing
Event article
A single event and associated image.
Route name
event_article
URL pattern
/events/event/{eventId}/{eventSlug}
Layout
Article
Module
Publishing
Page class
event-article
Acceptance criteria
- I can view an event
- Page errors if an invalid event ID is passed - 404 response
- Page errors if the event is offline - 404 response
- Breadcrumb includes events list
- I can preview an event
- Event specific metadata is used
- Title, event date, date interval, event time, location address, esri map, cost, summary, image, content are rendered on the page
- Multimedia items are rendered in event document editor content
- Interval is only shown if it has been completed
- ESRI map is only shown if integration is enabled
- Time is only shown if it has been completed
- Document editor content is only shown if it has been completed
- Image is only shown if it has been completed
- Image caption is shown where it has been added
- Approved version is shown
- Page does not error if location deleted
- HTML content is rendered unencoded
Event list
Filtered and paginated list of events.
Route name
event_list
URL pattern
/events
Layout
List
Module
Publishing
Page class
event-list
Acceptance criteria
- I can view a list of events
- A call to action is shown to submit your event
- 10 events are shown per page
- If page number is greater than 1, a previous link is shown
- If more pages exist than the current page number, a next link is shown
- Each event includes, title, summary, event date
- Each event links to a valid event path
- List of events can be filtered by date and location
- Events are shown in chronological order - from today ascending
- Message shown if no events in system
Event submission
Form for public submission of a new event.
Route name
event_submission
URL pattern
/event/new
Layout
Form
Module
Publishing
Page class
event-submit-form
Acceptance criteria
- Form includes title, start date, interval, end date, start time, end time, location, new location, cost, summary, description, image fields and submit button
- Error shown if start date is invalid date format or empty
- Error shown if end date is invalid date format
- Error shown if auth field is empty or invalid content
- Error shown if title empty or greater than 255 characters
- Error shown if new location is greater than 255 characters
- Error shown if location does not match a valid location id
- Error shown if summary is empty or greater than max summary character limit
- Error shown if description is greater than 65535 characters
- Error shown if start time is not in time format
- Error shown if end time is not in time format
- Error shown if cost is empty or greater than 255 characters
- Error shown if start date is after end date
- Error shown if image is not an image file of type jpg, jpeg, gif or png
- If errors are found, submitted values are shown in form fields
- If no errors found, event is submitted and image uploaded
- Image should be appended to description of submitted event
- Submitted event should not be live and visible on the website immediately after submission
- Image should appear in the site image library with valid title
- Event should have valid metadata
- Email notification of new event submission should be sent
- If event submitted, redirect to event list and show success message
Forgot password
Form to request a password reset link.
Route name
user_account_forget_password
URL pattern
/account/forgot-password
Layout
Form
Module
MyAccount
Page class
forgot-password-form
Acceptance criteria
- Redirects to https if ssl is enabled
- Redirects to appropriate url if user adapter forgot password page is specified
- Redirects to signin page if user adapter change details is disabled
- Form includes email address field and submit button
- Error message shown if email is not valid format
- Password reset email sent if email matches an existing user
- Success message shown if password reset email is sent
Index
The main homepage of the site.
Route name
index
URL pattern
/
Layout
Modular
Module
Publishing
Page class
index-modular
Acceptance criteria
- No breadcrumb is shown
- Homepage specific stylesheet is used
- No h1 is shown
- Page does not error if no homepage is available
- Homepage specific metadata is used
- Approved version is shown
- Modular homepage widget block is rendered as in CMS
- HTML content is rendered unencoded
- Homepage content relates to the independent homepage with highest position
Homepage
A single independent landing page.
Route name
homepage
URL pattern
/homepage/{homepageId}/{homepageSlug}
Layout
Modular
Module
Publishing
Page class
homepage-modular
Acceptance criteria
- Homepage specific stylesheet is used
- Page errors if an invalid homepage ID is passed - 404 response
- I can preview a homepage
- Preview includes accessibility check javascript
- Breadcrumb includes category path
- Homepage specific metadata is used
- Modular homepage widget block is rendered as in CMS
- Approved version is shown
- Page supplements are shown
- HTML content is rendered unencoded
- Hide navigation uses a one column layout
Meeting article
Details of a single meeting, including any agendas, minutes and other attachments.
Route name
meeting_article
URL pattern
/meetings/meeting/{meetingId}/{meetingSlug}
Layout
Article
Module
EGov
Page class
meeting-article
Acceptance criteria
- I can view a meeting article
- Page errors if an invalid meeting ID is provided - 404 response
- Page errors if meeting is offline - 404 response
- Breadcrumb includes a link to meeting list
- Committee title, meeting date, list of attachments are rendered on page
- Multimedia content in document editor content is rendered
- Meeting attachments can be downloaded
- HTML content is rendered unencoded
- Attachment types appear in the configured order
- Attachments are grouped by type
- Attachments appear in the configured position in their list
- Meeting specific metadata is used
Meeting download
Stream a meeting file attachment.
Route name
meeting_download
URL pattern
/download/meetings/id/{attachmentId}/{attachmentSlug}
Layout
n/a - no HTML output
Module
EGov
Meeting list
Filtered and paginated list of meetings.
Route name
meeting_list
URL pattern
/meetings
Layout
List
Module
EGov
Page class
meeting-list
Acceptance criteria
- I can view a list of meetings
- Only live meetings are shown in the list
- List is ordered by meeting date ascending
- Current page defaults to today where no filter options are set
- Meetings can be filtered by committee
- Meetings can be filtered by committee status (archived/current)
- 10 meetings are rendered per page
- Each list item links to valid meeting path
- If page number is greater than 1, a previous link is shown
- If more pages exist than the current page number, a next link is shown
- Message shown if no meetings in system
News article
A single news article and associated image.
Route name
news_article
URL pattern
/news/article/{articleId}/{articleSlug}
Layout
Article
Module
Publishing
Page class
news-article
Acceptance criteria
- I can preview a news article
- Page errors if an invalid news ID is passed - 404 response
- Page errors if the news article is offline - 404 response
- Breadcrumb includes news list
- Category specific stylesheet is used
- News article specific metadata is used
- Title, summary, image, content, news date content is rendered on the page
- Image is only rendered if it has been completed
- If image has caption, caption is shown
- News date is rendered in a recognised date format
- Multimedia items are rendered in article document editor content
- Approved version is shown
- HTML content is rendered unencoded
News list
Filtered and paginated list of news articles.
Route name
news_list
URL pattern
/news
Layout
List
Module
Publishing
Page class
news-list
Acceptance criteria
- I can view a list of news articles
- News articles are shown in chronological order - newest to oldest
- 10 articles are shown per page
- If page number is greater than 1, a previous link is shown
- If more pages exist than the current page number, a next link is shown
- List of news articles can be filtered by year and month
- Each article links to valid news article path
- Each article shows title, summary and news date
- Message shown if no news items in system
Offline
Holding page shown when the site has been taken offline.
Route name
site_offline
URL pattern
/offline
Layout
Article
Module
Utilities
Page class
offline-article
Acceptance criteria
- If site is offline, 40X response
- Offline exception page is shown
Password reset
Form to input a new password.
Route name
user_account_password_reset
URL pattern
/account/password-reset/{resetCode}
Layout
Form
Module
MyAccount
Page class
password-reset-form
Acceptance criteria
- Redirects to https if ssl is enabled
- Redirects to appropriate url if user adapter change password page is specified
- Redirects to index and error message shown if user not logged in and password reset code invalid
- Redirects to user home and error message shown if user logged in and password reset code invalid
- Form includes old password field, new password field, new password confirmation field and submit button
- If change has been forced, forced hidden input printed
- Error message is shown if password is less than 6 characters
- Error message is shown if password is greater than 30 characters
- Error message is shown if new password is not the same as new password confirmation
- If errors are found, submitted values are shown in form fields
- If no errors found, password is updated
- If password is updated, reset code is disabled.
Register
Form to create a new user account.
Route name
user_registration
URL pattern
/register
Layout
Form
Module
MyAccount
Page class
registration-form
Acceptance criteria
- Redirects to https if ssl is enabled
- Redirects to change details if valid user session
- Redirects to sign in if user adapter register is disabled
- Form includes csrf token, email address field, email address confirmation, password, password confirmation and register submit button
- Salutation field, forename, surname, birthday, age, sex, occupation, company, address, city, county, postcode, country, telephone, mobile, fax, website, data protection and targetting question fields when enabled in register preferences
- Error message is shown if CSRF token invalid on submission
- Error message is shown if password is less than 6 characters
- Error message is shown if password is greater than 30 characters
- Error message is shown if password is not the same as password confirmation
- Error message is shown if email address is empty
- Error message is shown if email address is not a string in email address format
- Error message is shown if email address matches a different registered user
- Error message is shown if email address is not the same as email confirmation
- Error message is shown if salutation is not one of Mr, Miss, Mrs, Ms, Mx, Dr or other
- Error message is shown if forename is blank
- Error message is shown if surname is blank
- Error message is shown if birthday is not a valid date
- Error message is shown if birthday is in the future
- Error message is shown if age is not a number
- Error message is shown if age is blank
- Error message is shown if sex is not one of “Male” or “Female”
- Error message is shown if address is blank
- Error message is shown if city is blank
- Error message is shown if postcode is blank or includes non alphanumeric characters
- Error message is shown if country is blank
- Error message is shown if an answer is not supplied for targetting question
- If errors are found, submitted values are shown in form fields
- If no errors found, user is registered
- If email authentication is enabled, authentication email is sent, redirected to index and info message is shown
- If user is registered, redirected to user home and success message shown
Restricted content login
Form used to access a restricted Galaxies site.
Route name
restricted
URL pattern
/restricted
Layout
Article
Module
Utilities
RSS
An RSS feed of recently published content
Route name
content_rss
URL pattern
/rss/{contentType}
Layout
n/a - no HTML output
Module
Publishing
Search list
List of search results provided by the site's search provider.
Route name
search_list
URL pattern
/site-search/results/
Layout
List
Module
Utilities
Page class
search-list
Sign in
Form to sign in to an existing user account.
Route name
user_account_signin
URL pattern
/account/signin
Layout
Form
Module
MyAccount
Page class
signin-form
Acceptance criteria
- Redirects to https if ssl is enabled
- Form includes email address, password, sign in button
- Error message is shown if details do not match user in system
- Error message doesn’t specify the incorrect value
- If details match valid user, user session started, user redirected to user account, success message shown
Unsubscribe
Form to unsubscribe from marketing newsletters sent by the site.
Route name
unsubscribe
URL pattern
/account/unsubscribe
Layout
Form
Module
MyAccount
Page class
unsubscribe-form
Acceptance criteria
- If user id and email match valid user from database, success message shown, redirect to index
- If user id and email do not match valid user from database, error message shown, redirect to index
- If valid user from database is found, data protection value is changed to 0
User home
User's account page detailing interactions with the site.
Route name
user_home
URL pattern
/account
Layout
List
Module
MyAccount
Page class
user-home-list
Acceptance criteria
- Redirects to https if ssl is enabled
- Must have valid user session to view
- Redirects to appropriate url if user adapter user home page is specified
- If user email authorisation is pending, message is shown and other functions disabled
- Submitted directory entries are shown on user home
- Valid api keys are shown on user home
- Welcome message naming user is shown
- If user adapter allows change details, link is shown
- If user adapter allows change password, link is shown
- Link is shown to logout of account
Non-HTML response routes
For the following routes, output comes directly from the controller and is not rendered in a template:
- meeting_download
- content_rss
- file_download
- logout
Template differences
There are a number of differences between the default template set provided with Photon, and the Jadu CMS legacy template set.
Events
Events templates have been condensed into two pages: events list and event article. A separate page to view events in a category is no longer available, events related to a particular category can be added to document category and document article templates where desired.
The event list does not include a calendar navigation element, events are shown in chronological order with next/previous pagination. Filtering by time period and location now interact, where as previously they were independent.
The event calendar is still available as a widget.
News
News templates have been condensed into two pages: news list and news article. A separate page to view news article in a category is no longer available, news related to a particular category can be added to document category and document article templates where desired.
The news archive is now combined into news list, the navigation of the news archive is provided as a filter form rather than a list of links.
The news list shows news articles in chronological order with next/previous pagination.
Downloads
Downloads templates have been condensed in a singled page: download article. Separate pages to view downloads in a category are no longer available. By default, downloads related to a particular category are listed on the document article template.
The download article template defaults to showing all files associated with a download record, and then providing a direct link to download the file, rather than then providing a link to the file specific page. The breadcrumb of the download article now links to document category tree, rather than the parallel download category tree.
As there is no downloads index page, there is no listing of popular downloads on the site.
A to Z
The A to Z home page, with separate tag cloud based navigation is no longer provided. A single list of A to Z items with alphabetical links to filter the list by letter is available, along with an A to Z article page. The A to Z article page no longer lists all content assigned to a category related to the A to Z article.
Councillors
The councillor index page, with hard coded statement, is no longer provided, a single list of councillors with filters for ward and party is provided instead.
The other councillors for a ward are no longer listed on the councillor article page. The "view by name", "view by party" and "view by ward" navigation links are no longer listed on the councillor article page.
Meetings & Minutes
Meeting templates have been condensed to remove the meeting specific category navigation pages. Meetings related to a particular category can be added to document category and document article templates where desired.
The meeting list page now shows all meetings chronologically with a filter form provided to filter by meeting heading or archive status.
Separate templates are no longer provided to view all archived meeting committees, or meetings related to a single committee.
The content of a meeting article page is now shown on load, rather than after clicking to view more as previously.
Directories
Directory templates have been condensed to remove the directory specific category navigation pages. By default, directories related to a particular category are listed on the document article template.
The breadcrumb of directory pages now links to document category tree, rather than the parallel directory category tree.
Sitemap
A separate, hardcoded sitemap template is no longer provided. A sitemap widget that outputs the document category tree is provided in its place.
Feedback form
A hardcoded feedback form is no longer provided. We recommend a content managed form is used where required.
Email a friend form
An email a friend form is no longer provided due to security concerns with this feature.
Terms and conditions
A separate terms and conditions content type is no longer provided, we recommend a content managed document or homepage is used where required.
Accessibility statement
A separate accessibility statement content type is no longer provided, we recommend a content managed document or homepage is used where required.
Location
A separate location content type is no longer provided, we recommend a content managed document or homepage is used where required.
API
A separate page to view an account's API key is no longer provided. The API key is instead shown directly on the user's account homepage.
Customisation
Creating a theme
Adding a new theme requires you to:
- Create a new theme bundle
- Create a theme class that defines your theme
- Register your theme with the CMS
- Configure your Symfony app to use the theme
Creating a theme bundle
AlphaTheme
|- AlphaThemeBundle.php
|- Component
| |- CategoryNavigationController.php
|- DependencyInjection
| |- AlphaThemeExtension.php
|- Page
| |- UtilitiesContent
| |- ThemeDemoController.php
|- Resources
| |- config
| | |- routing.yml
| | |- services.yml
| | |- theme.yml
| |- public
| | |- dist
| | | |...
| | |- images
| | | |...
| | |- js
| | |...
| |- templates
| |- layouts
| | |...
| |- pages
| | |...
| |- partials
| | |...
| |- widgets
| |...
|- Theme
|- AlphaTheme.php
A bundle is in essence a folder of files laid out in a consistent way.
It must contain:
- A bundle definition file eg.
AlphaThemeBundle.php
- A theme definition file eg.
Theme/AlphaTheme.php
- A theme service definition in a config file eg.
Resources/config/services.yml
- Dependency injection class to load the theme service definition eg.
DependencyInjection/AlphaThemeExtension.php
For Galaxies theme bundles, the following addtions are also required:
- A demo route definition in a config file eg.
Resources/config/routing.yml
- A theme config file eg.
Resources/config/theme.yml
- A demo route controller eg.
Page/UtilitiesContent/ThemeDemoController.php
- A preview image eg.
Resources/public/images/preview.png
An example theme bundle is available on GitHub: ExampleTheme
Creating a theme definition
<?php
namespace Spacecraft\DemoProject\Theme;
use Photon\Core\Theme\Theme;
class DemoTheme implements Theme
{
/**
* @return string
*/
public function getName()
{
return 'demo';
}
/**
* @return string
*/
public function getParent()
{
return 'base';
}
/**
* @return string
*/
public function getPath()
{
return __DIR__ . '/../Resources/templates';
}
}
The example defines the demo
theme, which extends base
. By convention, the theme file sits within the Theme
directory of the project.
The machine name of the theme should be defined in the getName()
method. If the theme is extending an existing theme, this should be defined in the getParent()
method. base
is the machine name of the CMS default theme.
The path to the twig templates provided by this theme should be defined within the getPath()
method.
Defining a theme service
spacecraft_demo_project.theme:
class: Spacecraft\DemoProject\Theme\DemoTheme
tags:
- { name: photon.theme }
To define a theme service service, create a service in services.yml
that points to the theme definition file. The service should be tagged with photon.theme
.
Using a custom theme
photon_core:
theme: demo
To use a theme, the configuration of your Symfony application should be updated. The photon_core
element should have a child, theme
. The value of theme
should be the machine name of the theme, eg. demo
.
By default, the CMS stores the Symfony application for the main site in /path/to/jadu/config/frontend.yml
.
Twig namespaces
{% extends '@theme:base/components/announcement.html.twig' %}
{% block title_outer %}
<h2>{{ block('title') }}</h2>
{% endblock %}
The selected theme will always be the main namespace for Twig, i.e. pages/demo.html.twig
will be loaded from the selected theme's templates.
If a theme has a parent theme, then the parent theme will also be within the main namespace.
Twig templates of a particular theme can be referenced using the theme namespace.
Customising pages
Defining the controller:
<?php
namespace Spacecraft\DemoProject\Page;
use Photon\Core\Controller\Page;
use Symfony\Component\HttpFoundation\Response;
class DemoController extends Page
{
/**
* @return Response
*/
public function __invoke()
{
return $this->render('pages/demo.html.twig');
}
}
Defining the service:
spacecraft_demo_project.page.demo:
class: Spacecraft\DemoProject\Page\DemoController
parent: photon.controller.page
When adding a new page, simply define the route and specify the new controller service
demo:
path: /demo
defaults:
_controller: spacecraft_demo_project.page.demo
Pages can be added in Photon by creating a controller class, defining a service and route.
The controller class is a standard Symfony controller that takes a Request
and returns a Response
. Generally, each page will have it's own controller and be an invokable class.
In this example the Twig template being rendered needs to be available in the current theme.
Customising components
Defining the controller:
<?php
namespace Spacecraft\DemoProject\Component;
use Photon\Core\Controller\Component;
use Symfony\Component\HttpFoundation\Response;
class AnnouncementController extends Component
{
/**
* @return Response
*/
public function __invoke()
{
return $this->render('components/announcement.html.twig');
}
}
Defining the service:
spacecraft_demo_project.page.demo:
class: Spacecraft\DemoProject\Component\AnnouncementController
parent: photon.controller.component
tags:
- { name: photon.component, component_name: announcement }
Invoking the component:
{{ component('announcement') }}
Components can be added in Photon by creating a controller class and defining a service tagged as photon.component
.
The controller class for a component is a standard Symfony controller that takes a Request
and returns a Response
. The controller must be an invokable class to be compatible with the component system.
The service must be given a name. This name will be used when referencing the component within a Twig template.
Once the component service is defined it can be rendered within any Photon template using the component()
Twig function.
Customising widgets
Defining the controller:
<?php
namespace Photon\CmsProject\Widget;
use Photon\CmsEngine\Model\PublishingContent\Homepage\HomepageWidget;
use Photon\Core\Controller\Widget;
use Symfony\Component\HttpFoundation\Response;
class ContentWidget extends Widget
{
/**
* @param HomepageWidget $widget
* @param bool $isPreview
*
* @return Response
*/
public function __invoke(HomepageWidget $widget, $isPreview = false)
{
if ($isPreview && empty($widget->getSettingValue('title')) && empty($widget->getSettingValue('content'))) {
return new Response('Please apply some settings to this widget.');
}
return $this->render('widgets/content.html.twig', [
'title' => $widget->getSettingValue('title'),
'content' => $widget->getSettingValue('content'),
]);
}
}
Defining the service:
photon_cms_project.widget.website_statistics:
class: Photon\CmsProject\Widget\WebsiteStatisticsWidget
parent: photon.controller.widget
arguments:
- '@photon_cms_engine.repository.website_statistics'
tags:
- { name: photon.widget, widget_id: 31 }
Widgets can be added in Photon by creating a controller class, registering the widget in the JaduHomepageWidgets
database table and defining a service tagged as photon.widget
and the id of the widget in the CMS database.
The controller class for a widget is a standard Symfony controller that takes a request and returns a response. The controller must be an invokable class to be compatible with the widget system.
The widget service must be tagged with photon.widget
and given an id. The id is used when the CMS identifies the controller to invoke, where a matching controller can not be found, the default widget controller is reverted to.
Customising supplements
<?xml version="1.0" encoding="utf-8"?>
<system xmlns:config="http://www.jadu.co.uk/schema/config">
<supplements config:type="array">
<item key="spacecraft-popular-pages">PopularPagesPageSupplementManager</item>
</supplements>
</system>
Supplements can be added in Photon by creating a manager class, administration interface file and associated class.
The new supplement class must be registered with the CMS in the database table JaduPageSupplements
. The supplement manager class must be registered in page_supplements.xml
.
Linking to theme assets
`{{ asset('images/info.png') }}`
This would generate a link to an image called
info.png
within the directoryResources/public/images/
Theme assets should be placed in a directory named public
in the Resources
directory of the bundle.
Theme assets can then be embedded in templates by calling the asset()
function.
Customising date format
Default date format in Photon is jS F Y
. This format can be changed by adding a date_format
value to the config.yml file.
- Main site:
{JADU_HOME}/config/frontend/config.yml
photon_core:
theme: base
fixture_set: base
date_format: Y-m-d
- Galaxies sites:
Can be configured per site in
{JADU_HOME}/config/galaxyms_jadudb_{SITE-ID}/config.yml
photon_core:
date_format: Y-m-d
{JADU_HOME}/config/galaxyms_jadudb_{SITE-ID}/config_prod.yml
:
yaml
imports:
- { resource: config.yml }
- Blogs:
All blogs follow the date format defined in the database JaduBlogs.dateFormat
, which is set to d/m/Y
by default.
If no value is set in the database, the default jS F Y
is used unless a value is defined in {JADU_HOME}/config/blog/config.yml
:
photon_core:
theme: blogbase
fixture_set: blogbase
date_format: Y-m-d
{JADU_HOME}/config/blog/config_prod.yml
:
imports:
- { resource: config.yml }
Troubleshooting
The site is complaining that the theme doesn't exist
This is commonly down to either the theme service not being defined within the theme bundle services.yml
, or the DependencyInjection folder and it's related files being missing from the theme bundle.
My template file isn't overriding the original template file
Generally this is down to differences in the path to the file. Double check that the files names match exactly, as this is case sensitive. Check that the directory path to the two templates is an exact match.