mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
first pass
This commit is contained in:
parent
0681567102
commit
16407b9185
@ -111,31 +111,37 @@ for a template file in the *simple/templates* folder, with the name `<PageType>`
|
||||
|
||||
Open *themes/simple/templates/Page.ss*. It uses standard HTML apart from these exceptions:
|
||||
|
||||
:::ss
|
||||
```ss
|
||||
<% base_tag %>
|
||||
```
|
||||
|
||||
The base_tag variable is replaced with the HTML [base element](http://www.w3.org/TR/html401/struct/links.html#h-12.4). This
|
||||
ensures the browser knows where to locate your site's images and css files.
|
||||
|
||||
:::ss
|
||||
```ss
|
||||
$Title
|
||||
$SiteConfig.Title
|
||||
```
|
||||
|
||||
These two variables are found within the html `<title>` tag, and are replaced by the "Page Name" and "Settings -> Site Title" fields in the CMS.
|
||||
|
||||
:::ss
|
||||
```ss
|
||||
$MetaTags
|
||||
```
|
||||
|
||||
The MetaTags variable will add meta tags, which are used by search engines. You can define your meta tags in the tab fields at the bottom of the content editor in the CMS.
|
||||
:::ss
|
||||
|
||||
```ss
|
||||
$Layout
|
||||
```
|
||||
|
||||
The Layout variable is replaced with the contents of a template file with the same name as the page type we are using.
|
||||
|
||||
Open *themes/simple/templates/Layout/Page.ss*. You will see more HTML and more SilverStripe template replacement tags and variables.
|
||||
|
||||
:::ss
|
||||
```ss
|
||||
$Content
|
||||
```
|
||||
|
||||
The Content variable is replaced with the content of the page currently being viewed. This allows you to make all changes to
|
||||
your site's content in the CMS.
|
||||
@ -144,9 +150,9 @@ These template markers are processed by SilverStripe into HTML before being sent
|
||||
browser and are either prefixed with a dollar sign ($)
|
||||
or placed between SilverStripe template tags:
|
||||
|
||||
:::ss
|
||||
```ss
|
||||
<% %>
|
||||
|
||||
```
|
||||
|
||||
**Flushing the cache**
|
||||
|
||||
@ -162,8 +168,9 @@ Open up *themes/simple/templates/Includes/Navigation.ss*
|
||||
|
||||
The Menu for our site is created using a **loop**. Loops allow us to iterate over a data set, and render each item using a sub-template.
|
||||
|
||||
:::ss
|
||||
```ss
|
||||
<% loop $Menu(1) %>
|
||||
```
|
||||
|
||||
returns a set of first level menu items. We can then use the template variable
|
||||
*$MenuTitle* to show the title of the page we are linking to, *$Link* for the URL of the page, and `$isSection` and `$isCurrent` to help style our menu with CSS (explained in more detail shortly).
|
||||
@ -171,7 +178,7 @@ returns a set of first level menu items. We can then use the template variable
|
||||
> *$Title* refers to **Page Name** in the CMS, whereas *$MenuTitle* refers to (the often shorter) **Navigation label**
|
||||
|
||||
|
||||
:::ss
|
||||
```ss
|
||||
<ul>
|
||||
<% loop $Menu(1) %>
|
||||
<li class="<% if $isCurrent %>current<% else_if $isSection %>section<% end_if %>">
|
||||
@ -179,6 +186,7 @@ returns a set of first level menu items. We can then use the template variable
|
||||
</li>
|
||||
<% end_loop %>
|
||||
</ul>
|
||||
```
|
||||
|
||||
Here we've created an unordered list called *Menu1*, which *themes/simple/css/layout.css* will style into the menu.
|
||||
Then, using a loop over the page control *Menu(1)*, we add a link to the list for each menu item.
|
||||
@ -195,15 +203,17 @@ A useful feature is highlighting the current page the user is looking at. We can
|
||||
|
||||
For example, if you were here: "Home > Company > Staff > Bob Smith", you may want to highlight 'Company' to say you are in that section.
|
||||
|
||||
:::ss
|
||||
```ss
|
||||
<li class="<% if $isCurrent %>current<% else_if $isSection %>section<% end_if %>">
|
||||
<a href="$Link" title="$Title.XML">$MenuTitle.XML</a>
|
||||
</li>
|
||||
```
|
||||
|
||||
you will then be able to target a section in css (*simple/css/layout.css*), e.g.:
|
||||
|
||||
:::css
|
||||
```css
|
||||
.section { background:#ccc; }
|
||||
```
|
||||
|
||||
## A second level of navigation
|
||||
|
||||
@ -224,7 +234,7 @@ Great, we now have a hierarchical site structure! Let's look at how this is crea
|
||||
|
||||
Adding a second level menu is very similar to adding the first level menu. Open up */themes/simple/templates/Includes/Sidebar.ss* template and look at the following code:
|
||||
|
||||
:::ss
|
||||
```ss
|
||||
<ul>
|
||||
<% loop $Menu(2) %>
|
||||
<li class="<% if $isCurrent %>current<% else_if $isSection %>section<% end_if %>">
|
||||
@ -235,6 +245,7 @@ Adding a second level menu is very similar to adding the first level menu. Open
|
||||
</li>
|
||||
<% end_loop %>
|
||||
</ul>
|
||||
```
|
||||
|
||||
This should look very familiar. It is the same idea as our first menu, except the loop block now uses *Menu(2)* instead of *Menu(1)*.
|
||||
As we can see here, the *Menu* control takes a single
|
||||
@ -245,7 +256,7 @@ To make sure the menu is not displayed on every page, for example, those that *d
|
||||
Look again in the *Sidebar.ss* file and you will see that the menu is surrounded with an **if block**
|
||||
like this:
|
||||
|
||||
:::ss
|
||||
```ss
|
||||
<% if $Menu(2) %>
|
||||
...
|
||||
<ul>
|
||||
@ -260,6 +271,7 @@ like this:
|
||||
</ul>
|
||||
...
|
||||
<% end_if %>
|
||||
```
|
||||
|
||||
The if block only includes the code inside it if the condition is true. In this case, it checks for the existence of
|
||||
*Menu(2)*. If it exists then the code inside will be processed and the menu will be shown. Otherwise the code will not
|
||||
@ -269,20 +281,22 @@ Now that we have two levels of navigation, it would also be useful to include so
|
||||
|
||||
Open up */themes/simple/templates/Includes/BreadCrumbs.ss* template and look at the following code:
|
||||
|
||||
:::ss
|
||||
```ss
|
||||
<% if $Level(2) %>
|
||||
<div id="Breadcrumbs">
|
||||
$Breadcrumbs
|
||||
</div>
|
||||
<% end_if %>
|
||||
```
|
||||
|
||||
Breadcrumbs are only useful on pages that aren't in the top level. We can ensure that we only show them if we aren't in
|
||||
the top level with another if statement.
|
||||
|
||||
The *Level* page control allows you to get data from the page's parents, e.g. if you used *Level(1)*, you could use:
|
||||
|
||||
:::ss
|
||||
```ss
|
||||
$Level(1).Title
|
||||
```
|
||||
|
||||
to get the top level page title. In this case, we merely use it to check the existence of a second level page: if one exists then we include breadcrumbs.
|
||||
|
||||
@ -294,7 +308,7 @@ Feel free to experiment with the if and loop statements. For example, you could
|
||||
|
||||
The following example runs an if statement and a loop on *Children*, checking to see if any sub-pages exist within each top level navigation item. You will need to come up with your own CSS to correctly style this approach.
|
||||
|
||||
:::ss
|
||||
```ss
|
||||
<ul>
|
||||
<% loop $Menu(1) %>
|
||||
<li class="<% if $isCurrent %>current<% else_if $isSection %>section<% end_if %>">
|
||||
@ -314,7 +328,7 @@ The following example runs an if statement and a loop on *Children*, checking to
|
||||
</li>
|
||||
<% end_loop %>
|
||||
</ul>
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Using a different template for the home page
|
||||
@ -379,21 +393,24 @@ It always tries to use the most specific template in an inheritance chain.
|
||||
To create a new template layout, create a copy of *Page.ss* (found in *themes/simple/templates/Layout*) and call it *HomePage.ss*. If we flush the cache (*?flush=1*), SilverStripe should now be using *HomePage.ss* for the homepage, and *Page.ss* for the rest of the site. Now let's customise the *HomePage* template.
|
||||
|
||||
First, we don't need the breadcrumbs and the secondary menu for the homepage. Let's remove them:
|
||||
:::ss
|
||||
|
||||
```ss
|
||||
<% include SideBar %>
|
||||
|
||||
```
|
||||
|
||||
We'll also replace the title text with an image. Find this line:
|
||||
|
||||
:::ss
|
||||
```ss
|
||||
<h1>$Title</h1>
|
||||
```
|
||||
|
||||
and replace it with:
|
||||
|
||||
:::ss
|
||||
```ss
|
||||
<div id="Banner">
|
||||
<img src="http://www.silverstripe.org/assets/SilverStripe-200.png" alt="Homepage image" />
|
||||
</div>
|
||||
|
||||
```
|
||||
|
||||
Your Home page should now look like this:
|
||||
|
||||
|
@ -49,7 +49,7 @@ presentation of our website.
|
||||
|
||||
### Controller
|
||||
|
||||
Each page type also has a **"controller"**. The controller contains all the code used to manipulate our data before it is rendered. For example, suppose we were making an auction site, and we only wanted to display the auctions closing in the next ten minutes. We would implement this logic in the controller. The controller for a page should inherit from [ContentController](api:SilverStripe\CMS\Controllers\ContentController). Just as we create a "Page" data object and subclass it for the rest of the site, we also create a "Page_Controller" that is subclassed.
|
||||
Each page type also has a **"controller"**. The controller contains all the code used to manipulate our data before it is rendered. For example, suppose we were making an auction site, and we only wanted to display the auctions closing in the next ten minutes. We would implement this logic in the controller. The controller for a page should inherit from [ContentController](api:SilverStripe\CMS\Controllers\ContentController). Just as we create a "Page" data object and subclass it for the rest of the site, we also create a "PageController" that is subclassed.
|
||||
|
||||
|
||||
Creating a new page type requires creating each of these three elements. We will then have full control over presentation, the database, and editable CMS fields.
|
||||
@ -63,16 +63,29 @@ A more in-depth introduction of Model-View-Controller can be found
|
||||
|
||||
To create a News section we'll need two new page types. The first one is obvious: we need an *ArticlePage* page type. The second is a little less obvious: we need an *ArticleHolder* page type to contain our article pages.
|
||||
|
||||
We'll start with the *ArticlePage* page type. First we create the model, a class called "ArticlePage". We put the *ArticlePage* class into a file called "ArticlePage.php" inside *mysite/code*. All other classes relating to *ArticlePage* should be placed within "ArticlePage.php", this includes our controller (*ArticlePage_Controller*).
|
||||
We'll start with the *ArticlePage* page type. First we create the model, a class called "ArticlePage". We put the *ArticlePage* class into a file called "ArticlePage.php" inside *mysite/code*. All other classes relating to *ArticlePage* should be placed within "ArticlePage.php", this includes our controller (*ArticlePageController*).
|
||||
|
||||
**mysite/code/ArticlePage.php**
|
||||
|
||||
:::php
|
||||
```php
|
||||
<?php
|
||||
class ArticlePage extends Page {
|
||||
use Page;
|
||||
|
||||
class ArticlePage extends Page
|
||||
{
|
||||
|
||||
}
|
||||
class ArticlePage_Controller extends Page_Controller {
|
||||
```
|
||||
**mysite/code/ArticlePageController.php**
|
||||
```php
|
||||
<?php
|
||||
use PageController;
|
||||
|
||||
class ArticlePageController extends PageController
|
||||
{
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
@ -83,14 +96,25 @@ Let's create the *ArticleHolder* page type.
|
||||
|
||||
**mysite/code/ArticleHolder.php**
|
||||
|
||||
:::php
|
||||
```php
|
||||
<?php
|
||||
class ArticleHolder extends Page {
|
||||
private static $allowed_children = array('ArticlePage');
|
||||
}
|
||||
class ArticleHolder_Controller extends Page_Controller {
|
||||
}
|
||||
use Page;
|
||||
|
||||
class ArticleHolder extends Page
|
||||
{
|
||||
private static $allowed_children = ['ArticlePage'];
|
||||
}
|
||||
```
|
||||
**mysite/code/ArticleHolderController.php**
|
||||
```php
|
||||
<?php
|
||||
use PageController;
|
||||
|
||||
class ArticleHolderController extends PageController
|
||||
{
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
Here we have done something interesting: the *$allowed_children* field. This is one of a number of static fields we can define to change the properties of a page type. The *$allowed_children* field is an array of page types that are allowed
|
||||
to be children of the page in the site tree. As we only want **news articles** in the news section, we only want pages of the type *ArticlePage* as children. We can enforce this in the CMS by setting the *$allowed_children* field within this class.
|
||||
@ -111,17 +135,20 @@ Now that we have an *ArticlePage* page type, let's make it a little more useful.
|
||||
the $db array to add extra fields to the database. It would be nice to know when each article was posted, and who posted
|
||||
it. Add a *$db* property definition in the *ArticlePage* class:
|
||||
|
||||
:::php
|
||||
```php
|
||||
<?php
|
||||
class ArticlePage extends Page {
|
||||
private static $db = array(
|
||||
use Page;
|
||||
|
||||
class ArticlePage extends Page
|
||||
{
|
||||
private static $db = [
|
||||
'Date' => 'Date',
|
||||
'Author' => 'Text'
|
||||
);
|
||||
];
|
||||
|
||||
// .....
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Every entry in the array is a *key => value* pair. The **key** is the name of the field, and the **value** is the type. See ["data types and casting"](/developer_guides/model/data_types_and_casting) for a complete list of types.
|
||||
|
||||
@ -134,12 +161,16 @@ When we rebuild the database, we will see that the *ArticlePage* table has been
|
||||
|
||||
To add our new fields to the CMS we have to override the *getCMSFields()* method, which is called by the CMS when it creates the form to edit a page. Add the method to the *ArticlePage* class.
|
||||
|
||||
:::php
|
||||
```php
|
||||
<?php
|
||||
class ArticlePage extends Page {
|
||||
use Page;
|
||||
|
||||
class ArticlePage extends Page
|
||||
{
|
||||
// ...
|
||||
|
||||
public function getCMSFields() {
|
||||
public function getCMSFields()
|
||||
{
|
||||
$fields = parent::getCMSFields();
|
||||
|
||||
$dateField = new DateField('Date');
|
||||
@ -153,20 +184,22 @@ To add our new fields to the CMS we have to override the *getCMSFields()* method
|
||||
|
||||
// ...
|
||||
|
||||
|
||||
```
|
||||
|
||||
Let's walk through this method.
|
||||
|
||||
:::php
|
||||
```php
|
||||
$fields = parent::getCMSFields();
|
||||
```
|
||||
|
||||
|
||||
Firstly, we get the fields from the parent class; we want to add fields, not replace them. The *$fields* variable
|
||||
returned is a [FieldList](api:SilverStripe\Forms\FieldList) object.
|
||||
|
||||
:::php
|
||||
```php
|
||||
$fields->addFieldToTab('Root.Main', new TextField('Author'), 'Content');
|
||||
$fields->addFieldToTab('Root.Main', new DateField('Date'), 'Content');
|
||||
```
|
||||
|
||||
|
||||
We can then add our new fields with *addFieldToTab*. The first argument is the tab on which we want to add the field to:
|
||||
@ -180,8 +213,9 @@ would create a new tab called "New Tab", and a single "Author" textfield inside.
|
||||
We have added two fields: A simple [TextField](api:SilverStripe\Forms\TextField) and a [DateField](api:SilverStripe\Forms\DateField).
|
||||
There are many more fields available in the default installation, listed in ["form field types"](/developer_guides/forms/field_types/common_subclasses).
|
||||
|
||||
:::php
|
||||
```php
|
||||
return $fields;
|
||||
```
|
||||
|
||||
|
||||
Finally, we return the fields to the CMS. If we flush the cache (by adding ?flush=1 at the end of the URL), we will be able to edit the fields in the CMS.
|
||||
@ -198,44 +232,53 @@ This makes it confusing and doesn't give the user much help when adding a date.
|
||||
To make the date field a bit more user friendly, you can add a dropdown calendar, set the date format and add a better title. By default,
|
||||
the date field will have the date format defined by your locale.
|
||||
|
||||
:::php
|
||||
```php
|
||||
<?php
|
||||
class ArticlePage extends Page {
|
||||
|
||||
// .....
|
||||
|
||||
public function getCMSFields() {
|
||||
$fields = parent::getCMSFields();
|
||||
|
||||
$dateField = new DateField('Date', 'Article Date (for example: 20/12/2010)');
|
||||
$dateField->setConfig('showcalendar', true);
|
||||
$dateField->setConfig('dateformat', 'dd/MM/YYYY');
|
||||
|
||||
$fields->addFieldToTab('Root.Main', $dateField, 'Content');
|
||||
$fields->addFieldToTab('Root.Main', new TextField('Author', 'Author Name'), 'Content');
|
||||
use Page;
|
||||
|
||||
return $fields;
|
||||
}
|
||||
class ArticlePage extends Page
|
||||
{
|
||||
|
||||
// .....
|
||||
|
||||
public function getCMSFields()
|
||||
{
|
||||
$fields = parent::getCMSFields();
|
||||
|
||||
$dateField = new DateField('Date', 'Article Date (for example: 20/12/2010)');
|
||||
$dateField->setConfig('showcalendar', true);
|
||||
$dateField->setConfig('dateformat', 'dd/MM/YYYY');
|
||||
|
||||
$fields->addFieldToTab('Root.Main', $dateField, 'Content');
|
||||
$fields->addFieldToTab('Root.Main', new TextField('Author', 'Author Name'), 'Content');
|
||||
|
||||
return $fields;
|
||||
}
|
||||
```
|
||||
|
||||
Let's walk through these changes.
|
||||
|
||||
:::php
|
||||
```php
|
||||
$dateField = new DateField('Date', 'Article Date (for example: 20/12/2010)');
|
||||
```
|
||||
|
||||
*$dateField* is declared in order to change the configuration of the DateField.
|
||||
|
||||
:::php
|
||||
```php
|
||||
$dateField->setConfig('showcalendar', true);
|
||||
```
|
||||
|
||||
By enabling *showCalendar* you show a calendar overlay when clicking on the field.
|
||||
|
||||
:::php
|
||||
```php
|
||||
$dateField->setConfig('dateformat', 'dd/MM/YYYY');
|
||||
```
|
||||
|
||||
*dateFormat* allows you to specify how you wish the date to be entered and displayed in the CMS field. See the [DBDateField](api:SilverStripe\ORM\FieldType\DBDateField) documentation for more configuration options.
|
||||
|
||||
:::php
|
||||
```php
|
||||
$fields->addFieldToTab('Root.Main', new TextField('Author', 'Author Name'), 'Content');
|
||||
```
|
||||
|
||||
By default the field name *'Date'* or *'Author'* is shown as the title, however this might not be that helpful so to change the title, add the new title as the second argument.
|
||||
|
||||
@ -250,7 +293,7 @@ page layout.
|
||||
### ArticlePage Template
|
||||
First, the template for displaying a single article:
|
||||
|
||||
**themes/simple/templates/Layout/ArticlePage.ss**
|
||||
**themes/simple/templates/Layout/ArticlePage.ss**
|
||||
|
||||
|
||||
:::ss
|
||||
@ -363,30 +406,31 @@ Note: The `news-file` icon may not exist in a default SilverStripe installation.
|
||||
|
||||
## Showing the latest news on the homepage
|
||||
|
||||
It would be nice to greet page visitors with a summary of the latest news when they visit the homepage. This requires a little more code though - the news articles are not direct children of the homepage, so we can't use the *Children* control. We can get the data for news articles by implementing our own function in *HomePage_Controller*.
|
||||
It would be nice to greet page visitors with a summary of the latest news when they visit the homepage. This requires a little more code though - the news articles are not direct children of the homepage, so we can't use the *Children* control. We can get the data for news articles by implementing our own function in *HomePageController*.
|
||||
|
||||
**mysite/code/HomePage.php**
|
||||
|
||||
:::php
|
||||
```php
|
||||
// ...
|
||||
public function LatestNews($num=5) {
|
||||
public function LatestNews($num=5)
|
||||
{
|
||||
$holder = ArticleHolder::get()->First();
|
||||
return ($holder) ? ArticlePage::get()->filter('ParentID', $holder->ID)->sort('Date DESC')->limit($num) : false;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
This function simply runs a database query that gets the latest news articles from the database. By default, this is five, but you can change it by passing a number to the function. See the [Data Model and ORM](/developer_guides/model/data_model_and_orm) documentation for details. We can reference this function as a page control in our *HomePage* template:
|
||||
|
||||
**themes/simple/templates/Layout/Homepage.ss**
|
||||
|
||||
:::ss
|
||||
```ss
|
||||
<!-- ... -->
|
||||
<div class="content">$Content</div>
|
||||
</article>
|
||||
<% loop $LatestNews %>
|
||||
<% include ArticleTeaser %>
|
||||
<% end_loop %>
|
||||
|
||||
```
|
||||
|
||||
When SilverStripe comes across a variable or page control it doesn't recognize, it first passes control to the controller. If the controller doesn't have a function for the variable or page control, it then passes control to the data object. If it has no matching functions, it then searches its database fields. Failing that it will return nothing.
|
||||
|
||||
@ -398,23 +442,24 @@ The controller for a page is only created when page is actually visited, while t
|
||||
|
||||
## Creating a RSS feed
|
||||
|
||||
An RSS feed is something that no news section should be without. SilverStripe makes it easy to create RSS feeds by providing an [RSSFeed](api:SilverStripe\Control\RSS\RSSFeed) class to do all the hard work for us. Add the following in the *ArticleHolder_Controller* class:
|
||||
An RSS feed is something that no news section should be without. SilverStripe makes it easy to create RSS feeds by providing an [RSSFeed](api:SilverStripe\Control\RSS\RSSFeed) class to do all the hard work for us. Add the following in the *ArticleHolderController* class:
|
||||
|
||||
**mysite/code/ArticleHolder.php**
|
||||
|
||||
:::php
|
||||
private static $allowed_actions = array(
|
||||
```php
|
||||
private static $allowed_actions = [
|
||||
'rss'
|
||||
);
|
||||
];
|
||||
|
||||
public function rss() {
|
||||
public function rss()
|
||||
{
|
||||
$rss = new RSSFeed($this->Children(), $this->Link(), "The coolest news around");
|
||||
return $rss->outputToBrowser();
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Ensure that when you have input the code to implement an RSS feed; flush the webpage afterwards
|
||||
(add ?flush=all on the end of your URL). This is because allowed_actions has changed.
|
||||
(add `?flush=1` on the end of your URL). This is because `allowed_actions` has changed.
|
||||
|
||||
This function creates an RSS feed of all the news articles, and outputs it to the browser. If we go to [http://localhost/your_site_name/news/rss](http://localhost/your_site_name/news/rss) we should see our RSS feed. When there is more to a URL after a page's base URL, "rss" in this case, SilverStripe will call the function with that name on the controller if it exists.
|
||||
|
||||
@ -422,16 +467,17 @@ Depending on your browser, you should see something like the picture below. If y
|
||||
|
||||
![](../_images/tutorial2_rss-feed.jpg)
|
||||
|
||||
Now all we need is to let the user know that our RSS feed exists. Add this function to *ArticleHolder_Controller*:
|
||||
Now all we need is to let the user know that our RSS feed exists. Add this function to *ArticleHolderController*:
|
||||
|
||||
**mysite/code/ArticleHolder.php**
|
||||
|
||||
:::php
|
||||
public function init() {
|
||||
```php
|
||||
public function init()
|
||||
{
|
||||
RSSFeed::linkToFeed($this->Link() . "rss");
|
||||
parent::init();
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
This automatically generates a link-tag in the header of our template. The *init* function is then called on the parent class to ensure any initialization the parent would have done if we hadn't overridden the *init* function is still called. Depending on your browser, you can see the RSS feed link in the address bar.
|
||||
|
||||
@ -441,34 +487,49 @@ Now that we have a complete news section, let's take a look at the staff section
|
||||
|
||||
**mysite/code/StaffHolder.php**
|
||||
|
||||
:::php
|
||||
```php
|
||||
<?php
|
||||
|
||||
class StaffHolder extends Page {
|
||||
private static $db = array();
|
||||
private static $has_one = array();
|
||||
private static $allowed_children = array('StaffPage');
|
||||
use Page;
|
||||
|
||||
class StaffHolder extends Page
|
||||
{
|
||||
private static $db = [];
|
||||
private static $has_one = [];
|
||||
private static $allowed_children = [StaffPage::class];
|
||||
}
|
||||
|
||||
class StaffHolder_Controller extends Page_Controller {
|
||||
```
|
||||
|
||||
**mysite/code/StaffHolderController.php**
|
||||
|
||||
```php
|
||||
<?php
|
||||
use PageController;
|
||||
|
||||
class StaffHolderController extends PageController
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Nothing here should be new. The *StaffPage* page type is more interesting though. Each staff member has a portrait image. We want to make a permanent connection between this image and the specific *StaffPage* (otherwise we could simply insert an image in the *$Content* field).
|
||||
|
||||
**mysite/code/StaffPage.php**
|
||||
|
||||
:::php
|
||||
```php
|
||||
<?php
|
||||
class StaffPage extends Page {
|
||||
private static $db = array(
|
||||
);
|
||||
private static $has_one = array(
|
||||
'Photo' => 'Image'
|
||||
);
|
||||
use SilverStripe\AssetAdmin\Forms\UploadField;
|
||||
use SilverStripe\Assets\Image;
|
||||
|
||||
class StaffPage extends Page
|
||||
{
|
||||
private static $db = [];
|
||||
|
||||
private static $has_one = [
|
||||
'Photo' => Image::class
|
||||
];
|
||||
|
||||
public function getCMSFields() {
|
||||
public function getCMSFields()
|
||||
{
|
||||
$fields = parent::getCMSFields();
|
||||
|
||||
$fields->addFieldToTab("Root.Images", new UploadField('Photo'));
|
||||
@ -476,10 +537,19 @@ Nothing here should be new. The *StaffPage* page type is more interesting though
|
||||
return $fields;
|
||||
}
|
||||
}
|
||||
|
||||
class StaffPage_Controller extends Page_Controller {
|
||||
}
|
||||
```
|
||||
|
||||
**mysite/code/StaffPageController.php**
|
||||
|
||||
```php
|
||||
<?php
|
||||
use PageController;
|
||||
|
||||
class StaffPageController extends PageController
|
||||
{
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
Instead of adding our *Image* as a field in *$db*, we have used the *$has_one* array. This is because an *Image* is not a simple database field like all the fields we have seen so far, but has its own database table. By using the *$has_one* array, we create a relationship between the *StaffPage* table and the *Image* table by storing the id of the respective *Image* in the *StaffPage* table.
|
||||
|
||||
@ -501,7 +571,7 @@ The staff section templates aren't too difficult to create, thanks to the utilit
|
||||
|
||||
**themes/simple/templates/Layout/StaffHolder.ss**
|
||||
|
||||
:::ss
|
||||
```ss
|
||||
<% include SideBar %>
|
||||
<div class="content-container unit size3of4 lastUnit">
|
||||
<article>
|
||||
@ -520,6 +590,7 @@ The staff section templates aren't too difficult to create, thanks to the utilit
|
||||
$Form
|
||||
</div>
|
||||
|
||||
```
|
||||
|
||||
This template is very similar to the *ArticleHolder* template. The *ScaleWidth* method of the [Image](api:SilverStripe\Assets\Image) class
|
||||
will resize the image before sending it to the browser. The resized image is cached, so the server doesn't have to
|
||||
@ -531,7 +602,7 @@ The *StaffPage* template is also very straight forward.
|
||||
|
||||
**themes/simple/templates/Layout/StaffPage.ss**
|
||||
|
||||
:::ss
|
||||
```ss
|
||||
<% include SideBar %>
|
||||
<div class="content-container unit size3of4 lastUnit">
|
||||
<article>
|
||||
@ -542,6 +613,7 @@ The *StaffPage* template is also very straight forward.
|
||||
</article>
|
||||
$Form
|
||||
</div>
|
||||
```
|
||||
|
||||
Here we use the *ScaleWidth* method to get a different sized image from the same source image. You should now have
|
||||
a complete staff section.
|
||||
|
@ -18,8 +18,9 @@ We are going to add a search box on the top of the page. When a user types somet
|
||||
To enable the search engine you need to include the following code in your `mysite/_config.php` file.
|
||||
This will enable fulltext search on page content as well as names of all files in the `/assets` folder.
|
||||
|
||||
:::php
|
||||
```php
|
||||
FulltextSearchable::enable();
|
||||
```
|
||||
|
||||
After including that in your `_config.php` you will need to rebuild the database by visiting [http://localhost/your_site_name/dev/build](http://localhost/your_site_name/dev/build) in your web browser (replace localhost/your_site_name with a domain if applicable). This will add fulltext search columns.
|
||||
|
||||
@ -34,7 +35,7 @@ To add the search form, we can add `$SearchForm` anywhere in our templates. In t
|
||||
|
||||
**themes/simple/templates/Includes/Header.ss**
|
||||
|
||||
:::ss
|
||||
```ss
|
||||
...
|
||||
<% if $SearchForm %>
|
||||
<span class="search-dropdown-icon">L</span>
|
||||
@ -43,6 +44,7 @@ To add the search form, we can add `$SearchForm` anywhere in our templates. In t
|
||||
</div>
|
||||
<% end_if %>
|
||||
<% include Navigation %>
|
||||
```
|
||||
|
||||
This displays as:
|
||||
|
||||
@ -55,11 +57,13 @@ is applied via `FulltextSearchable::enable()`
|
||||
|
||||
**cms/code/search/ContentControllerSearchExtension.php**
|
||||
|
||||
:::php
|
||||
class ContentControllerSearchExtension extends Extension {
|
||||
```php
|
||||
class ContentControllerSearchExtension extends Extension
|
||||
{
|
||||
...
|
||||
|
||||
function results($data, $form, $request) {
|
||||
public function results($data, $form, $request)
|
||||
{
|
||||
$data = array(
|
||||
'Results' => $form->getResults(),
|
||||
'Query' => $form->getSearchQuery(),
|
||||
@ -68,7 +72,7 @@ is applied via `FulltextSearchable::enable()`
|
||||
return $this->owner->customise($data)->renderWith(array('Page_results', 'Page'));
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
The code populates an array with the data we wish to pass to the template - the search results, query and title of the page. The final line is a little more complicated.
|
||||
|
||||
@ -97,7 +101,7 @@ class.
|
||||
|
||||
*themes/simple/templates/Layout/Page_results.ss*
|
||||
|
||||
:::ss
|
||||
```ss
|
||||
<div id="Content" class="searchResults">
|
||||
<h1>$Title</h1>
|
||||
|
||||
@ -148,6 +152,7 @@ class.
|
||||
</div>
|
||||
<% end_if %>
|
||||
</div>
|
||||
```
|
||||
|
||||
Then finally add ?flush=1 to the URL and you should see the new template.
|
||||
|
||||
|
@ -9,24 +9,26 @@ object!
|
||||
|
||||
A simple example is to set a field to the current date and time:
|
||||
|
||||
:::php
|
||||
```php
|
||||
/**
|
||||
* Sets the Date field to the current date.
|
||||
*/
|
||||
public function populateDefaults() {
|
||||
public function populateDefaults()
|
||||
{
|
||||
$this->Date = date('Y-m-d');
|
||||
parent::populateDefaults();
|
||||
}
|
||||
|
||||
```
|
||||
It's also possible to get the data from any other source, or another object, just by using the usual data retrieval
|
||||
methods. For example:
|
||||
|
||||
:::php
|
||||
```php
|
||||
/**
|
||||
* This method combines the Title of the parent object with the Title of this
|
||||
* object in the FullTitle field.
|
||||
*/
|
||||
public function populateDefaults() {
|
||||
public function populateDefaults()
|
||||
{
|
||||
if($parent = $this->Parent()) {
|
||||
$this->FullTitle = $parent->Title . ': ' . $this->Title;
|
||||
} else {
|
||||
@ -34,3 +36,4 @@ methods. For example:
|
||||
}
|
||||
parent::populateDefaults();
|
||||
}
|
||||
```
|
@ -34,8 +34,11 @@ The first step is to set up the basic data model,
|
||||
along with a method that returns the first letter of the title. This
|
||||
will be used both for grouping and for the title in the template.
|
||||
|
||||
:::php
|
||||
class Module extends DataObject {
|
||||
```php
|
||||
use SilverStripe\ORM\DataObject;
|
||||
|
||||
class Module extends DataObject
|
||||
{
|
||||
private static $db = array(
|
||||
'Title' => 'Text'
|
||||
);
|
||||
@ -44,16 +47,22 @@ will be used both for grouping and for the title in the template.
|
||||
* Returns the first letter of the module title, used for grouping.
|
||||
* @return string
|
||||
*/
|
||||
public function getTitleFirstLetter() {
|
||||
public function getTitleFirstLetter()
|
||||
{
|
||||
return $this->Title[0];
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The next step is to create a method or variable that will contain/return all the objects,
|
||||
sorted by title. For this example this will be a method on the `Page` class.
|
||||
|
||||
:::php
|
||||
class Page extends SiteTree {
|
||||
```php
|
||||
use SilverStripe\CMS\Model\SiteTree;
|
||||
use SilverStripe\ORM\GroupedList;
|
||||
|
||||
class Page extends SiteTree
|
||||
{
|
||||
|
||||
// ...
|
||||
|
||||
@ -61,17 +70,19 @@ sorted by title. For this example this will be a method on the `Page` class.
|
||||
* Returns all modules, sorted by their title.
|
||||
* @return GroupedList
|
||||
*/
|
||||
public function getGroupedModules() {
|
||||
public function getGroupedModules()
|
||||
{
|
||||
return GroupedList::create(Module::get()->sort('Title'));
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
The final step is to render this into a template. The `GroupedBy()` method breaks up the set into
|
||||
a number of sets, grouped by the field that is passed as the parameter.
|
||||
In this case, the `getTitleFirstLetter()` method defined earlier is used to break them up.
|
||||
|
||||
:::ss
|
||||
```ss
|
||||
<%-- Modules list grouped by TitleFirstLetter --%>
|
||||
<h2>Modules</h2>
|
||||
<% loop $GroupedModules.GroupedBy(TitleFirstLetter) %>
|
||||
@ -82,6 +93,7 @@ In this case, the `getTitleFirstLetter()` method defined earlier is used to brea
|
||||
<% end_loop %>
|
||||
</ul>
|
||||
<% end_loop %>
|
||||
```
|
||||
|
||||
## Grouping Sets By Month
|
||||
|
||||
@ -95,8 +107,11 @@ but grouping by its built-in `Created` property instead,
|
||||
which is automatically set when the record is first written to the database.
|
||||
This will have a method which returns the month it was posted in:
|
||||
|
||||
:::php
|
||||
class Module extends DataObject {
|
||||
```php
|
||||
use SilverStripe\ORM\DataObject;
|
||||
|
||||
class Module extends DataObject
|
||||
{
|
||||
|
||||
// ...
|
||||
|
||||
@ -104,17 +119,23 @@ This will have a method which returns the month it was posted in:
|
||||
* Returns the month name this news item was posted in.
|
||||
* @return string
|
||||
*/
|
||||
public function getMonthCreated() {
|
||||
public function getMonthCreated()
|
||||
{
|
||||
return date('F', strtotime($this->Created));
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
The next step is to create a method that will return all records that exist,
|
||||
sorted by month name from January to December. This can be accomplshed by sorting by the `Created` field:
|
||||
|
||||
:::php
|
||||
class Page extends SiteTree {
|
||||
```php
|
||||
use SilverStripe\CMS\Model\SiteTree;
|
||||
use SilverStripe\ORM\GroupedList;
|
||||
|
||||
class Page extends SiteTree
|
||||
{
|
||||
|
||||
// ...
|
||||
|
||||
@ -122,15 +143,16 @@ sorted by month name from January to December. This can be accomplshed by sortin
|
||||
* Returns all news items, sorted by the month they were posted
|
||||
* @return GroupedList
|
||||
*/
|
||||
public function getGroupedModulesByDate() {
|
||||
public function getGroupedModulesByDate()
|
||||
{
|
||||
return GroupedList::create(Module::get()->sort('Created'));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
The final step is the render this into the template using the [GroupedList::GroupedBy()](api:SilverStripe\ORM\GroupedList::GroupedBy()) method.
|
||||
|
||||
:::ss
|
||||
```ss
|
||||
// Modules list grouped by the Month Posted
|
||||
<h2>Modules</h2>
|
||||
<% loop $GroupedModulesByDate.GroupedBy(MonthCreated) %>
|
||||
@ -141,7 +163,7 @@ The final step is the render this into the template using the [GroupedList::Grou
|
||||
<% end_loop %>
|
||||
</ul>
|
||||
<% end_loop %>
|
||||
|
||||
```
|
||||
## Related
|
||||
|
||||
* [Howto: "Pagination"](/developer_guides/templates/how_tos/pagination)
|
||||
|
Loading…
Reference in New Issue
Block a user