Add introduction files to each of the sections

This commit is contained in:
Will Rossiter 2014-09-21 12:07:58 +12:00 committed by Cam Findlay
parent effefd5199
commit a506dfd42a
39 changed files with 396 additions and 417 deletions

View File

@ -1,8 +1,8 @@
# Requirements # Requirements
SilverStripe CMS needs to be installed on a web server. Content authors and website administrators use their web browser to access a web-based GUI to SilverStripe CMS needs to be installed on a web server. Content authors and website administrators use their web browser
do their day-to-day work. Website designers and developers require access to the files on the server to update templates, to access a web-based GUI to do their day-to-day work. Website designers and developers require access to the files on
website logic, and perform upgrades or maintainance. the server to update templates, website logic, and perform upgrades or maintenance.
Our web-based [PHP installer](/installation) can check if you meet the requirements listed below. Our web-based [PHP installer](/installation) can check if you meet the requirements listed below.
@ -36,14 +36,26 @@ Our web-based [PHP installer](/installation) can check if you meet the requireme
## Web server hardware requirements ## Web server hardware requirements
Hardware requirements vary widely depending on the traffic to your website, the complexity of its logic (i.e., PHP), and its size (i.e., database.) By default, all pages are dynamic, and thus access both the database and execute PHP code to generate. SilverStripe can cache full pages and segments of templates to dramatically increase performance. Hardware requirements vary widely depending on the traffic to your website, the complexity of its logic (i.e., PHP), and
its size (i.e., database.) By default, all pages are dynamic, and thus access both the database and execute PHP code to
generate. SilverStripe can cache full pages and segments of templates to dramatically increase performance.
A typical website page on a conservative single CPU machine (e.g., Intel 2Ghz) takes roughly 300ms to generate. This comfortably allows over a million page views per month. Caching and other optimisations can improve this by a factor of ten or even one hundred times. SilverStripe CMS can be used in multiple-server architectures to improve scalability and redundancy. A typical website page on a conservative single CPU machine (e.g., Intel 2Ghz) takes roughly 300ms to generate. This
comfortably allows over a million page views per month. Caching and other optimisations can improve this by a factor of
ten or even one hundred times. SilverStripe CMS can be used in multiple-server architectures to improve scalability and
redundancy.
For more information on how to scale SilverStripe see the [Performance](../../developer_guides/performance/) Gluide.
## Client side (CMS) requirements ## Client side (CMS) requirements
SilverStripe CMS is designed to work well with Google Chrome, Mozilla Firefox and Internet Explorer 8+. We aim to provide satisfactory experiences in Apple Safari. SilverStripe CMS works well across Windows, Linux, and Mac operating systems. SilverStripe CMS is designed to work well with Google Chrome, Mozilla Firefox and Internet Explorer 8+. We aim to
provide satisfactory experiences in Apple Safari. SilverStripe CMS works well across Windows, Linux, and Mac operating
systems.
## End user requirements ## ## End user requirements
SilverStripe CMS is designed to make excellent, standards-compliant websites that are compatible with a wide range of industry standard browsers and operating systems. A competent developer is able to produce websites that meet W3C guidelines for HTML, CSS, JavaScript, and accessibility, in addition to meeting specific guildelines, such as e-government requirements. SilverStripe CMS is designed to make excellent, standards-compliant websites that are compatible with a wide range of
industry standard browsers and operating systems. A competent developer is able to produce websites that meet W3C
guidelines for HTML, CSS, JavaScript, and accessibility, in addition to meeting specific guildelines, such as
e-government requirements.

View File

@ -1,15 +1,8 @@
# Installing SilverStripe title: Getting Started
introduction: SilverStripe is a web application. This means that you will need to have a webserver and database. We will take you through the setup of the server environment as well the application itself.
## Download
SilverStripe is a web application. This means that you will need to have a webserver and database meeting its ## Installing SilverStripe
[requirements](server-requirements). We will take you through the setup of the server environment as well the application itself.
<div markdown='1' style="float: right; margin-left: 20px">
![](../_images/composer.png)
</div>
## Getting the code
The best way to get SilverStripe is to [install with Composer](composer). Composer is a package management tool for PHP that The best way to get SilverStripe is to [install with Composer](composer). Composer is a package management tool for PHP that
lets you install and upgrade SilverStripe and its modules. Although installing Composer is one extra step, it will give you much more flexibility than just downloading the file from silverstripe.org. lets you install and upgrade SilverStripe and its modules. Although installing Composer is one extra step, it will give you much more flexibility than just downloading the file from silverstripe.org.

View File

@ -1,4 +1,7 @@
# Written Tutorials title: Tutorials
introduction: The tutorials below take a step by step look at how to build a SilverStripe application.
## Written Tutorials
* [Tutorial 1: Building a basic site](1-building-a-basic-site): An introduction to building a site with * [Tutorial 1: Building a basic site](1-building-a-basic-site): An introduction to building a site with
SilverStripe. SilverStripe.
@ -9,14 +12,14 @@ site".
* [Tutorial 5: Dataobject Relationship Management](5-dataobject-relationship-management): Learn how to create * [Tutorial 5: Dataobject Relationship Management](5-dataobject-relationship-management): Learn how to create
simple data relationships. simple data relationships.
# Video tutorials ## Video tutorials
* [Installing on Linux](http://silverstripe.org/assets/screencasts/Tutorial-InstallingLinux-DM08.swf) * [Installing on Linux](http://silverstripe.org/assets/screencasts/Tutorial-InstallingLinux-DM08.swf)
* [Installing on Mac OSX (using MAMP)](http://silverstripe.org/assets/screencasts/Tutorial-InstallingMAMP-SW08.swf) * [Installing on Mac OSX (using MAMP)](http://silverstripe.org/assets/screencasts/Tutorial-InstallingMAMP-SW08.swf)
* [Installing a module (e.g. a blog)](http://silverstripe.org/assets/screencasts/Tutorial-InstallingBlogModule-DM08.swf) * [Installing a module (e.g. a blog)](http://silverstripe.org/assets/screencasts/Tutorial-InstallingBlogModule-DM08.swf)
* [Customising the CMS (adding new fields)](http://silverstripe.org/assets/screencasts/Tutorial-ChangingFields-DM08.swf) * [Customising the CMS (adding new fields)](http://silverstripe.org/assets/screencasts/Tutorial-ChangingFields-DM08.swf)
# Help: If you get stuck ## Help: If you get stuck
* [Common Problems](/installation/common-problems): Review some existing solutions to common problems. * [Common Problems](/installation/common-problems): Review some existing solutions to common problems.
* [SilverStripe Forums](http://www.silverstripe.com/silverstripe-forum/): Head over to the forums and ask the community * [SilverStripe Forums](http://www.silverstripe.com/silverstripe-forum/): Head over to the forums and ask the community

View File

@ -0,0 +1,8 @@
title: Model and Databases
summary: Learn how SilverStripe manages database tables, ways to query your database and how to publish data.
[CHILDREN]
## How-to
[CHILDREN How_To]

View File

@ -1,9 +1,9 @@
# Building templates for page types # Building templates for page types
Much of your work building a SilverStripe site will involve the creation of Much of your work building a SilverStripe site will involve the creation of
templates for your own page types. SilverStripe has its own template language. templates for your own page types. SilverStripe has its own template language.
Its basic features like variables, blocks and loops are described in our ["templates" reference guide](/reference/templates). Its basic features like variables, blocks and loops are described in our ["templates" reference guide](/reference/templates).
In this guide, we'll show you specific uses for creating page layouts. In this guide, we'll show you specific uses for creating page layouts.
This assumes you are familiar with the concept of ["page types"](/topics/page-types). This assumes you are familiar with the concept of ["page types"](/topics/page-types).
To get a feel for what those templates look like, let's have a look at an abbreviated example. In your webroot, these templates are usually located in `themes/<your-theme>/templates`. To get a feel for what those templates look like, let's have a look at an abbreviated example. In your webroot, these templates are usually located in `themes/<your-theme>/templates`.
@ -24,21 +24,21 @@ Most of the magic happens in `Page.ss` and `Layout/Page.ss`.
<header> <header>
<h1>Bob's Chicken Shack</h1> <h1>Bob's Chicken Shack</h1>
</header> </header>
<navigation> <navigation>
<% if $Menu(1) %> <% if $Menu(1) %>
<ul> <ul>
<% loop $Menu(1) %> <% loop $Menu(1) %>
<li><a href="$Link" class="$LinkingMode">$MenuTitle</a></li> <li><a href="$Link" class="$LinkingMode">$MenuTitle</a></li>
<% end_loop %> <% end_loop %>
</ul> </ul>
<% end_if %> <% end_if %>
</navigation> </navigation>
<div class="typography"> <div class="typography">
$Layout $Layout
</div> </div>
</div> </div>
</body> </body>
</html> </html>
@ -85,7 +85,7 @@ and only preview draft content if explicitly requested (e.g. by the "preview" fe
`$Menu(1)` is a built-in page control that defines the top-level menu. `$Menu(1)` is a built-in page control that defines the top-level menu.
You can also create a sub-menu using `$Menu(2)`, and so forth. You can also create a sub-menu using `$Menu(2)`, and so forth.
The `<% loop $Menu(1) %>...<% end_loop %>` block defines a repeating element. The `<% loop $Menu(1) %>...<% end_loop %>` block defines a repeating element.
It will change the "scope" of your template, which means that all of the template variables you use inside it will refer to a menu item. The template code will be repeated once per menu item, with the scope set to that menu item's page. In this case, a menu item refers to an instance It will change the "scope" of your template, which means that all of the template variables you use inside it will refer to a menu item. The template code will be repeated once per menu item, with the scope set to that menu item's page. In this case, a menu item refers to an instance
of the `Page` class, so you can access all properties defined on there, for example `$Title`. of the `Page` class, so you can access all properties defined on there, for example `$Title`.
@ -116,13 +116,13 @@ underneath a "staff" holder on any page, regardless if its on the top level or e
This will show all children of a page even if the `ShowInMenus` property is set to FALSE. This will show all children of a page even if the `ShowInMenus` property is set to FALSE.
### Access to Parent and Level Pages ### Access to Parent and Level Pages
:::ss :::ss
<% with $Level(1) %> <% with $Level(1) %>
$Title $Title
<% end_with %> <% end_with %>
Will return a page in the current path, at the level specified by the numbers. Will return a page in the current path, at the level specified by the numbers.
It is based on the current page context, looking back through its parent pages. It is based on the current page context, looking back through its parent pages.
For example, imagine you're on the "bob marley" page, For example, imagine you're on the "bob marley" page,
@ -164,7 +164,7 @@ you can get an absolute one including the domain through [$AbsoluteLink](api:Sit
In addition, each menu item gets some context information relative In addition, each menu item gets some context information relative
to the page you're currently viewing, contained in the `$LinkingMode` placeholder. to the page you're currently viewing, contained in the `$LinkingMode` placeholder.
By setting a HTML class to this value, you can distinguish the styling of By setting a HTML class to this value, you can distinguish the styling of
the currently selected menu item. It can have the following values: the currently selected menu item. It can have the following values:
* `link`: You are neither on this page nor in this section. * `link`: You are neither on this page nor in this section.
@ -176,7 +176,7 @@ More common uses:
* `$LinkOrCurrent`: Determines if the item is the current page. Returns "link" or "current" strings. * `$LinkOrCurrent`: Determines if the item is the current page. Returns "link" or "current" strings.
* `$LinkOrSection`: Determines if the item is in the current section, so in the path towards the current page. Useful for menus which you only want to show a second level menu when you are on that page or a child of it. Returns "link" or "section" strings. * `$LinkOrSection`: Determines if the item is in the current section, so in the path towards the current page. Useful for menus which you only want to show a second level menu when you are on that page or a child of it. Returns "link" or "section" strings.
* `InSection(page-url)`: This if block will pass if we're currently on the page-url page or one of its children. * `InSection(page-url)`: This if block will pass if we're currently on the page-url page or one of its children.
Example: Only show the menu item linked if its the current one: Example: Only show the menu item linked if its the current one:
:::ss :::ss
@ -237,13 +237,13 @@ By default `$MetaTags` renders:
#### URLSegment #### URLSegment
This returns the part of the URL of the page you're currently on. This returns the part of the URL of the page you're currently on.
Shouldn't be used for linking to a page, since the link Shouldn't be used for linking to a page, since the link
is a composite value based on all parent pages as well (through the `$Link` variable). is a composite value based on all parent pages as well (through the `$Link` variable).
#### ClassName #### ClassName
Returns the class of the underlying `Page` record. Returns the class of the underlying `Page` record.
This can be handy to add to your `<body>` tag to influence This can be handy to add to your `<body>` tag to influence
CSS styles and JavaScript behaviour based on the page type used: CSS styles and JavaScript behaviour based on the page type used:
@ -255,7 +255,7 @@ use the `$CSSClasses` placeholder instead.
#### BaseHref #### BaseHref
Returns the base URL for the current site. Returns the base URL for the current site.
This is used to populate the `<base>` tag by default. This is used to populate the `<base>` tag by default.
Can be handy to prefix custom links (not generated through `SiteTree->Link()`), Can be handy to prefix custom links (not generated through `SiteTree->Link()`),
to ensure they work correctly when the webroot is hosted in a subfolder to ensure they work correctly when the webroot is hosted in a subfolder

View File

@ -21,19 +21,19 @@ Here is a very simple template:
<header> <header>
<h1>Bob's Chicken Shack</h1> <h1>Bob's Chicken Shack</h1>
</header> </header>
<% with $CurrentMember %> <% with $CurrentMember %>
<p>Welcome $FirstName $Surname.</p> <p>Welcome $FirstName $Surname.</p>
<% end_with %> <% end_with %>
<% if $Dishes %> <% if $Dishes %>
<ul> <ul>
<% loop $Dishes %> <% loop $Dishes %>
<li>$Title ($Price.Nice)</li> <li>$Title ($Price.Nice)</li>
<% end_loop %> <% end_loop %>
</ul> </ul>
<% end_if %> <% end_if %>
<% include Footer %> <% include Footer %>
</body> </body>
</html> </html>
@ -131,7 +131,7 @@ See [CSS](/topics/css) and [Javascript](/topics/javascript) topics for individua
## Conditional Logic ## Conditional Logic
You can conditionally include markup in the output. That is, test for something You can conditionally include markup in the output. That is, test for something
that is true or false, and based on that test, control what gets output. that is true or false, and based on that test, control what gets output.
The simplest if block is to check for the presence of a value. The simplest if block is to check for the presence of a value.
@ -141,8 +141,8 @@ The simplest if block is to check for the presence of a value.
<p>You are logged in as $CurrentMember.FirstName $CurrentMember.Surname.</p> <p>You are logged in as $CurrentMember.FirstName $CurrentMember.Surname.</p>
<% end_if %> <% end_if %>
The following compares a page property called `MyDinner` with the value in The following compares a page property called `MyDinner` with the value in
quotes, `kipper`, which is a **literal**. If true, the text inside the if-block quotes, `kipper`, which is a **literal**. If true, the text inside the if-block
is output. is output.
:::ss :::ss
@ -150,12 +150,12 @@ is output.
Yummy, kipper for tea. Yummy, kipper for tea.
<% end_if %> <% end_if %>
Note that inside a tag like this, variables should have a '$' prefix, and Note that inside a tag like this, variables should have a '$' prefix, and
literals should have quotes. SilverStripe 2.4 didn't include the quotes or $ literals should have quotes. SilverStripe 2.4 didn't include the quotes or $
prefix, and while this still works, we recommend the new syntax as it is less prefix, and while this still works, we recommend the new syntax as it is less
ambiguous. ambiguous.
This example shows the use of the `else` option. The markup after `else` is This example shows the use of the `else` option. The markup after `else` is
output if the tested condition is *not* true. output if the tested condition is *not* true.
:::ss :::ss
@ -165,9 +165,9 @@ output if the tested condition is *not* true.
I wish I could have kipper :-( I wish I could have kipper :-(
<% end_if %> <% end_if %>
This example shows the user of `else_if`. There can be any number of `else_if` This example shows the user of `else_if`. There can be any number of `else_if`
clauses. The conditions are tested from first to last, until one of them is true, clauses. The conditions are tested from first to last, until one of them is true,
and the markup for that condition is used. If none of the conditions are true, and the markup for that condition is used. If none of the conditions are true,
the markup in the `else` clause is used, if that clause is present. the markup in the `else` clause is used, if that clause is present.
:::ss :::ss
@ -186,7 +186,7 @@ This example shows the use of `not` to negate the test.
I'm going out for dinner tonight. I'm going out for dinner tonight.
<% end_if %> <% end_if %>
You can combine two or more conditions with `||` ("or"). The markup is used if You can combine two or more conditions with `||` ("or"). The markup is used if
*either* of the conditions is true. *either* of the conditions is true.
:::ss :::ss
@ -194,7 +194,7 @@ You can combine two or more conditions with `||` ("or"). The markup is used if
yummy, fish for tea yummy, fish for tea
<% end_if %> <% end_if %>
You can combine two or more conditions with `&&` ("and"). The markup is used if You can combine two or more conditions with `&&` ("and"). The markup is used if
*both* of the conditions are true. *both* of the conditions are true.
:::ss :::ss
@ -211,7 +211,7 @@ You can use inequalities like `<`, `<=`, `>`, `>=` to compare numbers.
## Looping Over Lists ## Looping Over Lists
The `<% loop %>...<% end_loop %>` tag is used to **iterate** or loop over a The `<% loop %>...<% end_loop %>` tag is used to **iterate** or loop over a
collection of items. For example: collection of items. For example:
:::ss :::ss
@ -235,7 +235,7 @@ with.
### Position Indicators ### Position Indicators
Inside the loop scope, there are many variables at your disposal to determine the Inside the loop scope, there are many variables at your disposal to determine the
current position in the list and iteration: current position in the list and iteration:
* `$Even`, `$Odd`: Returns boolean, handy for zebra striping * `$Even`, `$Odd`: Returns boolean, handy for zebra striping
@ -297,8 +297,8 @@ $Modulus and $MultipleOf can help to build column layouts.
$Modulus(value, offset) // returns an int $Modulus(value, offset) // returns an int
$MultipleOf(factor, offset) // returns a boolean. $MultipleOf(factor, offset) // returns a boolean.
The following example demonstrates how you can use $Modulus(4) to generate The following example demonstrates how you can use $Modulus(4) to generate
custom column names based on your loop statement. Note that this works for any custom column names based on your loop statement. Note that this works for any
control statement (not just children). control statement (not just children).
:::ss :::ss
@ -308,10 +308,10 @@ control statement (not just children).
</div> </div>
<% end_loop %> <% end_loop %>
Will return you column-3, column-2, column-1, column-0, column-3 etc. You can Will return you column-3, column-2, column-1, column-0, column-3 etc. You can
use these as styling hooks to float, position as you need. use these as styling hooks to float, position as you need.
You can also use $MultipleOf(value, offset) to help build columned layouts. In You can also use $MultipleOf(value, offset) to help build columned layouts. In
this case we want to add a <br> after every 3th item. this case we want to add a <br> after every 3th item.
:::ss :::ss
@ -323,17 +323,17 @@ this case we want to add a <br> after every 3th item.
## Scope ## Scope
In the `<% loop %>` section, we saw an example of two **scopes**. Outside the In the `<% loop %>` section, we saw an example of two **scopes**. Outside the
`<% loop %>...<% end_loop %>`, we were in the scope of the page. But inside the `<% loop %>...<% end_loop %>`, we were in the scope of the page. But inside the
loop, we were in the scope of an item in the list. The scope determines where loop, we were in the scope of an item in the list. The scope determines where
the value comes from when you refer to a variable. Typically the outer scope of the value comes from when you refer to a variable. Typically the outer scope of
a page type's layout template is the page that is currently being rendered. a page type's layout template is the page that is currently being rendered.
The outer scope of an included template is the scope that it was included into. The outer scope of an included template is the scope that it was included into.
### Up ### Up
When we are in a scope, we sometimes want to refer to the scope outside the When we are in a scope, we sometimes want to refer to the scope outside the
<% loop %> or <% with %>. We can do that easily by using `$Up`. `$Up` takes <% loop %> or <% with %>. We can do that easily by using `$Up`. `$Up` takes
the scope back to the previous level. Take the following example: the scope back to the previous level. Take the following example:
:::ss :::ss
@ -349,7 +349,7 @@ the scope back to the previous level. Take the following example:
<% end_loop %> <% end_loop %>
<% end_loop %> <% end_loop %>
With a page structure (Blog -> Blog entry -> Child blog entry) the With a page structure (Blog -> Blog entry -> Child blog entry) the
above will produce: above will produce:
:::ss :::ss
@ -364,8 +364,8 @@ above will produce:
### Top ### Top
While `$Up` provides us a way to go up 1 scope, `$Top` is a shortcut to jump to While `$Up` provides us a way to go up 1 scope, `$Top` is a shortcut to jump to
the top most scope of the page. Using the previous example but expanded to the top most scope of the page. Using the previous example but expanded to
include `$Top`: include `$Top`:
:::ss :::ss
@ -393,12 +393,12 @@ Will produce
Blog Blog
-- --
Child blog entry Child blog entry
Blog entry Blog entry
Blog Blog
### With ### With
The `<% with %>...<% end_with %>` tag lets you introduce a new scope. Consider The `<% with %>...<% end_with %>` tag lets you introduce a new scope. Consider
the following example: the following example:
:::ss :::ss
@ -407,13 +407,13 @@ the following example:
<% end_with %> <% end_with %>
Outside the `<% with %>...<% end_with %>`, we are in the page scope. Inside it, Outside the `<% with %>...<% end_with %>`, we are in the page scope. Inside it,
we are in the scope of `$CurrentMember`. We can refer directly to properties and we are in the scope of `$CurrentMember`. We can refer directly to properties and
methods of that member. So $FirstName is equivalent to $CurrentMember.FirstName. methods of that member. So $FirstName is equivalent to $CurrentMember.FirstName.
This keeps the markup clean, and if the scope is a complicated expression we don't This keeps the markup clean, and if the scope is a complicated expression we don't
have to repeat it on each reference of a property. have to repeat it on each reference of a property.
`<% with %>` also lets us use a collection as a scope, so we can access `<% with %>` also lets us use a collection as a scope, so we can access
properties of the collection itself, instead of iterating over it. For example: properties of the collection itself, instead of iterating over it. For example:
:::ss :::ss
@ -423,8 +423,8 @@ returns the number of items in the $Children collection.
## Pagination ## Pagination
Lists can be paginated, and looped over to generate pagination. For this to Lists can be paginated, and looped over to generate pagination. For this to
work, the list needs to be wrapped in a `[api:PaginatedList]`. The process is work, the list needs to be wrapped in a `[api:PaginatedList]`. The process is
explained in detail on the ["pagination" howto](/howto/pagination). explained in detail on the ["pagination" howto](/howto/pagination).
The list is split up in multiple "pages", each . Note that "page" is this context The list is split up in multiple "pages", each . Note that "page" is this context
@ -457,7 +457,7 @@ which is of this type. It forces the content into an explicitly escaped format.
Apart from value formatting, there's many methods to transform them as well, Apart from value formatting, there's many methods to transform them as well,
For example, the built in `$Now` placeholder is an instance of `[api:Date]`, For example, the built in `$Now` placeholder is an instance of `[api:Date]`,
and returns the current date in a standard system format. and returns the current date in a standard system format.
Since its an object, you can use the helper methods to return other formats: Since its an object, you can use the helper methods to return other formats:
:::ss :::ss
@ -481,7 +481,7 @@ Pulling apart this example we see:
## Comments ## Comments
Using standard HTML comments is supported. These comments will be included in the published site. Using standard HTML comments is supported. These comments will be included in the published site.
:::ss :::ss
$EditForm <!-- Some public comment about the form --> $EditForm <!-- Some public comment about the form -->
@ -507,10 +507,10 @@ It renders in the template as `<base href="http://www.mydomain.com" /><!--[if lt
## CurrentMember ## CurrentMember
Returns the currently logged in member, if there is one. Returns the currently logged in member, if there is one.
All of their details or any special Member page controls can be called on this. All of their details or any special Member page controls can be called on this.
Alternately, you can use `<% if $CurrentMember %>` to detect whether someone has logged Alternately, you can use `<% if $CurrentMember %>` to detect whether someone has logged
in. in.
:::ss :::ss
<% if $CurrentMember %> <% if $CurrentMember %>
@ -529,11 +529,11 @@ There are two ways you can extend the template variables you have available. You
return "Hi, this is my site"; return "Hi, this is my site";
} }
Will give you the ability to call `$MyCustomValue` from anywhere in your template. Will give you the ability to call `$MyCustomValue` from anywhere in your template.
:::ss :::ss
I've got one thing to say to you: <i>$MyCustomValue</i> I've got one thing to say to you: <i>$MyCustomValue</i>
// output "I've got one thing to say to you: <i>Hi, this is my site</i>" // output "I've got one thing to say to you: <i>Hi, this is my site</i>"
Your function could return a single value as above or it could be a subclass of `[api:ArrayData]` for example a Your function could return a single value as above or it could be a subclass of `[api:ArrayData]` for example a
`[api:DataObject]` with many values then each of these could be accessible via a control loop `[api:DataObject]` with many values then each of these could be accessible via a control loop
@ -551,7 +551,7 @@ And now you could call these values by using
<% with $MyCustomValues %> <% with $MyCustomValues %>
$Hi , $Name $Hi , $Name
<% end_with %> <% end_with %>
// output "Kia Ora , John Smith" // output "Kia Ora , John Smith"
Or by using the dot notation you would have Or by using the dot notation you would have
@ -565,7 +565,7 @@ All functions that provide data to templates must have no side effects, as the v
:::php :::php
private $counter = 0; private $counter = 0;
public function Counter() { public function Counter() {
$this->counter += 1; $this->counter += 1;
return $this->counter; return $this->counter;
@ -594,9 +594,9 @@ by using the `$Layout` variable so it makes sense to add the .typography style a
## Calling templates from PHP code ## Calling templates from PHP code
This is all very well and good, but how do the templates actually get called? This is all very well and good, but how do the templates actually get called?
Templates do nothing on their own. Rather, they are used to render *a particular object*. All of the `<% if %>`, `<%control %>`, Templates do nothing on their own. Rather, they are used to render *a particular object*. All of the `<% if %>`, `<%control %>`,
and variable codes are methods or parameters that are called *on that object*. All that is necessary is and variable codes are methods or parameters that are called *on that object*. All that is necessary is
that the object is an instance of `[api:ViewableData]` (or one of its subclasses). that the object is an instance of `[api:ViewableData]` (or one of its subclasses).
@ -627,11 +627,11 @@ default if it exists and there is no action in the url parameters.
class MyPage_Controller extends Page_Controller { class MyPage_Controller extends Page_Controller {
private static $allowed_actions = array('index'); private static $allowed_actions = array('index');
public function init(){ public function init(){
parent::init(); parent::init();
} }
public function index() { public function index() {
if(Director::is_ajax()) { if(Director::is_ajax()) {
return $this->renderWith("myAjaxTemplate"); return $this->renderWith("myAjaxTemplate");

View File

@ -21,7 +21,7 @@ In your controller (e.g. `mysite/code/Page.php`):
// either specify the css file manually // either specify the css file manually
Requirements::css("mymodule/css/my.css", "screen,projection"); Requirements::css("mymodule/css/my.css", "screen,projection");
// or mention the css filename and SilverStripe will get the file from the current theme and add it to the template // or mention the css filename and SilverStripe will get the file from the current theme and add it to the template
Requirements::themedCSS('print', null,'print'); Requirements::themedCSS('print', null,'print');
} }
} }
@ -51,7 +51,7 @@ An example of a good location to use `class="typography"` is the container eleme
`<div id="LeftContent">` `<div id="LeftContent">`
`<p>`We have a lot of content to go here.`</p>` `<p>`We have a lot of content to go here.`</p>`
`</div>` `</div>`
`<div id="Content" class="typography">` `<div id="Content" class="typography">`
$Content $Content
`</div>` `</div>`
@ -80,7 +80,7 @@ file. Then with this file you can define styles for the CMS or just import the s
:::css :::css
/* Import the common styles from typography like link colors. */ /* Import the common styles from typography like link colors. */
@import 'typography.css'; @import 'typography.css';
/* We want the backend editor to have a bigger font as well though */ /* We want the backend editor to have a bigger font as well though */
.typography * { font-size: 200% } .typography * { font-size: 200% }

View File

@ -19,7 +19,7 @@ See [requirements](/reference/requirements) documentation.
## jQuery, jQuery UI and jQuery.entwine: Our libraries of choice ## jQuery, jQuery UI and jQuery.entwine: Our libraries of choice
We predominantly use [jQuery](http://jquery.com) as our abstraction library for DOM related programming, within the We predominantly use [jQuery](http://jquery.com) as our abstraction library for DOM related programming, within the
SilverStripe CMS and certain framework aspects. SilverStripe CMS and certain framework aspects.
For richer interactions such as drag'n'drop, and more complicated interface elements like tabs or accordions, For richer interactions such as drag'n'drop, and more complicated interface elements like tabs or accordions,
SilverStripe CMS uses [jQuery UI](http://ui.jquery.com) on top of jQuery. SilverStripe CMS uses [jQuery UI](http://ui.jquery.com) on top of jQuery.
@ -105,16 +105,16 @@ Example: A plugin to highlight a collection of elements with a configurable fore
})(jQuery); })(jQuery);
Usage: Usage:
:::js :::js
(function($) { (function($) {
// Highlight all buttons with default colours // Highlight all buttons with default colours
jQuery(':button').highlight(); jQuery(':button').highlight();
// Highlight all buttons with green background // Highlight all buttons with green background
jQuery(':button').highlight({background: "green"}); jQuery(':button').highlight({background: "green"});
// Set all further highlight() calls to have a green background // Set all further highlight() calls to have a green background
$.fn.hilight.defaults.background = "green"; $.fn.hilight.defaults.background = "green";
})(jQuery); })(jQuery);
@ -140,20 +140,20 @@ Example: Highlighter
:::js :::js
(function($) { (function($) {
$.widget("ui.myHighlight", { $.widget("ui.myHighlight", {
getBlink: function () { getBlink: function () {
return this._getData('blink'); return this._getData('blink');
}, },
setBlink: function (blink) { setBlink: function (blink) {
this._setData('blink', blink); this._setData('blink', blink);
if(blink) this.element.wrapInner('<blink></blink>'); if(blink) this.element.wrapInner('<blink></blink>');
else this.element.html(this.element.children().html()); else this.element.html(this.element.children().html());
}, },
_init: function() { _init: function() {
// grab the default value and use it // grab the default value and use it
this.element.css('background',this.options.background); this.element.css('background',this.options.background);
this.element.css('color',this.options.foreground); this.element.css('color',this.options.foreground);
this.setBlink(this.options.blink); this.setBlink(this.options.blink);
} }
}); });
// For demonstration purposes, this is also possible with jQuery.css() // For demonstration purposes, this is also possible with jQuery.css()
$.ui.myHighlight.getter = "getBlink"; $.ui.myHighlight.getter = "getBlink";
@ -171,16 +171,16 @@ Usage:
(function($) { (function($) {
// call with default options // call with default options
$(':button').myHighlight(); $(':button').myHighlight();
// call with custom options // call with custom options
$(':button').myHighlight({background: "green"}); $(':button').myHighlight({background: "green"});
// set defaults for all future instances // set defaults for all future instances
$.ui.myHighlight.defaults.background = "green"; $.ui.myHighlight.defaults.background = "green";
// Adjust property after initialization // Adjust property after initialization
$(':button').myHighlight('setBlink', true); $(':button').myHighlight('setBlink', true);
// Get property // Get property
$(':button').myHighlight('getBlink'); $(':button').myHighlight('getBlink');
})(jQuery); })(jQuery);
@ -218,10 +218,10 @@ Usage:
(function($) { (function($) {
// call with default options // call with default options
$(':button').entwine().highlight(); $(':button').entwine().highlight();
// set options for existing and new instances // set options for existing and new instances
$(':button').entwine().setBackground('green'); $(':button').entwine().setBackground('green');
// get property // get property
$(':button').entwine().getBackground(); $(':button').entwine().getBackground();
})(jQuery); })(jQuery);
@ -243,7 +243,7 @@ jQuery with a few lines of code. Your jQuery code will normally end up as a ser
### Don't claim global properties ### Don't claim global properties
Global properties are evil. They are accessible by other scripts, might be overwritten or misused. A popular case is the `$` shortcut in different libraries: in PrototypeJS it stands for `document.getElementByID()`, in jQuery for `jQuery()`. Global properties are evil. They are accessible by other scripts, might be overwritten or misused. A popular case is the `$` shortcut in different libraries: in PrototypeJS it stands for `document.getElementByID()`, in jQuery for `jQuery()`.
:::js :::js
// you can't rely on '$' being defined outside of the closure // you can't rely on '$' being defined outside of the closure
@ -285,7 +285,7 @@ Example: Add a 'loading' classname to all pressed buttons
$('input[[type=submit]]').on('click', function() { $('input[[type=submit]]').on('click', function() {
$(this).addClass('loading'); $(this).addClass('loading');
}); });
// binding, applies to any inserted elements as well // binding, applies to any inserted elements as well
$('input[[type=submit]]').on(function() { $('input[[type=submit]]').on(function() {
$(this).addClass('loading'); $(this).addClass('loading');
@ -298,7 +298,7 @@ request](http://docs.jquery.com/Frequently_Asked_Questions#Why_do_my_events_stop
### Assume Element Collections ### Assume Element Collections
jQuery is based around collections of DOM elements, the library functions typically handle multiple elements (where it jQuery is based around collections of DOM elements, the library functions typically handle multiple elements (where it
makes sense). Encapsulate your code by nesting your jQuery commands inside a `jQuery().each()` call. Example: makes sense). Encapsulate your code by nesting your jQuery commands inside a `jQuery().each()` call.
:::js :::js
$('.MyCustomField').each(function() { $('.MyCustomField').each(function() {
@ -369,7 +369,7 @@ See [interactive example on jsbin.com](http://jsbin.com/axafa)
Ajax responses will sometimes need to update existing DOM elements, for example refresh a set of search results. Ajax responses will sometimes need to update existing DOM elements, for example refresh a set of search results.
Returning plain HTML is generally a good default behaviour, as it allows you to keep template rendering in one place (in Returning plain HTML is generally a good default behaviour, as it allows you to keep template rendering in one place (in
SilverStripe PHP code), and is easy to deal with in JavaScript. SilverStripe PHP code), and is easy to deal with in JavaScript.
If you need to process or inspect returned data, consider extracting it from the loaded HTML instead (through id/class If you need to process or inspect returned data, consider extracting it from the loaded HTML instead (through id/class
attributes, or the jQuery.metadata plugin). For returning status messages, please use the HTTP status-codes. attributes, or the jQuery.metadata plugin). For returning status messages, please use the HTTP status-codes.
@ -398,10 +398,10 @@ PHP:
public function autocomplete($request) { public function autocomplete($request) {
$results = Page::get()->filter("Title", $request->getVar('title')); $results = Page::get()->filter("Title", $request->getVar('title'));
if(!$results) return new HTTPResponse("Not found", 404); if(!$results) return new HTTPResponse("Not found", 404);
// Use HTTPResponse to pass custom status messages // Use HTTPResponse to pass custom status messages
$this->response->setStatusCode(200, "Found " . $results->Count() . " elements"); $this->response->setStatusCode(200, "Found " . $results->Count() . " elements");
// render all results with a custom template // render all results with a custom template
$vd = new ViewableData(); $vd = new ViewableData();
return $vd->customise(array( return $vd->customise(array(
@ -415,7 +415,7 @@ HTML
:::ss :::ss
<form action"#"> <form action"#">
<div class="autocomplete {url:'my-controller-route/autocomplete'}"> <div class="autocomplete {url:'MyController/autocomplete'}">
<input type="text" name="title" /> <input type="text" name="title" />
<div class="results" style="display: none;"> <div class="results" style="display: none;">
</div> </div>
@ -437,8 +437,8 @@ JavaScript:
function(data, status) { function(data, status) {
resultsEl.show(); resultsEl.show();
// get all record IDs from the new HTML // get all record IDs from the new HTML
var ids = jQuery('.results').find('li').map(function() { var ids = jQuery('.results').find('li').map(function() {
return $(this).attr('id').replace(/Record\-/,''); return $(this).attr('id').replace(/Record\-/,'');
}); });
} }
); );
@ -473,7 +473,7 @@ Example: Trigger custom 'validationfailed' event on form submission for each emp
}); });
return false; return false;
}); });
// listen to custom event on each <input> field // listen to custom event on each <input> field
$('form :input').bind('validationfailed',function(e) { $('form :input').bind('validationfailed',function(e) {
// $(this) refers to input field // $(this) refers to input field
@ -523,30 +523,30 @@ Example: jQuery.entwine
:::js :::js
/** /**
* Available Custom Events: * Available Custom Events:
* <ul> * <ul>
* <li>ajaxsubmit</li> * <li>ajaxsubmit</li>
* <li>validate</li> * <li>validate</li>
* <li>reloadeditform</li> * <li>reloadeditform</li>
* </ul> * </ul>
* *
* @class Main LeftAndMain interface with some control panel and an edit form. * @class Main LeftAndMain interface with some control panel and an edit form.
* @name ss.LeftAndMain * @name ss.LeftAndMain
*/ */
$('.LeftAndMain').entwine('ss', function($){ $('.LeftAndMain').entwine('ss', function($){
return/** @lends ss.LeftAndMain */ { return/** @lends ss.LeftAndMain */ {
/** /**
* Reference to some property * Reference to some property
* @type Number * @type Number
*/ */
MyProperty: 123, MyProperty: 123,
/** /**
* Renders the provided data into an unordered list. * Renders the provided data into an unordered list.
* *
* @param {Object} data * @param {Object} data
* @param {String} status * @param {String} status
* @return {String} HTML unordered list * @return {String} HTML unordered list
@ -556,11 +556,11 @@ Example: jQuery.entwine
+ /... + /...
+ '</ul>'; + '</ul>';
}, },
/** /**
* Won't show in documentation, but still worth documenting. * Won't show in documentation, but still worth documenting.
* *
* @return {String} Something else. * @return {String} Something else.
*/ */
_privateMethod: function() { _privateMethod: function() {
@ -591,14 +591,14 @@ Example: QUnit test (from [jquery.com](http://docs.jquery.com/QUnit#Using_QUnit)
Example: JSpec Shopping cart test (from [visionmedia.github.com](http://visionmedia.github.com/jspec/)) Example: JSpec Shopping cart test (from [visionmedia.github.com](http://visionmedia.github.com/jspec/))
describe 'ShoppingCart' describe 'ShoppingCart'
before_each before_each
cart = new ShoppingCart cart = new ShoppingCart
end end
describe 'addProduct' describe 'addProduct'
it 'should add a product' it 'should add a product'
cart.addProduct('cookie') cart.addProduct('cookie')
cart.addProduct('icecream') cart.addProduct('icecream')
cart.should.have 2, 'products' cart.should.have 2, 'products'
end end
end end
end end
@ -630,11 +630,11 @@ Here's an example of hooking the 'PageLoaded' and 'BeforeSave' methods:
this.observeMethod('BeforeSave', this.beforeSave); this.observeMethod('BeforeSave', this.beforeSave);
this.pageLoaded(); // call pageload initially too. this.pageLoaded(); // call pageload initially too.
}, },
pageLoaded : function() { pageLoaded : function() {
alert("You loaded a page"); alert("You loaded a page");
}, },
beforeSave: function() { beforeSave: function() {
alert("You clicked save"); alert("You clicked save");
} }

View File

@ -47,7 +47,7 @@ reducing HTTP requests. Note that for debugging purposes combined files is disab
By default it stores the generated file in the assets/ folder but you can configure this by pointing By default it stores the generated file in the assets/ folder but you can configure this by pointing
the `Requirements.combined_files_folder` configuration setting to a specific folder. the `Requirements.combined_files_folder` configuration setting to a specific folder.
If SilverStripe doesn't have permissions on your server to write these files it will default back to including them If SilverStripe doesn't have permissions on your server to write these files it will default back to including them
@ -72,7 +72,7 @@ language.
:::php :::php
Requirements::customScript(<<<JS Requirements::customScript(<<<JS
alert("hi there"); alert("hi there");
JS JS
); );
Requirements::customCSS(<<<CSS Requirements::customCSS(<<<CSS
@ -127,8 +127,8 @@ and use a newer version in a custom location.
:::php :::php
Requirements::block(THIRDPARTY_DIR . '/jquery/jquery.js'); Requirements::block(THIRDPARTY_DIR . '/jquery/jquery.js');
Caution: The CMS also uses the `Requirements` system, and its operation can be Caution: The CMS also uses the `Requirements` system, and its operation can be
affected by `block()` calls. Avoid this by limiting the scope of affected by `block()` calls. Avoid this by limiting the scope of
your blocking operations, e.g. in `init()` of your controller. your blocking operations, e.g. in `init()` of your controller.
@ -155,11 +155,11 @@ The SilverStripe core includes a lot of Requirements by itself. Most of these ar
## Motivation ## Motivation
Every page requested is made up of a number of parts, and many of those parts require their own CSS or JavaScript. Every page requested is made up of a number of parts, and many of those parts require their own CSS or JavaScript.
Rather than force the developer to put all of those requests into the template, or the header function, you can Rather than force the developer to put all of those requests into the template, or the header function, you can
reference required files anywhere in your application. reference required files anywhere in your application.
This lets you create very modular units of PHP+JavaScript+CSS, which a powerful concept but must be managed carefully. This lets you create very modular units of PHP+JavaScript+CSS, which a powerful concept but must be managed carefully.
## Managing Generic CSS styling ## Managing Generic CSS styling

View File

@ -43,7 +43,7 @@ Definition:
injection := "$" lookup | "{" "$" lookup "}" injection := "$" lookup | "{" "$" lookup "}"
call := word [ "(" argument { "," argument } ")" ] call := word [ "(" argument { "," argument } ")" ]
lookup := call { "." call }* lookup := call { "." call }*
argument := literal | argument := literal |
lookup | lookup |
"$" lookup "$" lookup

View File

@ -20,15 +20,15 @@ as a .tar.gz file.
## Developing your own theme ## Developing your own theme
See [Developing Themes](theme-development) to get an idea of how themes actually work and how you can develop your own. See [Developing Themes](theme-development) to get an idea of how themes actually work and how you can develop your own.
## Submitting your theme to SilverStripe ## Submitting your theme to SilverStripe
If you want to submit your theme to the SilverStripe directory then check If you want to submit your theme to the SilverStripe directory then check
* You should ensure your templates are well structured, modular and commented so it's easy for other people to * You should ensure your templates are well structured, modular and commented so it's easy for other people to
customise them. customise them.
* Templates should not contain text inside images and all images provided must be open source and not break any copyright or license laws. * Templates should not contain text inside images and all images provided must be open source and not break any copyright or license laws.
This includes any icons your template uses in the frontend or the backend CMS. This includes any icons your template uses in the frontend or the backend CMS.
* A theme does not include any PHP files. Only CSS, HTML, Images and Javascript. * A theme does not include any PHP files. Only CSS, HTML, Images and Javascript.

View File

@ -6,7 +6,7 @@
you create your own SilverStripe website theme. you create your own SilverStripe website theme.
Developing your own theme in SilverStripe is a piece of cake thanks to a very straight forward and clean templating Developing your own theme in SilverStripe is a piece of cake thanks to a very straight forward and clean templating
language. language.
## What is a Theme? ## What is a Theme?
@ -32,7 +32,7 @@ After you have created the templates folder you need to create 2 more folders wi
uppercase initial letters). These are 2 different types of templates you will use in your theme - Includes contain uppercase initial letters). These are 2 different types of templates you will use in your theme - Includes contain
snippets of HTML that you want to break out and share between templates (for example the Header can be an include, snippets of HTML that you want to break out and share between templates (for example the Header can be an include,
Footer, Navigation etc) whereas Layout templates are the base page templates. So you can have several includes in a Footer, Navigation etc) whereas Layout templates are the base page templates. So you can have several includes in a
Layout template. Layout template.
## Getting started - Core Files ## Getting started - Core Files
@ -64,27 +64,27 @@ our theme in action. The code for mine is below.
$MetaTags(false) $MetaTags(false)
<title>Bob's Chicken Shack | $Title</title> <title>Bob's Chicken Shack | $Title</title>
</head> </head>
<body> <body>
<div id="Container"> <div id="Container">
<div id="Header"> <div id="Header">
<h1>Bob's Chicken Shack</h1> <h1>Bob's Chicken Shack</h1>
</div> </div>
<div id="Navigation"> <div id="Navigation">
<% if $Menu(1) %> <% if $Menu(1) %>
<ul> <ul>
<% loop $Menu(1) %> <% loop $Menu(1) %>
<li><a href="$Link" title="Go to the $Title page" class="$LinkingMode">$MenuTitle</a></li> <li><a href="$Link" title="Go to the $Title page" class="$LinkingMode">$MenuTitle</a></li>
<% end_loop %> <% end_loop %>
</ul> </ul>
<% end_if %> <% end_if %>
</div> </div>
<div id="Layout"> <div id="Layout">
$Layout $Layout
</div> </div>
<div id="Footer"> <div id="Footer">
<p>Copyright $Now.Year - Bob's Chicken Shack.</p> <p>Copyright $Now.Year - Bob's Chicken Shack.</p>
</div> </div>
@ -117,9 +117,9 @@ See [Templates](/reference/themes) for more information about templates.
### CSS Files ### CSS Files
By standard SilverStripe uses 3 CSS Files for your site - By standard SilverStripe uses 3 CSS Files for your site -
* **layout.css** contains the layout and design of the site * **layout.css** contains the layout and design of the site
* **typography.css** contains the styling for the text/fonts/links (used in both front and back ends) * **typography.css** contains the styling for the text/fonts/links (used in both front and back ends)
* **form.css** styling for forms. * **form.css** styling for forms.
@ -149,16 +149,16 @@ Let's have a look at part of a Page.ss for the main layout elements defining a 2
<div id="Header"> <div id="Header">
<!-- Header --> <!-- Header -->
</div> </div>
<div id="Navigation"> <div id="Navigation">
<!-- The Main Site Nav --> <!-- The Main Site Nav -->
</div> </div>
<div id="Layout"> <div id="Layout">
<!-- The whole site content has to sit inside here! Anything you want to sub template (eg each page will be different, needs to be contained in $Layout. This calls the file /Layout/Page.ss or anyother sub page template --> <!-- The whole site content has to sit inside here! Anything you want to sub template (eg each page will be different, needs to be contained in $Layout. This calls the file /Layout/Page.ss or anyother sub page template -->
$Layout $Layout
</div> </div>
<div id="Footer"> <div id="Footer">
</div> </div>
</div> </div>
@ -184,7 +184,7 @@ Next is a division for the main navigation. This may contain something like:
<div id="Navigation"> <div id="Navigation">
<% if $Menu(1) %> <% if $Menu(1) %>
<ul> <ul>
<% loop $Menu(1) %> <% loop $Menu(1) %>
<li><a href="$Link" title="Go to the $Title page" class="$LinkingMode">$MenuTitle</a></li> <li><a href="$Link" title="Go to the $Title page" class="$LinkingMode">$MenuTitle</a></li>
<% end_loop %> <% end_loop %>
</ul> </ul>
@ -220,10 +220,10 @@ A bunch of resources feel free to use to make your template awesome
* [http://kuler.adobe.com](http://kuler.adobe.com) - Kuler is a great color scheming tool * [http://kuler.adobe.com](http://kuler.adobe.com) - Kuler is a great color scheming tool
* [http://blog.html.it/layoutgala/](http://blog.html.it/layoutgala/) - 40 super cool CSS layouts for you to use * [http://blog.html.it/layoutgala/](http://blog.html.it/layoutgala/) - 40 super cool CSS layouts for you to use
* [http://designmeltdown.com](http://designmeltdown.com) - Great gallery of websites. Browse through and get inspired. * [http://designmeltdown.com](http://designmeltdown.com) - Great gallery of websites. Browse through and get inspired.
* [http://validator.w3.org/](http://validator.w3.org/) - Your template must pass 'or get near' validation. * [http://validator.w3.org/](http://validator.w3.org/) - Your template must pass 'or get near' validation.
* [http://famfamfam.com/lab/icons/](http://famfamfam.com/lab/icons/) - free, beautiful icons. * [http://famfamfam.com/lab/icons/](http://famfamfam.com/lab/icons/) - free, beautiful icons.
* [http://cssremix.com](http://cssremix.com) - Another CSS site gallery for inspiration. * [http://cssremix.com](http://cssremix.com) - Another CSS site gallery for inspiration.
* [http://www.maxdesign.com.au/presentation/process/](http://www.maxdesign.com.au/presentation/process/) - a good process for creating a design * [http://www.maxdesign.com.au/presentation/process/](http://www.maxdesign.com.au/presentation/process/) - a good process for creating a design
## Reference ## Reference
@ -253,7 +253,7 @@ ambiguity for themes.
### Subthemes ### Subthemes
If you have a theme called mytheme_forum, it is considered to be a 'subtheme' of the mytheme theme. This lets module If you have a theme called mytheme_forum, it is considered to be a 'subtheme' of the mytheme theme. This lets module
developers release extensions to popular themes that will let their module work with that theme. developers release extensions to popular themes that will let their module work with that theme.
A subtheme overrides the files in the module. So for instance, if you have the forum setup instead of editing the files A subtheme overrides the files in the module. So for instance, if you have the forum setup instead of editing the files
within the forum/ module you would create a themes/yourtheme_forum/ folder. within the forum/ module you would create a themes/yourtheme_forum/ folder.

View File

@ -8,14 +8,14 @@ most likely the "Page" template in your theme,
located in `themes/<mytheme>/templates/Page.ss`. located in `themes/<mytheme>/templates/Page.ss`.
:::ss :::ss
<ul> <ul>
<% loop $Menu(1) %> <% loop $Menu(1) %>
<li> <li>
<a href="$Link" title="Go to the $Title page" class="$LinkingMode"> <a href="$Link" title="Go to the $Title page" class="$LinkingMode">
<span>$MenuTitle</span> <span>$MenuTitle</span>
</a> </a>
</li> </li>
<% end_loop %> <% end_loop %>
</ul> </ul>
More details on creating a menu are explained as part of ["Tutorial 1: Building a basic site"](/tutorials/1-building-a-basic-site), as well as ["Page type templates" topic](/topics/page-type-templates). More details on creating a menu are explained as part of ["Tutorial 1: Building a basic site"](/tutorials/1-building-a-basic-site), as well as ["Page type templates" topic](/topics/page-type-templates).

View File

@ -0,0 +1,8 @@
title: Templates and Views
summary: This guide showcases the SilverStripe template engine and learn how to build your own themes.
[CHILDREN]
## How-to
[CHILDREN How_To]

View File

@ -0,0 +1,8 @@
title: Controllers
summary: Controllers form the backbone of your SilverStripe application. They handle routing URLs to your templates.
[CHILDREN]
## How-to
[CHILDREN How_To]

View File

@ -0,0 +1,8 @@
title: Forms
summary: Capture user information through Forms. This guide will work through making forms, custom form fields and adding fields to your data.
[CHILDREN]
## How-to
[CHILDREN How_To]

View File

@ -0,0 +1,8 @@
title: Configuration
summary: SilverStripe provides several ways to store and modify your application settings. Learn about site wide settings and the YAML based configuration system.
[CHILDREN]
## How-to
[CHILDREN How_To]

View File

@ -0,0 +1,8 @@
title: Extending SilverStripe
summary: Understand the ways to modify the built-in functionality through Extensions, Subclassing and Dependency Injection.
[CHILDREN]
## How-to
[CHILDREN How_To]

View File

@ -1,3 +1,5 @@
summary: Deploy robust applications by bundling Unit and Behavior tests with your application code and modules.
# Unit and Integration Testing # Unit and Integration Testing
For behaviour testing in SilverStripe, check out [SilverStripe Behat Documentation](https://github.com/silverstripe-labs/silverstripe-behat-extension/). For behaviour testing in SilverStripe, check out [SilverStripe Behat Documentation](https://github.com/silverstripe-labs/silverstripe-behat-extension/).

View File

@ -1,3 +1,5 @@
summary: Learn how to identify errors in your application and best practice for logging application errors.
# Debugging # Debugging
## Environment Types ## Environment Types
@ -44,7 +46,7 @@ To set your site to test mode set this in your `config.yml` file
environment_type: 'test' environment_type: 'test'
A common situation is to enable password protected site viewing on your test site only. A common situation is to enable password protected site viewing on your test site only.
You can enable that but adding this to your `config.yml` file: You can enable that but adding this to your `config.yml` file:
:::yml :::yml
@ -122,7 +124,7 @@ On live sites, all errors are emailed to the address specified in the `Debug.sen
Since we don't have a decent interactive debugger going, we use the following debugging techniques: Since we don't have a decent interactive debugger going, we use the following debugging techniques:
* Putting *Debug::show()* and *Debug::message()* at key places in the code can help you know what's going on. * Putting *Debug::show()* and *Debug::message()* at key places in the code can help you know what's going on.
Sometimes, it helps to put this debugging information into the core modules, although, if possible, try and get what you Sometimes, it helps to put this debugging information into the core modules, although, if possible, try and get what you
need by using [url querystring variables](/reference/urlvariabletools). need by using [url querystring variables](/reference/urlvariabletools).
@ -143,7 +145,7 @@ the development effort itself as "test-driven development".
#### Profiling #### Profiling
Profiling is the best way to identify bottle necks and other slow moving parts of your application prime for optimization. SilverStripe Profiling is the best way to identify bottle necks and other slow moving parts of your application prime for optimization. SilverStripe
does not include any profiling tools out of the box, but we recommend the use of existing tools such as [XHProf](https://github.com/facebook/xhprof/) does not include any profiling tools out of the box, but we recommend the use of existing tools such as [XHProf](https://github.com/facebook/xhprof/)
and [XDebug](http://xdebug.org/). and [XDebug](http://xdebug.org/).

View File

@ -0,0 +1,8 @@
title: Performance
summary: Make your applications faster by learning how to write more scalable code and ways to cache your important information.
[CHILDREN]
## How-to
[CHILDREN How_To]

View File

@ -0,0 +1,7 @@
summary: This guide covers user authentication, the permission system and how to secure your code against malicious behaviors
[CHILDREN]
## How-to
[CHILDREN How_To]

View File

@ -1,3 +1,5 @@
summary: Send HTML and plain text email from your SilverStripe application.
# Email # Email
SilverStripe has emailing functionality using the built-in mail() function in PHP. SilverStripe has emailing functionality using the built-in mail() function in PHP.
@ -44,16 +46,16 @@ Example:
:::php :::php
$email = new Email($from, $to, $subject, $body); $email = new Email($from, $to, $subject, $body);
$email->setTemplate('MyEmail'); $email->setTemplate('MyEmail');
// You can call this multiple times or bundle everything into an array, including DataSetObjects // You can call this multiple times or bundle everything into an array, including DataSetObjects
$email->populateTemplate(Member::currentUser()); $email->populateTemplate(Member::currentUser());
$welcomeMsg = 'Thank you for joining on '.date('Y-m-d'.'!'); $welcomeMsg = 'Thank you for joining on '.date('Y-m-d'.'!');
$email->populateTemplate(array( $email->populateTemplate(array(
'WelcomeMessage' => $welcomeMsg, // Accessible in template via $WelcomeMessage 'WelcomeMessage' => $welcomeMsg, // Accessible in template via $WelcomeMessage
)); ));
$email->send(); $email->send();
@ -96,7 +98,7 @@ systems.
:::php :::php
if(Director::isLive()) Config::inst()->update('Email', 'bcc_all_emails_to', "client@example.com"); if(Director::isLive()) Config::inst()->update('Email', 'bcc_all_emails_to', "client@example.com");
else Config::inst()->update('Email', 'send_all_emails_to', "developer@example.com"); else Config::inst()->update('Email', 'send_all_emails_to', "developer@example.com");
### Setting Custom Headers ### Setting Custom Headers

View File

@ -9,7 +9,7 @@ be customized to fit your data.
## The CsvBulkLoader class ## The CsvBulkLoader class
The [api:CsvBulkLoader] class facilitate complex CSV-imports by defining column-mappings and custom converters. The [api:CsvBulkLoader] class facilitate complex CSV-imports by defining column-mappings and custom converters.
It uses PHP's built-in `fgetcsv()` function to process CSV input, and accepts a file handle as an input. It uses PHP's built-in `fgetcsv()` function to process CSV input, and accepts a file handle as an input.
Feature overview: Feature overview:
@ -52,7 +52,7 @@ The simplest way to use [api:CsvBulkLoader] is through a [api:ModelAdmin] interf
'Player' 'Player'
); );
private static $model_importers = array( private static $model_importers = array(
'Player' => 'PlayerCsvBulkLoader', 'Player' => 'PlayerCsvBulkLoader',
); );
private static $url_segment = 'players'; private static $url_segment = 'players';
} }
@ -73,13 +73,13 @@ You'll need to add a route to your controller to make it accessible via URL
class MyController extends Controller { class MyController extends Controller {
private static $allowed_actions = array('Form'); private static $allowed_actions = array('Form');
protected $template = "BlankPage"; protected $template = "BlankPage";
public function Link($action = null) { public function Link($action = null) {
return Controller::join_links('MyController', $action); return Controller::join_links('MyController', $action);
} }
public function Form() { public function Form() {
$form = new Form( $form = new Form(
$this, $this,
@ -94,7 +94,7 @@ You'll need to add a route to your controller to make it accessible via URL
); );
return $form; return $form;
} }
public function doUpload($data, $form) { public function doUpload($data, $form) {
$loader = new CsvBulkLoader('MyDataObject'); $loader = new CsvBulkLoader('MyDataObject');
$results = $loader->load($_FILES['CsvFile']['tmp_name']); $results = $loader->load($_FILES['CsvFile']['tmp_name']);
@ -104,7 +104,7 @@ You'll need to add a route to your controller to make it accessible via URL
if($results->DeletedCount()) $messages[] = sprintf('Deleted %d items', $results->DeletedCount()); if($results->DeletedCount()) $messages[] = sprintf('Deleted %d items', $results->DeletedCount());
if(!$messages) $messages[] = 'No changes'; if(!$messages) $messages[] = 'No changes';
$form->sessionMessage(implode(', ', $messages), 'good'); $form->sessionMessage(implode(', ', $messages), 'good');
return $this->redirectBack(); return $this->redirectBack();
} }
} }
@ -131,9 +131,9 @@ Datamodel for Player
class Player extends DataObject { class Player extends DataObject {
private static $db = array( private static $db = array(
'PlayerNumber' => 'Int', 'PlayerNumber' => 'Int',
'FirstName' => 'Text', 'FirstName' => 'Text',
'LastName' => 'Text', 'LastName' => 'Text',
'Birthday' => 'Date', 'Birthday' => 'Date',
); );
private static $has_one = array( private static $has_one = array(
'Team' => 'FootballTeam' 'Team' => 'FootballTeam'
@ -148,7 +148,7 @@ Datamodel for FootballTeam:
<?php <?php
class FootballTeam extends DataObject { class FootballTeam extends DataObject {
private static $db = array( private static $db = array(
'Title' => 'Text', 'Title' => 'Text',
); );
private static $has_many = array( private static $has_many = array(
'Players' => 'Player' 'Players' => 'Player'

View File

@ -3,7 +3,7 @@
## Introduction ## Introduction
`[api:RestfulService]` uses the php curl library, enabling connections to remote web services which support a REST interface and consuming those web services. (Examples: [Flickr](http://www.flickr.com/services/api/), [Youtube](http://code.google.com/apis/youtube/overview.html), Amazon and etc). `[api:RestfulService]` can parse the XML response (sorry no JSON support) `[api:RestfulService]` uses the php curl library, enabling connections to remote web services which support a REST interface and consuming those web services. (Examples: [Flickr](http://www.flickr.com/services/api/), [Youtube](http://code.google.com/apis/youtube/overview.html), Amazon and etc). `[api:RestfulService]` can parse the XML response (sorry no JSON support)
returned from the web service. Further it supports caching of the response, and you can customize the cache interval. returned from the web service. Further it supports caching of the response, and you can customize the cache interval.
To gain the functionality you can either create a new `[api:RestfulService]` object or create a class extending the To gain the functionality you can either create a new `[api:RestfulService]` object or create a class extending the
RestfulService (see [flickrservice](http://silverstripe.org/flickr-module/) and RestfulService (see [flickrservice](http://silverstripe.org/flickr-module/) and
@ -28,7 +28,7 @@ RestfulService (see [flickrservice](http://silverstripe.org/flickr-module/) and
:::php :::php
//example for extending RestfulService //example for extending RestfulService
class FlickrService extends RestfulService { class FlickrService extends RestfulService {
public function __construct($expiry=NULL){ public function __construct($expiry=NULL){
parent::__construct('http://www.flickr.com/services/rest/', $expiry); parent::__construct('http://www.flickr.com/services/rest/', $expiry);
$this->checkErrors = true; $this->checkErrors = true;
@ -44,12 +44,12 @@ RestfulService (see [flickrservice](http://silverstripe.org/flickr-module/) and
$service->basicAuth('username', 'password'); $service->basicAuth('username', 'password');
$service->httpHeader('Accept: application/xml'); $service->httpHeader('Accept: application/xml');
$service->httpHeader('Content-Type: application/xml'); $service->httpHeader('Content-Type: application/xml');
$peopleXML = $service->request('/people'); $peopleXML = $service->request('/people');
$people = $service->getValues($peopleXML, 'user'); $people = $service->getValues($peopleXML, 'user');
// ... // ...
$taskXML = $service->request('/tasks'); $taskXML = $service->request('/tasks');
$tasks = $service->getValues($taskXML, 'task'); $tasks = $service->getValues($taskXML, 'task');
@ -57,7 +57,7 @@ RestfulService (see [flickrservice](http://silverstripe.org/flickr-module/) and
## Features ## Features
### Caching ### Caching
To set the cache interval you can pass it as the 2nd argument to constructor. To set the cache interval you can pass it as the 2nd argument to constructor.
@ -68,7 +68,7 @@ To set the cache interval you can pass it as the 2nd argument to constructor.
### Getting Values & Attributes ### Getting Values & Attributes
You can traverse throught document tree to get the values or attribute of a particular node. You can traverse throught document tree to get the values or attribute of a particular node.
for example you can traverse for example you can traverse
:::xml :::xml
<entries> <entries>
@ -84,7 +84,7 @@ to extract the id attributes of the entries use:
$this->getAttributes($xml, "entries", "entry") //will return all attributes of each entry node $this->getAttributes($xml, "entries", "entry") //will return all attributes of each entry node
to extract the values (the names) of the entries use: to extract the values (the names) of the entries use:
:::php :::php
$this->getValues($xml, "entries", "entry") //will return all values of each entry node $this->getValues($xml, "entries", "entry") //will return all values of each entry node
@ -119,11 +119,11 @@ could delgate the error handling to it's descendant class. To handle the errors
// This will raise Youtube API specific error messages (if any). // This will raise Youtube API specific error messages (if any).
public function errorCatch($response){ public function errorCatch($response){
$err_msg = $response; $err_msg = $response;
if(strpos($err_msg, '<') === false) { if(strpos($err_msg, '<') === false) {
user_error("YouTube Service Error : $err_msg", E_USER_ERROR); user_error("YouTube Service Error : $err_msg", E_USER_ERROR);
} }
return $response; return $response;
} }
@ -197,8 +197,8 @@ Put something like this code in mysite/code/Page.php inside class Page_Controlle
$service = new RestfulService($url); $service = new RestfulService($url);
$request = $service->request(); $request = $service->request();
$body = $request->getBody(); $body = $request->getBody();
$items = $service->getValues($body,"channel","item"); $items = $service->getValues($body,"channel","item");
$output = ''; $output = '';
foreach($items as $item) { foreach($items as $item) {
// Fix quote encoding // Fix quote encoding
@ -206,7 +206,7 @@ Put something like this code in mysite/code/Page.php inside class Page_Controlle
$output .= "<li><a href=\"{$item->link}\">{$item->title}</a><br />{$description}</li>"; $output .= "<li><a href=\"{$item->link}\">{$item->title}</a><br />{$description}</li>";
} }
return $output; return $output;
} }
Put something like this code in `themes/<your-theme>/templates/Layout/HomePage.ss`: Put something like this code in `themes/<your-theme>/templates/Layout/HomePage.ss`:
@ -214,7 +214,7 @@ Put something like this code in `themes/<your-theme>/templates/Layout/HomePage.s
:::ss :::ss
<h3>My Latest Del.icio.us Links</h3> <h3>My Latest Del.icio.us Links</h3>
<ul> <ul>
$RestfulLinks(http://del.icio.us/rss/elijahlofgren) $RestfulLinks(http://del.icio.us/rss/elijahlofgren)
</ul> </ul>

View File

@ -2,17 +2,17 @@
## Introduction ## Introduction
Generating RSS/Atom-feeds is a matter of rendering a `[api:SS_List]` through Generating RSS/Atom-feeds is a matter of rendering a `[api:SS_List]` through
the `[api:RSSFeed]` class. the `[api:RSSFeed]` class.
The `[api:RSSFeed]` class doesn't limit you to generating article based feeds, The `[api:RSSFeed]` class doesn't limit you to generating article based feeds,
it is just as easy to create a feed of your current staff members, comments or it is just as easy to create a feed of your current staff members, comments or
any other custom `[api:DataObject]` subclasses you have defined. The only any other custom `[api:DataObject]` subclasses you have defined. The only
logical limitation here is that every item in the RSS-feed should be accessible logical limitation here is that every item in the RSS-feed should be accessible
through a URL on your website, so its advisable to just create feeds from sub through a URL on your website, so its advisable to just create feeds from sub
classes of `[api:SiteTree]`. classes of `[api:SiteTree]`.
If you wish to generate an RSS feed for `[api:DataObject]` instances, ensure they If you wish to generate an RSS feed for `[api:DataObject]` instances, ensure they
define an AbsoluteLink() method. define an AbsoluteLink() method.
## Usage ## Usage
@ -20,23 +20,23 @@ define an AbsoluteLink() method.
:::php :::php
RSSFeed::linkToFeed($link, $title) RSSFeed::linkToFeed($link, $title)
This line should go in your `[api:Controller]` subclass in the action you want This line should go in your `[api:Controller]` subclass in the action you want
to include the HTML link. Not all arguments are required, see `[api:RSSFeed]` and example below. Last Modified Time is expected in seconds like time(). to include the HTML link. Not all arguments are required, see `[api:RSSFeed]` and example below. Last Modified Time is expected in seconds like time().
:::php :::php
$feed = new RSSFeed( $feed = new RSSFeed(
$list, $list,
$link, $link,
$title, $title,
$description, $description,
$titleField, $titleField,
$descriptionField, $descriptionField,
$authorField, $authorField,
$lastModifiedTime, $lastModifiedTime,
$etag $etag
); );
Creates a new `[api:RSSFeed]` instance to be returned. The arguments notify Creates a new `[api:RSSFeed]` instance to be returned. The arguments notify
SilverStripe what values to include in the feed. SilverStripe what values to include in the feed.
## Examples ## Examples
@ -48,12 +48,12 @@ SilverStripe what values to include in the feed.
private static $allowed_actions = array('rss'); private static $allowed_actions = array('rss');
public function init() { public function init() {
parent::init(); parent::init();
// linkToFeed will add an appropriate HTML link tag to the website // linkToFeed will add an appropriate HTML link tag to the website
// <head> tag to notify web browsers that an RSS feed is available // <head> tag to notify web browsers that an RSS feed is available
// for this page. You can include as many feeds on the page as you // for this page. You can include as many feeds on the page as you
// wish as long as each as a different link. For example: // wish as long as each as a different link. For example:
// ('blog/rss', 'staff/rss'). // ('blog/rss', 'staff/rss').
// //
// In this example $this->Link("rss") refers to the *rss* function // In this example $this->Link("rss") refers to the *rss* function
// we define below. // we define below.
RSSFeed::linkToFeed($this->Link("rss"), "RSS feed of this blog"); RSSFeed::linkToFeed($this->Link("rss"), "RSS feed of this blog");
@ -76,45 +76,45 @@ SilverStripe what values to include in the feed.
### Showing the 10 most recently updated pages ### Showing the 10 most recently updated pages
You can use `[api:RSSFeed]` to easily create a feed showing your latest Page You can use `[api:RSSFeed]` to easily create a feed showing your latest Page
updates. Update mysite/code/Page.php to something like this: updates. Update mysite/code/Page.php to something like this:
:::php :::php
<?php <?php
class Page extends SiteTree {} class Page extends SiteTree {}
class Page_Controller extends ContentController { class Page_Controller extends ContentController {
private static $allowed_actions = array('rss'); private static $allowed_actions = array('rss');
public function init() { public function init() {
parent::init(); parent::init();
RSSFeed::linkToFeed($this->Link() . "rss", "10 Most Recently Updated Pages"); RSSFeed::linkToFeed($this->Link() . "rss", "10 Most Recently Updated Pages");
} }
public function rss() { public function rss() {
$rss = new RSSFeed($this->LatestUpdates(), $this->Link(), "10 Most Recently Updated Pages", "Shows a list of the 10 most recently updated pages."); $rss = new RSSFeed($this->LatestUpdates(), $this->Link(), "10 Most Recently Updated Pages", "Shows a list of the 10 most recently updated pages.");
return $rss->outputToBrowser(); return $rss->outputToBrowser();
} }
public function LatestUpdates() { public function LatestUpdates() {
return Page::get()->sort("LastEdited", "DESC")->limit(10); return Page::get()->sort("LastEdited", "DESC")->limit(10);
} }
} }
### Rendering DataObjects in a RSSFeed ### Rendering DataObjects in a RSSFeed
DataObjects can be rendered in the feed as well, however, since they aren't explicitly DataObjects can be rendered in the feed as well, however, since they aren't explicitly
`[api:SiteTree]` subclasses we need to include a function `AbsoluteLink` to allow the `[api:SiteTree]` subclasses we need to include a function `AbsoluteLink` to allow the
RSS feed to link through to the item. RSS feed to link through to the item.
If the items are all displayed on a single page you may simply hard code the link to If the items are all displayed on a single page you may simply hard code the link to
point to a particular page. point to a particular page.
Take an example, we want to create an RSS feed of all the Students, a DataObject we Take an example, we want to create an RSS feed of all the Students, a DataObject we
defined in the [fifth tutorial](/tutorials/5-dataobject-relationship-management). defined in the [fifth tutorial](/tutorials/5-dataobject-relationship-management).
:::php :::php
<?php <?php
class Student extends DataObject { class Student extends DataObject {
public function AbsoluteLink() { public function AbsoluteLink() {
// see tutorial 5, students are assigned a project, so the 'link' // see tutorial 5, students are assigned a project, so the 'link'
@ -132,12 +132,12 @@ for all the students as we've seen before.
public function init() { public function init() {
parent::init(); parent::init();
RSSFeed::linkToFeed($this->Link("students"), "Students feed"); RSSFeed::linkToFeed($this->Link("students"), "Students feed");
} }
public function students() { public function students() {
$rss = new RSSFeed( $rss = new RSSFeed(
$list = $this->getStudents(), $list = $this->getStudents(),
$link = $this->Link("students"), $link = $this->Link("students"),
$title = "Students feed" $title = "Students feed"
); );
return $rss->outputToBrowser(); return $rss->outputToBrowser();
} }
@ -148,7 +148,7 @@ for all the students as we've seen before.
### Customizing the RSS Feed template ### Customizing the RSS Feed template
The default template used is framework/templates/RSSFeed.ss and includes The default template used is framework/templates/RSSFeed.ss and includes
displaying titles and links to the content. If you have a particular need displaying titles and links to the content. If you have a particular need
for customizing the XML produced (say for additional meta data) use `setTemplate`. for customizing the XML produced (say for additional meta data) use `setTemplate`.
@ -159,8 +159,8 @@ unique template (write your own XML in themes/yourtheme/templates/Students.ss)
public function students() { public function students() {
$rss = new RSSFeed( $rss = new RSSFeed(
$list = $this->getStudents(), $list = $this->getStudents(),
$link = $this->Link("students"), $link = $this->Link("students"),
$title = "Students feed" $title = "Students feed"
); );
$rss->setTemplate('Students'); $rss->setTemplate('Students');
return $rss->outputToBrowser(); return $rss->outputToBrowser();

View File

@ -0,0 +1,7 @@
summary: Integrate other web services within your application or make your SilverStripe data available via REST.
[CHILDREN]
## How-to
[CHILDREN How_To]

View File

@ -1,3 +1,5 @@
summary: Provide your users with advanced search functionality.
# Search # Search
## Searching for Pages (and Files) ## Searching for Pages (and Files)
@ -7,7 +9,7 @@ See [Tutorial: Site Search](/tutorials/4-site-search) for details.
## Searching for DataObjects ## Searching for DataObjects
The `[api:SearchContext]` class provides a good base implementation that you can hook into your own controllers. The `[api:SearchContext]` class provides a good base implementation that you can hook into your own controllers.
A working implementation of searchable DataObjects can be seen in the `[ModelAdmin](/reference/modeladmin)` class. A working implementation of searchable DataObjects can be seen in the `[ModelAdmin](/reference/modeladmin)` class.
[SearchContext](/reference/searchcontext) goes into more detail about setting up a default search form for `[api:DataObject]`s. [SearchContext](/reference/searchcontext) goes into more detail about setting up a default search form for `[api:DataObject]`s.

View File

@ -1,3 +1,5 @@
summary: Display templates and PHP code in different languages based on the preferences of your website users.
# i18n # i18n
## Introduction ## Introduction
@ -6,7 +8,7 @@ The i18n class (short for "internationalization") in SilverStripe enables you to
different languages based on your global settings and the preferences of your website users. This process is also known different languages based on your global settings and the preferences of your website users. This process is also known
as l10n (short for "localization"). as l10n (short for "localization").
For translating any content managed through the CMS or stored in the database, For translating any content managed through the CMS or stored in the database,
please use the "[translatable](http://github.com/silverstripe/silverstripe-translatable)" module. please use the "[translatable](http://github.com/silverstripe/silverstripe-translatable)" module.
This page aims to describe the low-level functionality of the i18n-API. It targets developers who: This page aims to describe the low-level functionality of the i18n-API. It targets developers who:
@ -33,7 +35,7 @@ want to set.
:::php :::php
//Example 1: setting the locale //Example 1: setting the locale
i18n::set_locale('de_DE'); //Setting the locale to German (Germany) i18n::set_locale('de_DE'); //Setting the locale to German (Germany)
i18n::set_locale('ca_AD'); //Setting to Catalan (Andorra) i18n::set_locale('ca_AD'); //Setting to Catalan (Andorra)
@ -53,7 +55,7 @@ To let browsers know which language they're displaying a document in, you can de
:::html :::html
//'Page.ss' (HTML) //'Page.ss' (HTML)
<html lang="$ContentLocale"> <html lang="$ContentLocale">
//'Page.ss' (XHTML) //'Page.ss' (XHTML)
<html lang="$ContentLocale" xml:lang="$ContentLocale" xmlns="http://www.w3.org/1999/xhtml"> <html lang="$ContentLocale" xml:lang="$ContentLocale" xmlns="http://www.w3.org/1999/xhtml">
@ -61,7 +63,7 @@ To let browsers know which language they're displaying a document in, you can de
Setting the '<html>' attribute is the most commonly used technique. There are other ways to specify content languages Setting the '<html>' attribute is the most commonly used technique. There are other ways to specify content languages
(meta tags, HTTP headers), explained in this [w3.org article](http://www.w3.org/International/tutorials/language-decl/). (meta tags, HTTP headers), explained in this [w3.org article](http://www.w3.org/International/tutorials/language-decl/).
You can also set the [script direction](http://www.w3.org/International/questions/qa-scripts), You can also set the [script direction](http://www.w3.org/International/questions/qa-scripts),
which is determined by the current locale, in order to indicate the preferred flow of characters which is determined by the current locale, in order to indicate the preferred flow of characters
and default alignment of paragraphs and tables to browsers. and default alignment of paragraphs and tables to browsers.
@ -70,7 +72,7 @@ and default alignment of paragraphs and tables to browsers.
### Date and time formats ### Date and time formats
Formats can be set globally in the i18n class. These settings are currently only picked up by the CMS, you'll need Formats can be set globally in the i18n class. These settings are currently only picked up by the CMS, you'll need
to write your own logic for any frontend output. to write your own logic for any frontend output.
:::php :::php
@ -97,7 +99,7 @@ In order to add a value, add the following to your `config.yml`:
native: Kölsch native: Kölsch
Similarly, to change an existing language label, you can overwrite one of these keys: Similarly, to change an existing language label, you can overwrite one of these keys:
:::yml :::yml
i18n: i18n:
common_locales: common_locales:
@ -106,11 +108,11 @@ Similarly, to change an existing language label, you can overwrite one of these
### i18n in URLs ### i18n in URLs
By default, URLs for pages in SilverStripe (the `SiteTree->URLSegment` property) By default, URLs for pages in SilverStripe (the `SiteTree->URLSegment` property)
are automatically reduced to the allowed allowed subset of ASCII characters. are automatically reduced to the allowed allowed subset of ASCII characters.
If characters outside this subset are added, they are either removed or (if possible) "transliterated". If characters outside this subset are added, they are either removed or (if possible) "transliterated".
This describes the process of converting from one character set to another This describes the process of converting from one character set to another
while keeping characters recognizeable. For example, vowels with french accents while keeping characters recognizeable. For example, vowels with french accents
are replaced with their base characters, `pâté` becomes `pate`. are replaced with their base characters, `pâté` becomes `pate`.
In order to allow for so called "multibyte" characters outside of the ASCII subset, In order to allow for so called "multibyte" characters outside of the ASCII subset,
@ -128,21 +130,21 @@ Date- and time related form fields support i18n ([api:DateField], [api:TimeField
$field = new DateField(); // will automatically set date format defaults for 'ca_AD' $field = new DateField(); // will automatically set date format defaults for 'ca_AD'
$field->setLocale('de_DE'); // will not update the date formats $field->setLocale('de_DE'); // will not update the date formats
$field->setConfig('dateformat', 'dd. MMMM YYYY'); // sets typical 'de_DE' date format, shows as "23. Juni 1982" $field->setConfig('dateformat', 'dd. MMMM YYYY'); // sets typical 'de_DE' date format, shows as "23. Juni 1982"
Defaults can be applied globally for all field instances through the `DateField.default_config` Defaults can be applied globally for all field instances through the `DateField.default_config`
and `TimeField.default_config` [configuration arrays](/topics/configuration). and `TimeField.default_config` [configuration arrays](/topics/configuration).
If no 'locale' default is set on the field, [api:i18n::get_locale()] will be used. If no 'locale' default is set on the field, [api:i18n::get_locale()] will be used.
**Important:** Form fields in the CMS are automatically configured according to the profile settings for the logged-in user (`Member->Locale`, `Member->DateFormat` and `Member->TimeFormat`). This means that in most cases, **Important:** Form fields in the CMS are automatically configured according to the profile settings for the logged-in user (`Member->Locale`, `Member->DateFormat` and `Member->TimeFormat`). This means that in most cases,
fields created through [api:DataObject::getCMSFields()] will get their i18n settings from a specific member fields created through [api:DataObject::getCMSFields()] will get their i18n settings from a specific member
The [api:DateField] API can be enhanced by JavaScript, and comes with The [api:DateField] API can be enhanced by JavaScript, and comes with
[jQuery UI datepicker](http://jqueryui.com/demos/datepicker/) capabilities built-in. [jQuery UI datepicker](http://jqueryui.com/demos/datepicker/) capabilities built-in.
The field tries to translate the date formats and locales into a format compatible with jQuery UI The field tries to translate the date formats and locales into a format compatible with jQuery UI
(see [api:DateField_View_JQuery::$locale_map_] and [api:DateField_View_JQuery::convert_iso_to_jquery_format()]). (see [api:DateField_View_JQuery::$locale_map_] and [api:DateField_View_JQuery::convert_iso_to_jquery_format()]).
:::php :::php
$field = new DateField(); $field = new DateField();
$field->setLocale('de_AT'); // set Austrian/German locale $field->setLocale('de_AT'); // set Austrian/German locale
$field->setConfig('showcalendar', true); $field->setConfig('showcalendar', true);
$field->setConfig('jslocale', 'de'); // jQuery UI only has a generic German localization $field->setConfig('jslocale', 'de'); // jQuery UI only has a generic German localization
@ -164,10 +166,10 @@ All strings passed through the `_t()` function will be collected in a separate l
### The _t() function ### The _t() function
The `_t()` function is the main gateway to localized text, and takes four parameters, all but the first being optional. The `_t()` function is the main gateway to localized text, and takes four parameters, all but the first being optional.
It can be used to translate strings in both PHP files and template files. The usage for each case is described below. It can be used to translate strings in both PHP files and template files. The usage for each case is described below.
* **$entity:** Unique identifier, composed by a namespace and an entity name, with a dot separating them. Both are arbitrary names, although by convention we use the name of the containing class or template. Use this identifier to reference the same translation elsewhere in your code. * **$entity:** Unique identifier, composed by a namespace and an entity name, with a dot separating them. Both are arbitrary names, although by convention we use the name of the containing class or template. Use this identifier to reference the same translation elsewhere in your code.
* **$string:** (optional) The original language string to be translated. Only needs to be declared once, and gets picked up the [text collector](#collecting-text). * **$string:** (optional) The original language string to be translated. Only needs to be declared once, and gets picked up the [text collector](#collecting-text).
* **$string:** (optional) Natural language comment (particularly short phrases and individual words) * **$string:** (optional) Natural language comment (particularly short phrases and individual words)
are very context dependent. This parameter allows the developer to convey this information are very context dependent. This parameter allows the developer to convey this information
@ -177,13 +179,13 @@ to the translator.
#### Usage in PHP Files #### Usage in PHP Files
:::php :::php
// Simple string translation // Simple string translation
_t('LeftAndMain.FILESIMAGES','Files & Images'); _t('LeftAndMain.FILESIMAGES','Files & Images');
// Using the natural languate comment parameter to supply additional context information to translators // Using the natural languate comment parameter to supply additional context information to translators
_t('LeftAndMain.HELLO','Site content','Menu title'); _t('LeftAndMain.HELLO','Site content','Menu title');
// Using injection to add variables into the translated strings. // Using injection to add variables into the translated strings.
_t('CMSMain.RESTORED', _t('CMSMain.RESTORED',
"Restored {value} successfully", "Restored {value} successfully",
@ -207,13 +209,13 @@ the PHP version of the function.
:::ss :::ss
// Simple string translation // Simple string translation
<%t Namespace.Entity "String to translate" %> <%t Namespace.Entity "String to translate" %>
// Using the natural languate comment parameter to supply additional context information to translators // Using the natural languate comment parameter to supply additional context information to translators
<%t SearchResults.NoResult "There are no results matching your query." is "A message displayed to users when the search produces no results." %> <%t SearchResults.NoResult "There are no results matching your query." is "A message displayed to users when the search produces no results." %>
// Using injection to add variables into the translated strings (note that $Name and $Greeting must be available in the current template scope). // Using injection to add variables into the translated strings (note that $Name and $Greeting must be available in the current template scope).
<%t Header.Greeting "Hello {name} {greeting}" name=$Name greeting=$Greeting %> <%t Header.Greeting "Hello {name} {greeting}" name=$Name greeting=$Greeting %>
#### Caching in Template Files with locale switching #### Caching in Template Files with locale switching
When caching a `<% loop %>` or `<% with %>` with `<%t params %>`. It is important to add the Locale to the cache key otherwise it won't pick up locale changes. When caching a `<% loop %>` or `<% with %>` with `<%t params %>`. It is important to add the Locale to the cache key otherwise it won't pick up locale changes.
@ -256,7 +258,7 @@ By default, the language files are loaded from modules in this order:
This default order is configured in `framework/_config/i18n.yml`. This file specifies two blocks of module ordering: `basei18n`, listing admin, and framework, and `defaulti18n` listing all other modules. This default order is configured in `framework/_config/i18n.yml`. This file specifies two blocks of module ordering: `basei18n`, listing admin, and framework, and `defaulti18n` listing all other modules.
To create a custom module order, you need to specify a config fragment that inserts itself either after or before those items. For example, you may have a number of modules that have to come after the framework/admin, but before anyhting else. To do that, you would use this To create a custom module order, you need to specify a config fragment that inserts itself either after or before those items. For example, you may have a number of modules that have to come after the framework/admin, but before anyhting else. To do that, you would use this
--- ---
Name: customi18n Name: customi18n
@ -282,7 +284,7 @@ Each module can have one language table per locale, stored by convention in the
The translation is powered by [Zend_Translate](http://framework.zend.com/manual/en/zend.translate.html), The translation is powered by [Zend_Translate](http://framework.zend.com/manual/en/zend.translate.html),
which supports different translation adapters, dealing with different storage formats. which supports different translation adapters, dealing with different storage formats.
By default, SilverStripe 3.x uses a YAML format (through the [Zend_Translate_RailsYAML adapter](https://github.com/chillu/zend_translate_railsyaml)). By default, SilverStripe 3.x uses a YAML format (through the [Zend_Translate_RailsYAML adapter](https://github.com/chillu/zend_translate_railsyaml)).
Example: framework/lang/en.yml (extract) Example: framework/lang/en.yml (extract)
@ -305,7 +307,7 @@ The cache can be cleared through the `?flush=1` query parameter,
or explicitly through `Zend_Translate::getCache()->clean(Zend_Cache::CLEANING_MODE_ALL)`. or explicitly through `Zend_Translate::getCache()->clean(Zend_Cache::CLEANING_MODE_ALL)`.
<div class="hint" markdown='1'> <div class="hint" markdown='1'>
The format of language definitions has changed significantly in since version 2.x. The format of language definitions has changed significantly in since version 2.x.
</div> </div>
In order to enable usage of [version 2.x style language definitions](http://doc.silverstripe.org/framework/en/2.4/topics/i18n#language-tables-in-php) in 3.x, you need to register a legacy adapter In order to enable usage of [version 2.x style language definitions](http://doc.silverstripe.org/framework/en/2.4/topics/i18n#language-tables-in-php) in 3.x, you need to register a legacy adapter
@ -330,10 +332,10 @@ Unlike the PHP logic, these files aren't auto-discovered and have to be included
### Requirements ### Requirements
Each language has its own language table in a separate file. Each language has its own language table in a separate file.
To save bandwidth, only two files are actually loaded by To save bandwidth, only two files are actually loaded by
the browser: The current locale, and the default locale as a fallback. the browser: The current locale, and the default locale as a fallback.
The `Requirements` class has a special method to determine these includes: The `Requirements` class has a special method to determine these includes:
Just point it to a directory instead of a file, and the class will figure out the includes. Just point it to a directory instead of a file, and the class will figure out the includes.
:::php :::php
@ -364,8 +366,8 @@ Example Translation Table (`<my-module-dir>/javascript/lang/de.js`)
'MYMODULE.MYENTITY' : "Artikel wirklich löschen?" 'MYMODULE.MYENTITY' : "Artikel wirklich löschen?"
}); });
For most core modules, these files are generated by a For most core modules, these files are generated by a
[build task](https://github.com/silverstripe/silverstripe-buildtools/blob/master/src/GenerateJavascriptI18nTask.php), [build task](https://github.com/silverstripe/silverstripe-buildtools/blob/master/src/GenerateJavascriptI18nTask.php),
with the actual source files in a JSON with the actual source files in a JSON
format which can be processed more easily by external translation providers (see `javascript/lang/src`). format which can be processed more easily by external translation providers (see `javascript/lang/src`).

View File

@ -1,3 +1,5 @@
summary: Learn how to deal with File and Image records
# Files, Images and Folders # Files, Images and Folders
## Files, Images and Folders as database records ## Files, Images and Folders as database records

View File

@ -0,0 +1,7 @@
summary: Extend the admin view to provide custom behavior or new features for CMS users.
[CHILDREN]
## How-to
[CHILDREN How_To]

View File

@ -1,13 +1,15 @@
summary: An overview of the steps involved in delivering a SilverStripe web page.
# Execution Pipeline # Execution Pipeline
## Introduction ## Introduction
This page documents all the steps from an URL request to the delivered page. This page documents all the steps from an URL request to the delivered page.
## .htaccess and RewriteRule ## .htaccess and RewriteRule
Silverstripe uses **[mod_rewrite](http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html)** to deal with page requests. Silverstripe uses **[mod_rewrite](http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html)** to deal with page requests.
So instead of having your normal everyday `index.php` file which tells all, you need to look elsewhere. So instead of having your normal everyday `index.php` file which tells all, you need to look elsewhere.
The basic .htaccess file after installing SilverStripe looks like this: The basic .htaccess file after installing SilverStripe looks like this:
@ -81,15 +83,15 @@ You can access the following controller-method with /team/signup
:::php :::php
class Team extends DataObject {} class Team extends DataObject {}
class Team_Controller extends Controller { class Team_Controller extends Controller {
private static $allowed_actions = array('signup'); private static $allowed_actions = array('signup');
public function signup($id, $otherId) { public function signup($id, $otherId) {
return $this->renderWith('MyTemplate'); return $this->renderWith('MyTemplate');
} }
} }
## SSViewer template rendering ## SSViewer template rendering

View File

@ -1,4 +1,6 @@
# Commandline Usage via "sake" summary: Automate SilverStripe, run cronjobs or sync with other platforms through the sake Command Line Interface.
# Command line usage
## Introduction ## Introduction
@ -27,7 +29,7 @@ All parameters will be available in `$_GET` within SilverStripe.
Sake is a simple wrapper around `cli-script.php`. It also tries to detect which `php` executable to use Sake is a simple wrapper around `cli-script.php`. It also tries to detect which `php` executable to use
if more than one are available. if more than one are available.
**If you are using a debian server:** Check you have the php-cli package installed for sake to work. **If you are using a debian server:** Check you have the php-cli package installed for sake to work.
If you get an error when running the command php -v, then you may not have php-cli installed so sake won't work. If you get an error when running the command php -v, then you may not have php-cli installed so sake won't work.
### Installation ### Installation
@ -147,7 +149,7 @@ php-cli /path/to/site_root/framework/cli-script.php dev/tasks/MyTask
``` ```
A good approach to setting up and testing your task to run with cron is: A good approach to setting up and testing your task to run with cron is:
1. Try running the task via the command-line on your server. `/path/to/site_root/framework/sake dev/tasks/MyTask` 1. Try running the task via the command-line on your server. `/path/to/site_root/framework/sake dev/tasks/MyTask`
2. Set up a cron job to run the task every minute. `* * * * * /path/to/site_root/framework/sake dev/tasks/MyTask` 2. Set up a cron job to run the task every minute. `* * * * * /path/to/site_root/framework/sake dev/tasks/MyTask`
3. Finally, set the task to run when you want it to. `0 2 * * * /path/to/site_root/framework/sake dev/tasks/MyTask` (2am) 3. Finally, set the task to run when you want it to. `0 2 * * * /path/to/site_root/framework/sake dev/tasks/MyTask` (2am)

View File

@ -1,8 +1,7 @@
#Developer Guides title: Developer Guides
A collection of more advanced functionality and features contained within the SilverStripe Framework. This covers common use cases, provides code examples and explanations of how you might use parts of the Framework and CMS to suit your projects. introduction: The following guides take a more detailed look into the core concepts and code examples for building SilverStripe applications.
This is by no means a completely exhaustive list of Classes and Methods but rather more of a descriptive book style format with examples. In each guide you'll find reference documentation followed by a collection of short and informal How-to's which contain
snippets of code to use in your own projects.
Each key section will also contain a "How To" section into which we accept community contributed code examples and more specific use cases. [CHILDREN]
TODO - A table of contents including any missing stub pages.

View File

@ -0,0 +1,4 @@
title: Upgrading
introduction: Keep your SilverStripe installations up to date with the latest fixes, security patches and new features.
# Upgrading

View File

@ -1,134 +1,11 @@
# Changelogs title: Changelogs
introduction: Key information on new features and improvements in each version.
Keep up to date with new releases subscribe to the [SilverStripe Release Announcements](https://groups.google.com/group/silverstripe-announce) group, Keep up to date with new releases subscribe to the [SilverStripe Release Announcements](https://groups.google.com/group/silverstripe-announce) group,
or read our [blog posts about releases](http://silverstripe.org/blog/tag/release). or read our [blog posts about releases](http://silverstripe.org/blog/tag/release).
We also keep an overview of [security-related releases](http://silverstripe.org/security-releases/). We also keep an overview of [security-related releases](http://silverstripe.org/security-releases/).
For information on how to upgrade to newer versions consult the [upgrading](/installation/upgrading) guide. For information on how to upgrade to newer versions consult the [upgrading](/upgrading) guide.
## Stable Releases [CHILDREN]
* [3.2.0](3.2.0) - Unreleased
* [3.1.8](3.1.8) - 18 November 2014
* [3.1.7](3.1.7) - 14 November 2014
* [3.1.6](3.1.6) - 25 August 2014
* [3.1.5](3.1.5) - 13 May 2014
* [3.1.4](3.1.4) - 8 April 2014
* [3.1.0](3.1.0) - 1 October 2013
* [3.0.11](3.0.11) - 13 May 2014
* [3.0.10](3.0.10) - 8 April 2014
* [3.0.5](3.0.5) - 20 February 2013
* [3.0.4](3.0.4) - 19 February 2013
* [3.0.3](3.0.3) - 26 November 2012
* [3.0.2](3.0.2) - 17 September 2012
* [3.0.1](3.0.1) - 31 July 2012
* [3.0.0](3.0.0) - 28 June 2012
* [2.4.7](2.4.7) - 1 February 2012
* [2.4.6](2.4.6) - 18 October 2011
* [2.4.10](2.4.10) - 2013-02-19
* [2.4.9](2.4.9) - 2012-12-04
* [2.4.8](2.4.8) - 2012-10-30
* [2.4.7](2.4.7) - 2012-02-01
* [2.4.6](2.4.6) - 2011-10-17
* [2.4.5](2.4.5) - 2 February 2011
* [2.4.4](2.4.4) - 21 December 2010
* [2.4.3](2.4.3) - 11 November 2010
* [2.4.2](2.4.2) - 22 September 2010
* [2.4.1](2.4.1) - 23 July 2010
* [2.4.0](2.4.0)
* [2.3.13](2.3.13) - 1 February 2012
* [2.3.12](2.3.12) - 17 October 2011
* [2.3.11](2.3.11) - 2 February 2011
* [2.3.10](2.3.10) - 21 December 2010
* [2.3.9](2.3.9) - 11 November 2010
* [2.3.8](2.3.8) - 23 July 2010
* [2.3.7](2.3.7) - 18 March 2010
* [2.3.6](2.3.6) - 8 February 2010
* [2.3.5](2.3.5) - 21 January 2010
* [2.3.4](2.3.4) - 27 November 2009
* [2.3.3](2.3.3) - 3 August 2009
* [2.3.2](2.3.2) - 18 June 2009
* [2.3.1](2.3.1) - 19 March 2009
* [2.3.0](2.3.0) - 23 February 2009
* [2.2.4](2.2.4) - 20 March 2009
* [2.2.3](2.2.3) - ~31 October 2008
* [2.2.2](2.2.2) - 22 May 2008
* [2.2.1](2.2.1) - 21 December 2007
* [2.2.0](2.2.0) - 28 November 2007
* [2.1.1](2.1.1) - 2 November 2007
* [2.1.0](2.1.0) - 2 October 2007
* [2.0.2](2.0.2) - 14 July 2007
* [2.0.1](2.0.1) - 17 April 2007
* 2.0.0 - 3 February 2007 (initial release)
## Alpha/beta/release candidate
* [3.1.7-rc1](rc/3.1.7-rc1) - 8 November 2014
* [3.1.6-rc3](rc/3.1.6-rc3) - 18 August 2014
* [3.1.6-rc2](rc/3.1.6-rc2) - 12 August 2014
* [3.1.6-rc1](rc/3.1.6-rc1) - 5 August 2014
* [3.1.5-rc1](rc/3.1.5-rc1) - 7 May 2014
* [3.1.4-rc1](rc/3.1.4-rc1) - 1 April 2014
* [3.0.11-rc1](rc/3.0.11-rc1) - 7 May 2014
* [3.0.10-rc1](rc/3.0.10-rc1) - 1 April 2014
* [3.0.6-rc1](rc/3.0.6-rc1) - 2013-08-08
* [3.0.3-rc1](rc/3.0.3-rc1) - 6 November 2012
* [3.0.2-rc2](rc/3.0.2-rc2) - 12 September 2012
* [3.0.2-rc1](rc/3.0.2-rc1) - 5 September 2012
* [3.0.0-rc3](rc/3.0.0-rc3) - 27 June 2012
* [3.0.0-rc2](rc/3.0.0-rc2) - 26 June 2012
* [3.0.0-rc1](rc/3.0.0-rc1) - 18 June 2012
* [3.0.0-beta3](beta/3.0.0-beta3) - 28 May 2012
* [3.0.0-beta2](beta/3.0.0-beta2) - 20 April 2012
* [3.0.0-beta1](beta/3.0.0-beta1) - 12 March 2012
* [3.0.0-alpha2](alpha/3.0.0-alpha2) - 12 January 2012
* [3.0.0-alpha1](alpha/3.0.0-alpha1) - 1 November 2011
* [3.0.0-pr1](pr/3.0.0-pr1) - 2 May 2011
* [2.4.5-rc1](rc/2.4.5-rc1) - 31 January 2011
* [2.4.4-rc2](rc/2.4.4-rc2) - 20 December 2010
* [2.4.4-rc1](rc/2.4.4-rc1) - 10 December 2010
* [2.4.3-rc2](rc/2.4.3-rc2) - 4 November 2010
* [2.4.3-rc1](rc/2.4.3-rc1) - 1 November 2010
* [2.4.2-rc2](rc/2.4.2-rc2) - 20 September 2010
* [2.4.2-rc1](rc/2.4.2-rc1) - 16 September 2010
* [2.4.1-rc2](rc/2.4.1-rc2) - 21 July 2010
* [2.4.1-rc1](rc/2.4.1-rc1) - 16 July 2010
* [2.4.0-rc3](rc/2.4.0-rc3) - 4 May 2010
* [2.4.0-rc2](rc/2.4.0-rc2) - 30 April 2010
* [2.4.0-rc1](rc/2.4.0-rc1) - 1st April 2010
* [2.4.0-beta2](beta/2.4.0-beta2) - 17 March 2010
* [2.4.0-beta1](beta/2.4.0-beta1) - 29 January 2010
* [2.4.0-alpha1](alpha/2.4.0-alpha1) - 11 November 2009
* [2.3.11-rc1](rc/2.3.11-rc1) - 31 January 2011
* [2.3.10-rc2](rc/2.3.10-rc2) - 20 December 2010
* [2.3.10-rc1](rc/2.3.10-rc1) - 10 December 2010
* [2.3.9-rc2](rc/2.3.9-rc2) - 4 November 2010
* [2.3.9-rc1](rc/2.3.9-rc1) - 1 November 2010
* [2.3.8-rc1](rc/2.3.8-rc1) - 16 July 2010

View File

@ -1,7 +1,5 @@
# Contributing Issues and Opinions # Contributing Issues and Opinions
[« Back to Contributing page](../contributing)
## Reporting Bugs ## Reporting Bugs
If you have discovered a bug in SilverStripe, we'd be glad to hear about it - If you have discovered a bug in SilverStripe, we'd be glad to hear about it -

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB