Small text changes, added api links, cont. updating images for tutorials, fixed tutorials from member feedback

This commit is contained in:
Michael Andrewartha 2011-03-09 10:05:51 +13:00
parent e260b697c0
commit 626980acb5
79 changed files with 722 additions and 647 deletions

View File

@ -406,7 +406,7 @@ to debug.
## Related
* [Templates](/topics/templates)
* [Themes](/topics/themes)
* [Developing Themes](theme-development)
* [Developing Themes](/topics/theme-development)
* [Widgets](/topics/widgets)
* [Images](/reference/image)
* [Built in page controls](/reference/built-in-page-controls)

View File

@ -9,7 +9,7 @@ BBCode is used by default in the [blog](http://silverstripe.org/blog-module) and
To add bbcode parsing to a template, instead of $Content use:
:::php
:::ss
$Content.Parse(BBCodeParser)

View File

@ -60,7 +60,7 @@ SilverStripe supports a simple set of conditional logic
<% end_if %>
See more information on conditional logic on [templates](templates).
See more information on conditional logic on [templates](/topics/templates).
### Site wide settings

View File

@ -15,7 +15,7 @@ See `[api:TableListField]`.
## Setting Parent/Child-Relations
ComplexTableField tries to determine the parent-relation automatically by looking at the $has_one property on the listed
`[api:ComplexTableField]` tries to determine the parent-relation automatically by looking at the $has_one property on the listed
child, or the record loaded into the surrounding form (see getParentClass() and getParentIdName()). You can force a
specific parent relation:
@ -62,18 +62,18 @@ You can override this behaviour in various ways:
If you don't want several functions to appear (e.g. no add-link), there's several ways:
* Use ComplexTableField->setPermissions(array("show","edit")) to limit the functionality without touching the template
* Use `ComplexTableField->setPermissions(array("show","edit"))` to limit the functionality without touching the template
(more secure). Possible values are "show","edit", "delete" and "add".
* Subclass ComplexTableField and override the rendering-mechanism
* Use ComplexTableField->setTemplate() and ComplexTableField->setTemplatePopup() to provide custom templates
* Subclass `[api:ComplexTableField]` and override the rendering-mechanism
* Use `ComplexTableField->setTemplate()` and `ComplexTableField->setTemplatePopup()` to provide custom templates
### Customising fields and Requirements in the popup
There are several ways to customise the fields in the popup. Often you would want to display more information in the
popup as there is more real-estate for you to play with.
ComplexTableField gives you several options to do this. You can either
`[api:ComplexTableField]` gives you several options to do this. You can either
* Pass a FieldSet in the constructor.
* Pass a String in the constructor.
@ -83,7 +83,7 @@ The second will call the String as a method on the source class (Which should re
Popup.
You can also customise Javascript which is loaded for the Lightbox. As Requirements::clear() is called when the popup is
instantiated, ComplexTableField will look for a function to gather any specific requirements that you might need on your
instantiated, `[api:ComplexTableField]` will look for a function to gather any specific requirements that you might need on your
source class. (e.g. Inline Javascript or styling).
For this, create a function called "getRequirementsForPopup".
@ -116,11 +116,11 @@ You'll have to do something like this in your form:
You have to hack in an ID on the form, as the CMS forms have this, and front end forms usually do not.
It's not a perfect solution, but it works relatively well to get a simple ComplexTableField up and running on the front
It's not a perfect solution, but it works relatively well to get a simple `[api:ComplexTableField]` up and running on the front
end.
To come: Make it a lot more flexible so tables can be easily used on the front end. It also needs to be flexible enough
to use a popup as well, out of the box.
to use a popup as well, out of the box.
## Subclassing
@ -144,7 +144,7 @@ Most of the time, you need to override the following methods:
* Find a less fragile solution for accessing this field through the main controller and ReferencedField, e.g. build a
seperate CTF-instance (doesn't necessarly have to be connected to the original by ReferencedField)
* Control width/height of popup by constructor (hardcoded at the moment)
* Integrate search from MemberTableField.php directly on ComplexTableField
* Integrate search from MemberTableField.php directly on `[api:ComplexTableField]`
* Less performance-hungry implementation of detail-view paging (don't return all items on a single view)
* Use automatic has-many and many-many functions to return a ComponentSet rather than building the join manually
* Javascript/Ajax-Sorting (see http://www.activewidgets.com/grid/ and http://openrico.org/rico/livegrid.page)
* Javascript/Ajax-Sorting (see [http://www.activewidgets.com/grid/](http://www.activewidgets.com/grid/) and [http://openrico.org/rico/livegrid.page](http://openrico.org/rico/livegrid.page))

View File

@ -5,7 +5,7 @@ opting for "convention over configuration". This page details what that databas
## Base tables
Each direct sub-class of DataObject will have its own table.
Each direct sub-class of `[api:DataObject]` will have its own table.
The following fields are always created.
@ -36,21 +36,21 @@ data sub-classed objects across **multiple tables**.
For example, suppose we have the following set of classes:
* Class SiteTree extends DataObject: Title, Content fields
* Class Page extends SiteTree: Abstract field
* Class NewsSection extends SiteTree: *No special fields*
* Class NewsArticle extend Page: ArticleDate field
* Class `[api:SiteTree]` extends `[api:DataObject]`: Title, Content fields
* Class `[api:Page]` extends `[api:SiteTree]`: Abstract field
* Class NewsSection extends `[api:SiteTree]`: *No special fields*
* Class NewsArticle extend `[api:Page]`: ArticleDate field
The data for the following classes would be stored across the following tables:
* SiteTree
* `[api:SiteTree]`
* ID: Int
* ClassName: Enum('SiteTree', 'Page', 'NewsArticle')
* Created: Datetime
* LastEdited: Datetime
* Title: Varchar
* Content: Text
* Page
* `[api:Page]`
* ID: Int
* Abstract: Text
* NewsArticle
@ -59,16 +59,16 @@ The data for the following classes would be stored across the following tables:
The way it works is this:
* "Base classes" are direct sub-classes of DataObject. They are always given a table, whether or not they have special
fields. This is called the "base table"
* "Base classes" are direct sub-classes of `[api:DataObject]`. They are always given a table, whether or not they have
special fields. This is called the "base table"
* The base table's ClassName field is set to class of the given record. It's an enumeration of all possible
sub-classes of the base class (including the base class itself)
* Each sub-class of the base object will also be given its own table, *as long as it has custom fields*. In the
example above, NewsSection didn't have its own data and so an extra table would be redundant.
* In all the tables, ID is the primary key. A matching ID number is used for all parts of a particular record:
record #2 in Page refers to the same object as record #2 in SiteTree.
record #2 in Page refers to the same object as record #2 in `[api:SiteTree]`.
To retrieve a news article, SilverStripe joins the SiteTree, Page and NewsArticle tables by their ID fields. We use a
To retrieve a news article, SilverStripe joins the `[api:SiteTree]`, `[api:Page]` and NewsArticle tables by their ID fields. We use a
left-join for robustness; if there is no matching record in Page, we can return a record with a blank Article field.
## Staging and versioning
@ -126,4 +126,4 @@ other database platforms if we chose to support them.
* We'd like to support more than just MySQL, however, there needs to be a pretty good reason for doing so since it will
become something that needs to be supported for the rest of SilverStripe's life and could easily become an albatross.
On the cards are MS SQL, PostgreSQL and SQLite.
* It could be desireable to implement a non-repeating auto-numbering system.
* It could be desirable to implement a non-repeating auto-numbering system.

View File

@ -12,7 +12,7 @@ A single database record & abstract class for the data-access-model.
## Basics
The call to `DataObject->getCMSFields()` is the centerpiece of every data administration interface in Silverstripe,
The call to `DataObject->getCMSFields()` is the centerpiece of every data administration interface in SilverStripe,
which returns a `[api:FieldSet]`''.
:::php
@ -33,8 +33,6 @@ These calls retrieve a `[api:FieldSet]` for the area where you intend to work wi
* Requirements: SilverStripe 2.3.*
// bla
:::php
$fields = singleton('MyDataObject')->getCMSFields();
@ -82,8 +80,8 @@ Example: Simple Definition
}
Searchable fields will be appear in the search interface with a default form field (usually a TextField) and a default
search filter assigned (usually an ExactMatchFilter). To override these defaults, you can specify additional information
Searchable fields will be appear in the search interface with a default form field (usually a `[api:TextField]`) and a default
search filter assigned (usually an `[api:ExactMatchFilter]`). To override these defaults, you can specify additional information
on `$searchable_fields`:
:::php
@ -95,7 +93,7 @@ on `$searchable_fields`:
}
If you assign a single string value, you can set it to be either a FormField or SearchFilter. To specify both, you can
If you assign a single string value, you can set it to be either a `[api:FormField]` or `[api:SearchFilter]`. To specify both, you can
assign an array:
:::php
@ -144,7 +142,7 @@ To include relations (''$has_one'', `$has_many` and `$many_many`) in your search
* Requirements: SilverStripe 2.3.*
Summary fields can be used to show a quick overview of the data for a specific DataObject record. Most common use is
Summary fields can be used to show a quick overview of the data for a specific `[api:DataObject]` record. Most common use is
their display as table columns, e.g. in the search results of a `[api:ModelAdmin]` CMS interface.
Example: Getting predefined summary fields

View File

@ -9,7 +9,7 @@ implementation. Have a look at `[api:Object->useCustomClass()]`.
## Usage
Your Decorator will nee to be a subclass of DataObjectDecorator or the Extension class.
Your Decorator will nee to be a subclass of `[api:DataObjectDecorator]` or the `[api:Extension]` class.
:::php
<?php
@ -27,7 +27,7 @@ class you want to extend.
### Adding a decorator to a built-in class
Sometimes you will want to add decorators to classes that you didn't make. For example, you might want to add the
ForumRole decorator to the Member object.
`[api:ForumRole]` decorator to the `[api:Member]` object.
:::php
@ -97,20 +97,20 @@ The $fields parameter is passed by reference, as it is an object.
### Custom database generation
Some decorators are designed to transparently add more sophisticated data-collection capabilities to your data object.
For example, Versioned adds version tracking and staging to any data object that it is applied to. To do this, you need
to be able to create additional database tables and fields to keep your state stored in.
Some decorators are designed to transparently add more sophisticated data-collection capabilities to your data object.
For example, `[api:Versioned]` adds version tracking and staging to any data object that it is applied to. To do this,
you need to be able to create additional database tables and fields to keep your state stored in.
To do this, define an **augmentDatabase()** method on your decorator. This will be called when db/build is visited.
* You can query $this->owner for information about the data object, such as the fields it has
* You can query ``$this->owner`` for information about the data object, such as the fields it has
* You can use **DB::requireTable($tableName, $fieldList, $indexList)** to set up your new tables. This function takes
care of creating, modifying, or leaving tables as required, based on your desired schema.
### Custom write queries
If you have customised the generated database, then you probably want to change the way that writes happen. This is
used by Versioned to get an entry written in ClassName_versions whenever an insert/update happens.
used by `[api:Versioned]` to get an entry written in ClassName_versions whenever an insert/update happens.
To do this, define the **augmentWrite(&$manipulation)** method. This method is passed a manipulation array representing
the write about to happen, and is able to amend this as desired, since it is passed by reference.
@ -125,17 +125,17 @@ be modified as needed by your method. Instead of a manipulation array, we have
### Additional methods
The other thing you may want to do with a decorator is provide a method that can be called on the DataObject that is
being decorated. For instance, you may add a publish() method to every DataObject that is decorated with Versioned.
The other thing you may want to do with a decorator is provide a method that can be called on the `[api:DataObject]` that is
being decorated. For instance, you may add a publish() method to every `[api:DataObject]` that is decorated with `[api:Versioned]`.
This is as simple as defining a method called publish() on your decorator. Bear in mind, however, that instead of
$this, you should be referring to $this->owner.
* $this = The DataObjectDecorator object.
* $this->owner = The related DataObject object.
* $this = The `[api:DataObjectDecorator]` object.
* $this->owner = The related `[api:DataObject]` object.
If you want to add your own internal properties, you can add this to the DataObjectDecorator, and these will be referred
to as $this->propertyName. Every DataObject has an associated DataObjectDecorator instance for each class that it is
If you want to add your own internal properties, you can add this to the `[api:DataObjectDecorator]`, and these will be referred
to as `$this->propertyName`. Every `[api:DataObject]` has an associated `[api:DataObjectDecorator]` instance for each class that it is
decorated by.
:::php

View File

@ -6,7 +6,7 @@ This class represents a set of `[api:DataObject]`s, such as the results of a que
[datamodel](/topics/datamodel)-related querying. It implements the [Iterator
interface](http://php.net/manual/en/language.oop5.iterations.php) introduced in PHP5.
Relations (`has_many`/`many_many`) are described in `[api:ComponentSet]`, a subclass of DataObjectSet.
Relations (`has_many`/`many_many`) are described in `[api:ComponentSet]`, a subclass of `[api:DataObjectSet]`.
## Usage
@ -56,7 +56,7 @@ This works on the object itself, so do NOT do something like this:
:::php
$sortedSet = $mySet->sort('Lastname'); //ascending
## Merge with other DataObjectSets
## Merge with other `[api:DataObjectSet]`s
:::php
$myFirstSet->merge($mySecondSet);
@ -88,7 +88,7 @@ It is good practice to check for empty sets before doing any iteration.
### Paging
DataObjects have native support for dealing with **pagination**.
`[api:DataObject]`s have native support for dealing with **pagination**.
See *setPageLimits*, *setPageLength*, etc.
FIXME Complete pagination documentation

View File

@ -2,7 +2,7 @@
## Introduction
Director is the first step in the "execution pipeline". It parses the URL, matching it to one of a number of patterns,
`[api:Director]` is the first step in the "execution pipeline". It parses the URL, matching it to one of a number of patterns,
and determines the controller, action and any argument to be used. It then runs the controller, which will finally run
the viewer and/or perform processing steps.
@ -12,7 +12,7 @@ the viewer and/or perform processing steps.
## Redirection
The Director class has a number of methods to facilitate 301 and 302 HTTP redirection.
The `[api:Director]` class has a number of methods to facilitate 301 and 302 HTTP redirection.
* **Director::redirect("action-name")**: If there's no slash in the URL passed to redirect, then it is assumed that you
want to go to a different action on the current controller.
@ -33,8 +33,8 @@ redirectBack().
You can influence the way URLs are resolved one of 2 ways
1. Adding rules to Director in `<yourproject>/_config.php` (See Default Rewrite Rules below for examples)
2. Adding rules in your extended Controller class via the *$url_handlers* static variable
1. Adding rules to `[api:Director]` in `<yourproject>/_config.php` (See Default Rewrite Rules below for examples)
2. Adding rules in your extended `[api:Controller]` class via the *$url_handlers* static variable
See [controller](/topics/controller) for examples and explanations on how the rules get processed for both 1 and 2 above.
@ -56,7 +56,7 @@ SilverStripe comes with certain rewrite rules (e.g. for *admin/assets*).
## Links
* See ModelAsController class for details on controller/model-coupling
* See `[api:ModelAsController]` class for details on controller/model-coupling
* See [execution-pipeline](/reference/execution-pipeline) for custom routing
## API Documentation

View File

@ -53,7 +53,7 @@ All requests go through main.php, which sets up the environment and then hands c
**See:** The API documentation of `[api:Main]` for information about how main.php processes requests.
## Director and URL patterns
main.php relies on Director to work out which controller should handle this request. Director will instantiate that
main.php relies on `[api:Director]` to work out which controller should handle this request. `[api:Director]` will instantiate that
controller object and then call `[api:Controller::run()]`.
**See:** The API documentation of `[api:Director]` for information about how Director parses URLs and hands control over to a controller object.
@ -73,7 +73,7 @@ When you create a function, you can access the ID like this:
## Controllers and actions
Controllers are the building blocks of your application.
`[api:Controller]`s are the building blocks of your application.
**See:** The API documentation for `[api:Controller]`

View File

@ -48,7 +48,7 @@ set {inlcudeDefaultJS} to false and work with behaviour.js.
* `[FileField](api:FileField)`: Simple file upload dialog.
* `[FileIFrameField](api:FileIFrameField)`: File uploads through an iframe
* `[api:Image]`: Image upload through an iframe, with thumbnails and file-selection from existing assets
* `[api:ImageField]`: Image upload through an iframe, with thumbnails and file-selection from existing assets
* `[SimpleImageField](api:SimpleImageField)`: SimpleImageField provides an easy way of uploading images to Image has_one
relationships. Unlike ImageField, it doesn't use an iframe.

View File

@ -111,8 +111,8 @@ and whenever you upload or modify an Image through SilverStripe.
If you encounter problems with images not appearing, or have mysteriously disappeared, you can try manually flushing the
image cache.
http://www.mysite.com/images/flush
## API Documentation
`[api:Image]`

View File

@ -2,6 +2,7 @@
Reference articles complement our auto-generated [API docs](http://api.silverstripe.org) in providing deeper introduction into a specific API.
* [Advanced templates](advanced-templates): Advanced SilverStripe template syntax
* [BBCode](bbcode): Extensible shortcode syntax
* [Built-in page controls](built-in-page-controls): Explains the template syntax and available variables/placeholders
* [ComplexTableField](complextablefield): Manage records and their relations inside the CMS
@ -29,7 +30,6 @@ Reference articles complement our auto-generated [API docs](http://api.silverstr
* [StaticPublisher](staticpublisher): Export a page tree as static HTML for better performance and portability
* [TableField](tablefield): Add and edit records with inline edits in this form field
* [TableListField](tablelistfield): View and delete records in the CMS
* [Templates](templates): Process our data for output in HTML and other formats
* [Typography](typography): CSS file to enable WYSIWYG previews in the CMS
* [urlvariabletools](urlvariabletools): Debug and maintenance switches
* [Versioned](versioned): Extension for SiteTree and other classes to store old versions and provide "staging"

View File

@ -2,11 +2,11 @@
## Introduction
The Member class is used to represent user accounts on a SilverStripe site (including newsletter recipients).
The `[api:Member]` class is used to represent user accounts on a SilverStripe site (including newsletter recipients).
## Testing For Logged In Users
The Member class comes with 2 static methods for getting information about the current logged in user.
The `[api:Member]` class comes with 2 static methods for getting information about the current logged in user.
**Member::currentUserID()**
@ -38,10 +38,11 @@ Returns the full *Member* Object for the current user, returns *null* if user is
## Subclassing
<div class="warning" markdown="1">
This is the least desirable way of extending the Member class. It's better to use DataObjectDecorator (see below).
This is the least desirable way of extending the `[api:Member]` class. It's better to use `[api:DataObjectDecorator]`
(see below).
</div>
You can defined subclasses of member to add extra fields or functionality to the built-in membership system.
You can defined subclasses of `[api:Member]` to add extra fields or functionality to the built-in membership system.
:::php
class MyMember extends Member {
@ -63,8 +64,8 @@ Note that if you want to look this class-name up, you can call Object::getCustom
## Overloading getCMSFields()
If you overload the built-in function getCMSFields(), then you can change the form that is used to view & edit member
details in the newsletter system. This function returns a FieldSet object. You should generally start by calling
parent::getCMSFields() and manipulate the FieldSet from there.
details in the newsletter system. This function returns a `[api:FieldSet]` object. You should generally start by calling
parent::getCMSFields() and manipulate the `[api:FieldSet]` from there.
:::php
function getCMSFields() {
@ -78,11 +79,11 @@ parent::getCMSFields() and manipulate the FieldSet from there.
## Extending Member or DataObject?
Basic rule: Class "Member" should just be extended for entities who have some kind of login.
If you have different types of Members in the system, you have to make sure that those with login-capabilities have
Basic rule: Class `[api:Member]` should just be extended for entities who have some kind of login.
If you have different types of `[api:Member]`s in the system, you have to make sure that those with login-capabilities have
unique email-addresses (as this is used for login-credentials).
For persons without login-capabilities (e.g. for an address-database), you shouldn't extend member to avoid conflicts
with the Member-database. This enables us to have a different subclass of Member for an email-address with login-data,
For persons without login-capabilities (e.g. for an address-database), you shouldn't extend `[api:Member]` to avoid conflicts
with the Member-database. This enables us to have a different subclass of `[api:Member]` for an email-address with login-data,
and another subclass for the same email-address in the address-database.
## Member Role Decorator
@ -95,7 +96,7 @@ class. A better way is to use role decorators to add this behaviour.
// OR
Member::add_role('ForumRole');
A role decorator is simply a subclass of `[api:DataObjectDecorator]` that is designed to be used to add behaviour to Member.
A role decorator is simply a subclass of `[api:DataObjectDecorator]` that is designed to be used to add behaviour to `[api:Member]`.
The roles affect the entire class - all members will get the additional behaviour. However, if you want to restrict
things, you should add appropriate `[api:Permission::checkMember()]` calls to the role's methods.

View File

@ -104,7 +104,7 @@ fields are searched (e.g. "partial match", "fulltext", etc.) using `$searchable_
## Summary Fields
Summary Fields are the columns which are shown in the `[api:TableListField]` when viewing DataObjects. These can be
customized for each DataObject's search results using `$summary_fields`.
customized for each `[api:DataObject]`'s search results using `$summary_fields`.
* See `[api:DataObject]`

View File

@ -55,7 +55,7 @@ From a block that shows a summary of the page edits if administrator, nothing if
Often you want to invalidate a cache when any in a set of objects change, or when the objects in a relationship change.
To help do this, SilverStripe 2.4 also introduces the concept of Aggregates. These calculate and return SQL aggregates
on sets of DataObjects - the most useful for us being the Max aggregate.
on sets of `[api:DataObject]`s - the most useful for us being the Max aggregate.
For example, if we have a menu, we want that menu to update whenever _any_ page is edited, but would like to cache it
otherwise. By using aggregates, that's easy
@ -236,6 +236,4 @@ Can be re-written as:
<% end_control %>
<% end_cached %>
<% end_cached %>
<% end_cached %>

View File

@ -12,7 +12,7 @@ and then select the permissions tab, and add that permission to the list.
The simple usage, Permission::check("PERM_CODE") will detect if the currently logged in member has the given permission.
See the API docs for more options.
** Group ACLs **
**Group ACLs**
* Call **Permission::check("MY_PERMISSION_CODE")** to see if the current user has MY_PERMISSION_CODE.
* MY_PERMISSION_CODE can be loaded into the Security admin on the appropriate group, using the "Permissions" tab.
@ -22,9 +22,9 @@ You can use whatever codes you like, but for the sanity of developers and users,
## PermissionProvider
PermissionProvider is an interface which lets you define a method *providePermissions()*. This method should return a
`[api:PermissionProvider]` is an interface which lets you define a method *providePermissions()*. This method should return a
map of permission code names with a human readable explanation of its purpose (see
[:permission:codes](/reference/permission)).
[permissions:codes](/reference/permission)).
:::php
class Page_Controller implements PermissionProvider {

View File

@ -133,8 +133,7 @@ In your controller's init() function, add:
## CMS Requirements
The Silverstripe core includes a lot of Requirements by itself. Most of these are collated in `[api:LeftAndMain]`//
first.
The SilverStripe core includes a lot of Requirements by itself. Most of these are collated in `[api:LeftAndMain]` first.
## Motivation

View File

@ -2,12 +2,13 @@
## Introduction
RestfulService enables connecting to remote web services which supports REST interface and consume those web services
(for example Flickr, Youtube, Amazon and etc). RestfulService can parse the XML response (sorry no JSON support)
`[api:RestfulService]` enables connecting to remote web services which supports REST interface and consume those web services
(for example [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.
To gain the functionality you can either create a new RestfulService object or create a class extending the
RestfulService (see `flickrservice` and `youtubeservice` modules).
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
[youtubeservice](http://silverstripe.org/youtube-gallery-module/) modules).
## Examples
@ -112,8 +113,8 @@ to get the value of entry node with the namespace media, use:
### Handling Errors
If the web service returned an error (for example, API key not available or inadequate parameters) RestfulService could
delgate the error handling to it's descendant class. To handle the errors define a function called errorCatch
If the web service returned an error (for example, API key not available or inadequate parameters) `[api:RestfulService]`
could delgate the error handling to it's descendant class. To handle the errors define a function called errorCatch
:::php
/*
@ -142,7 +143,7 @@ If you want to bypass error handling on your sub-classes you could define that i
## Other Uses
### How to use RestfulService to easily embed an RSS feed
### How to use `[api:RestfulService]` to easily embed an RSS feed
`[api:RestfulService]` can be used to easily embed an RSS feed (since it's also an xml response) from a site
such as del.icio.us

View File

@ -5,7 +5,7 @@
Generating RSS/Atom-feeds is just a matter of rendering a `[api:DataObject]` and the Page Comment Interface.
Handled through the `[api:RSSFeed]` class.
RSSFeed doesn't limit you to generating "article-based" feeds, it is just as easy to create a feed of your current
`[api:RSSFeed]` doesn't limit you to generating "article-based" feeds, it is just as easy to create a feed of your current
staff-members. The only 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 subclasses of `[api:SiteTree]`.
@ -31,7 +31,7 @@ your website, so its advisable to just create feeds from subclasses of `[api:Sit
### Example of showing the 10 most recently updated pages
You can use RSSFeed to easily create a feed showing your latest Page updates. Just change mysite/code/Page.php to
You can use `[api:RSSFeed]` to easily create a feed showing your latest Page updates. Just change mysite/code/Page.php to
something like this:
:::php
@ -44,7 +44,7 @@ something like this:
}
class Page_Controller extends ContentController {
function init() {
RSSFeed::linkToFeed($this->Link() . "rss", "10 Most Recently Updated Pages");
parent::init();
@ -72,7 +72,7 @@ can also do http://www.yoursite.com/PageComment/rss?pageid=46 where pageid is th
## External Sources
RSSFeed only creates feeds from your own data. We've included the [SimplePie](http://simplepie.org) RSS-parser for
`[api:RSSFeed]` only creates feeds from your own data. We've included the [SimplePie](http://simplepie.org) RSS-parser for
accessing feeds from external sources.

View File

@ -3,16 +3,16 @@
## Introduction
Manages searching of properties on one or more `[api:DataObject]` types, based on a given set of input parameters.
SearchContext is intentionally decoupled from any controller-logic,
`[api:SearchContext]` is intentionally decoupled from any controller-logic,
it just receives a set of search parameters and an object class it acts on.
The default output of a SearchContext is either a `[api:SQLQuery]` object for further refinement, or a
The default output of a `[api:SearchContext]` is either a `[api:SQLQuery]` object for further refinement, or a
`[api:DataObject]` instance.
In case you need multiple contexts, consider namespacing your request parameters by using `FieldSet->namespace()` on
the $fields constructor parameter.
SearchContext is mainly used by `[api:ModelAdmin]`, our generic data administration interface. Another
`[api:SearchContext]` is mainly used by `[api:ModelAdmin]`, our generic data administration interface. Another
implementation can be found in generic frontend search forms through the [genericviews](http://silverstripe.org/generic-views-module) module.
## Requirements
@ -33,9 +33,10 @@ See `[api:DataObject::$searchable_fields]`.
### Customizing fields and filters
In this example we're defining three attributes on our MyDataObject subclasss: `PublicProperty`, `HiddenProperty`
In this example we're defining three attributes on our MyDataObject subclass: `PublicProperty`, `HiddenProperty`
and `MyDate`. The attribute `HiddenProperty` should not be searchable, and `MyDate` should only search for dates
*after* the search entry (with a `GreaterThanFilter`). Similiar to the built-in `DataObject->getDefaultSearchContext()` method, we're building our own `getCustomSearchContext()` variant.
*after* the search entry (with a `GreaterThanFilter`). Similiar to the built-in `DataObject->getDefaultSearchContext()`
method, we're building our own `getCustomSearchContext()` variant.
:::php
class MyDataObject extends DataObject {
@ -86,11 +87,6 @@ and `MyDate`. The attribute `HiddenProperty` should not be searchable, and `MyDa
}
### Pagination
For paginating records on multiple pages, you need to get the generated `SQLQuery` before firing off the actual
@ -184,7 +180,7 @@ Results.PaginationSummary(4) defines how many pages the search will show in the
## Available SearchFilters
See SearchFilter API Documentation `[api:SearchFilter]`
See `[api:SearchFilter]` API Documentation
## API Documentation
`[api:SearchContext]`

View File

@ -6,23 +6,23 @@ the site reports by clicking "Site Reports" in the left hand side bar and select
![](_images/sitereport.png)
By default the CMS ships with a couple basic reports -
By default the CMS ships with a couple of basic reports -
## Default Reports
* "Empty Pages" which will generate a list of pages without content
* "Pages edited in the last 2 weeks" which will list all the pages edited in the last 2 weeks in order of most recently
edited.
* "To Do" which displays all the ToDo notes you have added to each page and a link to the page. This is in 2.2.2 and
* "To Do" which displays all the ToDo notes you have added to each page and a link to the page. Note: This is in 2.2.2 and
later
* Also the Ecommerce module provides 2 or 3 reports out of box. Such as All Products, Orders...
## Creating Custom Reports
You can create reports for you own data quickly and easily. A general knowledge of Silverstripe's
You can create reports for you own data quickly and easily. A general knowledge of SilverStripe's
[Datamodel](/topics/datamodel) would help before you attempt this.
Inside the Mysite/Code folder - your projects code, create a file called CustomSideReport or MyProjectSiteReport and
Inside the Mysite/Code folder - your projects code, create a file called `CustomSideReport` or `MyProjectSiteReport` and
inside this file we can add our site reports.
CustomSideReport.php
@ -91,6 +91,4 @@ file and add class's as you need them inside that for each report.
* More examples.
## API Documentation
`[api:ReportAdmin]`
`[api:ReportAdmin]`

View File

@ -2,12 +2,12 @@
## Introduction
The SiteConfig panel was introduced in 2.4 for providing a generic interface for managing site wide settings or
The `[api:SiteConfig]` panel was introduced in 2.4 for providing a generic interface for managing site wide settings or
functionality which is used throughout the site. Out of the box it provides 2 fields 'Site Name' and 'Site Tagline'.
## Accessing SiteConfig Options
## Accessing `[api:SiteConfig]` Options
You can access SiteConfig options from any SS template by using the function $SiteConfig.FieldName
You can access `[api:SiteConfig]` options from any SS template by using the function $SiteConfig.FieldName
:::ss
$SiteConfig.Title
@ -28,8 +28,7 @@ Or if you want to access variables in the PHP you can do
$config->Title
## Extending SiteConfig
## Extending `[api:SiteConfig]`
To extend the options available in the panel you can define your own fields via an Extension.
@ -59,13 +58,13 @@ Then add a link to your extension in the _config.php file like below.
Object::add_extension('SiteConfig', 'CustomSiteConfig');
This tells SilverStripe to add the CustomSiteConfig extension to the SiteConfig class.
This tells SilverStripe to add the CustomSiteConfig extension to the `[api:SiteConfig]` class.
After adding those two pieces of code, rebuild your database by visiting http://yoursite.com/dev/build and then reload
the admin interface. You may need to reload it with a ?flush=1 on the end.
You can define as many extensions for SiteConfig as you need. For example if you are developing a module you can define
You can define as many extensions for `[api:SiteConfig]` as you need. For example if you are developing a module you can define
your own global settings for the dashboard.
## API Documentation
`[api:SiteConfig]`
`[api:SiteConfig]`

View File

@ -5,7 +5,7 @@
An object representing a SQL query. It is easier to deal with object-wrappers than string-parsing a raw SQL-query. This
object is used by `[api:DataObject]`, though...
A word of caution: Dealing with low-level SQL is not encouraged in the Silverstripe [datamodel](/topics/datamodel) for various
A word of caution: Dealing with low-level SQL is not encouraged in the SilverStripe [datamodel](/topics/datamodel) for various
reasons. You'll break the behaviour of:
* Custom getters/setters
@ -15,7 +15,7 @@ reasons. You'll break the behaviour of:
* `[api:DataObject]`
* Database abstraction
We'll explain some ways to use *SELECT* with the full power of SQL, but still maintain a connection to the Silverstripe
We'll explain some ways to use *SELECT* with the full power of SQL, but still maintain a connection to the SilverStripe
[datamodel](/topics/datamodel).
## Usage
@ -109,7 +109,7 @@ Useful for creating dropdowns.
### "Raw" SQL with DB::query()
This is not recommended for most cases, but you can also use the Silverstripe database-layer to fire off a raw query:
This is not recommended for most cases, but you can also use the SilverStripe database-layer to fire off a raw query:
:::php
DB::query("UPDATE Player SET Status='Active'");
@ -142,10 +142,10 @@ This form of building a query has the following advantages:
* Selection of *ID*, *ClassName*, *RecordClassName*, which are necessary to use *buildDataObjectSet* later on
* Filtering records for correct *ClassName*
### Transforming a result to DataObjectSet
### Transforming a result to `[api:DataObjectSet]`
This is a commonly used technique inside Silverstripe: Use raw SQL, but transfer the resulting rows back into
DataObjects.
This is a commonly used technique inside SilverStripe: Use raw SQL, but transfer the resulting rows back into
`[api:DataObject]`s.
:::php
$sqlQuery = new SQLQuery();
@ -183,16 +183,16 @@ DataObjects.
var_dump($myFirstPlayer->Status); // undefined, as we didn't LEFT JOIN the BasePlayer-table
CAUTION: Depending on the selected columns in your query, you might get into one of the following scenarios:
**CAUTION:** Depending on the selected columns in your query, you might get into one of the following scenarios:
* Not all object-properties accessible: You need to take care of selecting the right stuff yourself
* Overlayed object-properties: If you *LEFT JOIN* a table which also has a column 'Birthdate' and do a global select on
this table, you might not be able to access original object-properties.
* You can't create DataObjects where no scalar record-data is available, e.g. when using *GROUP BY*
* You can't create `[api:DataObject]`s where no scalar record-data is available, e.g. when using *GROUP BY*
* Naming conflicts with custom getters: A getter like Player->getName() will overlay the column-data selected in the
above example
Be careful when saving back DataObjects created through *buildDataObjectSet*, you might get strange side-effects due to
Be careful when saving back `[api:DataObject]`s created through *buildDataObjectSet*, you might get strange side-effects due to
the issues noted above.
## Using FormFields with custom SQL

View File

@ -83,17 +83,17 @@ you can also add an exclusion
function allPagesToCache() {
$urls = array();
$pages = DataObject::get("SiteTree");
// ignored page types
$ignored = array('UserDefinedForm');
foreach($pages as $page) {
// check to make sure this page is not in the classname
if(!in_array($page->ClassName, $ignored)) {
$urls = array_merge($urls, (array)$page->subPagesToCache());
}
}
return $urls;
}
@ -127,7 +127,7 @@ example](http://open.silverstripe.com/browser/modules/cms/trunk/code/staticpubli
.htaccess update simpler.
Just look for this line:
RewriteRule .* sapphire/main.php?url=%1&%{QUERY_STRING} [L]

View File

@ -2,9 +2,8 @@
## Introduction
TableField behaves in the same manner as `[api:TableListField]`, however allows the editing of existing and adding of
new rows.
The data is saved back by the surrounding form-saving (mostly EditForm->save).
`[api:TableField]` behaves in the same manner as `[api:TableListField]`, however allows the editing of existing and adding of
new rows. The data is saved back by the surrounding form-saving (mostly EditForm->save).
See `[api:TableListField]` for more documentation on the base-class
@ -66,15 +65,15 @@ Note: You still have to attach some form of `[api:Validator]` to the form to tri
### Nested Table Fields
When you have TableField inside a `[api:ComplexTableField]`, the parent ID may not be known in your
getCMSFields() method. In these cases, you can set a value to '$RecordID' in your TableField extra data, and this will
be populated with the newly created record id upon save.
When you have `[api:TableField]` inside a `[api:ComplexTableField]`, the parent ID may not be known in your
getCMSFields() method. In these cases, you can set a value to '$RecordID' in your `[api:TableField]` extra data, and this
will be populated with the newly created record id upon save.
## Known Issues
* A TableField doesn't reload any submitted form-data if the saving is interrupted by a failed validation. After
refreshing the form with the validation-errors, the TableField will be blank again.
* You can't add **visible default data** to columns in a TableField, please use *setExtraData*
* A `[api:TableField]` doesn't reload any submitted form-data if the saving is interrupted by a failed validation. After
refreshing the form with the validation-errors, the `[api:TableField]` will be blank again.
* You can't add **visible default data** to columns in a `[api:TableField]`, please use *setExtraData*
## API Documentation

View File

@ -8,9 +8,9 @@ Provides customizeable columns, record-deletion by ajax, paging, sorting, CSV-ex
## Example
Here's an example of a full featured TableListField implementation. It features editing members in the database directly
as a button on each record, as well as filtering, and sorting. It also makes use of the 'export' permission, allowing
export of data as a CSV.
Here's an example of a full featured `[api:TableListField]` implementation. It features editing members in the database
directly as a button on each record, as well as filtering, and sorting. It also makes use of the 'export' permission,
allowing export of data as a CSV.
:::php
function getReportField() {
@ -90,7 +90,7 @@ For more information on each of the features used in the example, you can read b
$customCsvQuery->select[] = "CONCAT(col1,col2) AS MyCustomSQLColumn";
$myTableListField->setCustomCsvQuery($customQuery);
TableListField also tries to resolve Component-relations(has_one, has_many) and custom getters automatically:
`[api:TableListField]` also tries to resolve Component-relations(has_one, has_many) and custom getters automatically:
:::php
$myTableListField = new TableListField(
@ -139,12 +139,12 @@ Example (sorting by "FirstName" column):
);
If you want to sort by custom getters in your DataObject, please reformulate them to a custom SQL column. This
If you want to sort by custom getters in your `[api:DataObject]`, please reformulate them to a custom SQL column. This
restriction is needed to avoid performance-hits by caching and sorting potentially large datasets on PHP-level.
### Casting
Column-values can be casted, based on the casting-types available through DBObject (sapphire/core/model/fieldtypes).
Column-values can be casted, based on the casting-types available through DBObject (sapphire/core/model/fieldtypes).
:::php
$myTableListField->setFieldCasting(array(
@ -155,7 +155,7 @@ Column-values can be casted, based on the casting-types available through DBObje
### Permissions
Permissions vary in different TableListField-implementations, and are evaluated in the template.
Permissions vary in different `[api:TableListField]`-implementations, and are evaluated in the template.
By default, all listed permissions are enabled.
:::php
@ -237,7 +237,7 @@ implement averages etc.
)
);
In TableField-implementation, these summaries also react to changes in input-fields by javascript.
In `[api:TableListField]`-implementation, these summaries also react to changes in input-fields by javascript.
Available methods:
* sum
@ -245,7 +245,7 @@ Available methods:
### Grouping
Used to group by a specific column in the DataObject and create partial summaries.
Used to group by a specific column in the `[api:DataObject]` and create partial summaries.
Please use only together with addSummary().
(Automatically disables sorting).
@ -257,7 +257,7 @@ Please use only together with addSummary().
### Custom Sorting
Please subclass TableListField to implement custom sorting, following the naming-convention
Please subclass `[api:TableListField]` to implement custom sorting, following the naming-convention
"`colFunction_<yourFunctionName>`".
:::php
@ -274,7 +274,7 @@ Please subclass TableListField to implement custom sorting, following the naming
In case you want to perform utility-functions like "export" or "print" through action-buttons,
make sure to subclass Utility() which collates all possible actions.
### Customizing Look&Feel
### Customizing Look & Feel
You can exchange the used template, e.g. to change applied CSS-classes or the HTML-markup:
@ -285,4 +285,4 @@ You can exchange the used template, e.g. to change applied CSS-classes or the HT
## API Documentation
[api:TableListField]
`[api:TableListField]`

View File

@ -4,8 +4,7 @@
SilverStripe lets you customise the style of content in the CMS.
## Usage
This is done by setting up a CSS file called
(projectname)/css/typography.css
This is done by setting up a CSS file called (projectname)/css/typography.css.
You also need to create a file called (projectname)/css/editor.css with the following content:
@ -40,8 +39,8 @@ It's important to realise that this CSS file is included directly into the CMS s
can alter the styling of other parts of the interface. While this is novel, it can be dangerous and is probably not
what you're after.
The way around this is to limit all your styling selectors to elements inside something with class="typography". The
other half of this is to put class="typography" onto any area in your template where you would like the styling to be
The way around this is to limit all your styling selectors to elements inside something with `class="typography"`. The
other half of this is to put `class="typography"` onto any area in your template where you would like the styling to be
applied.
**WRONG**
@ -73,7 +72,7 @@ applied.
If you would to include different styles for different sections of your site, you can use class names the same as the
name of the data fields. This example sets up different paragraph styles for 2 HTML editor fieldsc alled Content and
name of the data fields. This example sets up different paragraph styles for 2 HTML editor fields called Content and
OtherContent:
:::css
@ -89,7 +88,7 @@ OtherContent:
### Removing the typography class
Sometimes, it's not enough to add a class, you also want to remove the typography class. You can use the
HTMLEditorField method setCSSClass.
`[api:HTMLEditorField]` method setCSSClass.
This example sets another CSS class typographybis:
@ -104,5 +103,4 @@ This example sets another CSS class typographybis:
}
This functionality will be available in the version 2.0.2 of the CMS.
**Note:** This functionality will be available in the version 2.0.2 of the CMS.

View File

@ -3,7 +3,7 @@
## Introduction
This page lists a number of "page options" , "rendering tools" or "special URL variables" that you can use to debug your
sapphire applications. These are consumed in PHP using the $_REQUEST or $_GET superglobals throughout the Sapphire
sapphire applications. These are consumed in PHP using the $_REQUEST or $_GET super globals throughout the Sapphire
core.
**General Usage**
@ -18,8 +18,8 @@ Append the option and corresponding value to your URL in your browser's address
| URL Variable | | Values | | Description |
| ------------ | | ------ | | ----------- |
| flush | | 1,all | | This will clear out all cached information about the page. This is used frequently during development - for example, when adding new PHP or SS files. See below for value descriptions. |
| showtemplate | | 1 | | Show the compiled version of all the templates used, including line numbers. Good when you have a syntax error in a template. Cannot be used on a Live site without **isDev** **flush** can be used with the following values: |
| ?flush=1 | | | | | Flushes the current page and included templates |
| showtemplate | | 1 | | Show the compiled version of all the templates used, including line numbers. Good when you have a syntax error in a template. Cannot be used on a Live site without **isDev**. **flush** can be used with the following values: |
| ?flush=1 | | | | Flushes the current page and included templates |
| ?flush=all | | | | Flushes the entire template cache |
## General Testing
@ -29,13 +29,13 @@ Append the option and corresponding value to your URL in your browser's address
| isDev | | 1 | | Put the site into [development mode](/topics/debugging), enabling debugging messages to the browser on a live server. For security, you'll be asked to log in with an administrator log-in |
| isTest | | 1 | | Put the site into [test mode](/topics/debugging), enabling debugging messages to the admin email and generic errors to the browser on a live server |
| debug | | 1 | | Show a collection of debugging information about the director / controller operation |
| debug_request | | 1 | | Show all steps of the request from initial HTTPRequest to Controller to Template Rendering |
| debug_request | | 1 | | Show all steps of the request from initial `[api:HTTPRequest]` to `[api:Controller]` to Template Rendering |
## Classes and Objects
| URL Variable | | Values | | Description |
| ------------ | | ------ | | ----------- |
| debugmanifest | | 1 | | Show the entire Sapphire manifest as currently built (Use /dev/build to rebuild) |
| debugmanifest | | 1 | | Show the entire Sapphire manifest as currently built (Use `/dev/build` to rebuild) |
| usetestmanifest | | 1 | | Force use of the default test manifest |
| debugmethods | | 1 | | Shows all methods available when an object is constructed (useful when extending classes or using object decorators) |
| debugfailover | | 1 | | Shows failover methods from classes extended |
@ -52,7 +52,7 @@ Append the option and corresponding value to your URL in your browser's address
| URL Variable | | Values | | Description |
| ------------ | | ------ | | ----------- |
| debug_memory | | 1 | | Output the number of bytes of memory used for this request |
| debug_profile | | 1 | | Enable the [profiler](/topics/debugging) for the duration of the request |
| debug_profile | | 1 | | Enable the [profiler](/topics/debugging) for the duration of the request |
| profile_trace | | 1 | | Includes full stack traces, must be used with **debug_profile** |
| debug_behaviour | | 1 | | Get profiling of [Behaviour.js](http://bennolan.com/behaviour) performance (Firebug recommended) |
| debug_javascript | | 1 | | Force debug-output on live-sites |
@ -79,9 +79,9 @@ Redirections](security#redirect_back_to_another_page_after_login) for more infor
| Site URL | | Action |
| -------- | | ------ |
| %%http://yoursite.com%%**/dev/build** | | Rebuild the entire database and manifest, see below for additional URL Variables |
| %%http://yoursite.com%%**/admin/publishall/** | | Publish all pages on the site |
| %%http://yoursite.com%%**/anypage/images/flush** | | Creates new images for the page by deleting the resized ones and going back to the original to create new resized one |
| http://yoursite.com**/dev/build** | | Rebuild the entire database and manifest, see below for additional URL Variables |
| http://yoursite.com**/admin/publishall/** | | Publish all pages on the site |
| http://yoursite.com**/anypage/images/flush** | | Creates new images for the page by deleting the resized ones and going back to the original to create new resized one |
### /dev/build

View File

@ -28,6 +28,4 @@ whenever a blog entry has been published.
mail("sam@silverstripe.com", "Blog published", "The blog has been published");
parent::onAfterPublish();
}
}
}

View File

@ -19,22 +19,26 @@ It is unclear how this works for data-objects that are not pages.
In the security tab you can make groups for security. The way this was intended was as follows (this may be a counter
intuitive):
- employees
1. marketing
- marketing executive
* employees
* marketing
* marketing executive
Thus, the further up the hierarchy you go the MORE privileges you can get. Similarly, you could have:
- members
1. coordinators
- admins
* members
* coordinators
* admins
Where members have some privileges, coordinators slightly more and administrators the most; having each group inheriting
privileges from its parent group.
## Permission checking is at class level
SilverStripe provides a security mechanism via the *Permission::check* method (see *LeftAndMain.php* for examples on how
SilverStripe provides a security mechanism via the *Permission::check* method (see `[api:LeftAndMain]` for examples on how
the admin screens work)
(next step -- go from *Permission::checkMember*...
(next step -- go from *Permission::checkMember*...)
### Nuts and bolts -- figuring it out
@ -44,14 +48,14 @@ works.
### Loading the admin page: looking at security
If you go to [your site]/admin -- how does that work?
*Director.php* maps the 'admin' URL request through a *Director* rule to the CMSMain controller (see `[api:CMSMain]`, with no arguments.
If you go to [your site]/admin *Director.php* maps the 'admin' URL request through a `[api:Director]` rule to the
`[api:CMSMain]` controller (see `[api:CMSMain]`, with no arguments).
*CMSMain.init()* calls its parent which, of all things is called *LeftAndMain*. It's in *LeftAndMain* that the
*CMSMain.init()* calls its parent which, of all things is called `[api:LeftAndMain]`. It's in `[api:LeftAndMain]` that the
important security checks are made by calling *Permission::check*.
`[api:Security::permissionFailure]` is the next utility function you can use to redirect to the login form.
### Customizing Access Checks in CMS Classes
see `[api:LeftAndMain]`
see `[api:LeftAndMain]`

View File

@ -1,9 +1,9 @@
# Common Configuration through _config.php
# Common configuration through _config.php
## Introduction
Silverstripe doesn't have a global configuration-array or an interface with all available configuration-options. As all
Silverstripe logic is contained in classes, the appropriate place to configure their behaviour is directly in the class
SilverStripe doesn't have a global configuration-array or an interface with all available configuration-options. As all
SilverStripe logic is contained in classes, the appropriate place to configure their behaviour is directly in the class
itself.
This lack of a configuration-GUI is on purpose, as we'd like to keep developer-level options where they belong (into
@ -12,7 +12,7 @@ CMS"](http://www.silverstripe.com/core-team-discussion/flat/2723) for further re
In addition to these principle, some settings are
* Author-level configuration like interface language or date/time formats can be performed in the CMS "My Profile" section (`admin/myprofile`).
* Group-related configuration like [api:HTMLEditorField] settings can be found in the "Security" section (`admin/security`).
* Group-related configuration like `[api:HTMLEditorField]` settings can be found in the "Security" section (`admin/security`).
* Site-wide settings like page titles can be set (and extended) on the root tree element in the CMS "Content" section (through the [siteconfig](/reference/siteconfig) API).
## _ss_environment.php
@ -24,8 +24,9 @@ See [environment-management](/topics/environment-management).
This file is detected in each folder by `[api:ManifestBuilder]`. This way, every toplevel-folder (=module)
can have independent configuration-rules.
//Please note that this is the only place where you can put in procedural code - all other functionality is wrapped in
classes (see [common-problems](/installation/common-problems)).//
Please note that this is the only place where you can put in procedural code - all other functionality is wrapped in
classes (see [common-problems](/installation/common-problems)).
You can call most static methods from _config.php - classes will be loaded as required. Here's a list - **this is
incomplete - please add to it** *Try to keep it in alphabetical order too! :)*

View File

@ -6,7 +6,7 @@ your SilverStripe site.
## Example
mysite/code/Controllers/FastFood.php
`mysite/code/Controllers/FastFood.php`
:::php
<?php
@ -20,14 +20,14 @@ mysite/code/Controllers/FastFood.php
?>
mysite/_config.php
`mysite/_config.php`
:::php
Director::addRules(50, array('fastfood/$Action/$ID/$Name' => 'FastFood_Controller'));
Request for '/fastfood/order/24/cheesefries' would result in the following to the $arguments above. If needed, use
"?flush=1" on the end of request after making any code changes to your controller.
Request for `/fastfood/order/24/cheesefries` would result in the following to the $arguments above. If needed, use
`?flush=1` on the end of request after making any code changes to your controller.
:::ss
Array
@ -42,12 +42,12 @@ Request for '/fastfood/order/24/cheesefries' would result in the following to th
In the above example the URLs were configured using the `[api:Director]` rules in the **_config.php** file.
Alternatively you can specify these in your Controller class via the **$url_handlers** static array (which gets
processed by the RequestHandler).
processed by the `[api:RequestHandler]`).
This is useful when you want to subvert the fixed action mapping of 'fastfood/order/*' to the function **order**. In
the case below we also want any orders coming through '/fastfood/drivethrough/' to use the same order function.
This is useful when you want to subvert the fixed action mapping of `fastfood/order/*` to the function **order**. In
the case below we also want any orders coming through `/fastfood/drivethrough/` to use the same order function.
mysite/code/Controllers/FastFood.php
`mysite/code/Controllers/FastFood.php`
:::php
class FastFood_Controller extends Controller {
@ -59,15 +59,15 @@ mysite/code/Controllers/FastFood.php
## URL Patterns
The RequestHandler class will parse all rules you specify against the following patterns.
The `[api:RequestHandler]` class will parse all rules you specify against the following patterns.
**A rule must always start with alphabetical ([A-Za-z]) characters or a $Variable declaration**
| Pattern | | Description |
| ----------- | | --------------- |
| `$` | | **Param Variable** - Starts the name of a paramater variable, it is optional to match this unless ! is used |
| `!` | | **Require Variable** - Placing this after a parameter variable requires data to be present for the rule to match |
| `//` | | **Shift Point** - Declares that only variables denoted with a $ are parsed into the $params AFTER this point in the regex |
| Pattern | Description |
| ----------- | --------------- |
| `$` | **Param Variable** - Starts the name of a paramater variable, it is optional to match this unless ! is used |
| `!` | **Require Variable** - Placing this after a parameter variable requires data to be present for the rule to match |
| `//` | **Shift Point** - Declares that only variables denoted with a $ are parsed into the $params AFTER this point in the regex |
## Examples

View File

@ -30,8 +30,9 @@ Or in your template (e.g. `themes/yourtheme/templates/Page.ss`):
:::ss
<% require css(mymodule/css/my.css) %>
Management through the `Requirements` class has the advantage that modules can include their own CSS files without modifying your template.
On the other hand, you as a template developer can "block" or change certain CSS files that are included from thirdparty code.
Management through the `Requirements` class has the advantage that modules can include their own CSS files without modifying
your template. On the other hand, you as a template developer can "block" or change certain CSS files that are included from
thirdparty code.
## WYSIWYG editor: typography.css and editor.css

View File

@ -22,9 +22,9 @@ for introducing their usage.
## HTMLText vs. Text, and HTMLVarchar vs. Varchar
The database field types HTMLVarchar and Varchar are exactly the same in the database. However, the templating engine
knows to escape the Varchar field and not the HTMLVarchar field. So, it's important you use the right field if you
don't want to be putting $FieldType.XML everywhere.
The database field types `[api:HTMLVarchar]` and `[api:Varchar]` are exactly the same in the database. However, the
templating engine knows to escape the `[api:Varchar]` field and not the `[api:HTMLVarchar]` field. So, it's important you
use the right field if you don't want to be putting $FieldType.XML everywhere.
If you're going to put HTML content into the field, please use the field type with the HTML prefix. Otherwise, you're
going to risk double-escaping your data, forgetting to escape your data, and generally creating a confusing situation.

View File

@ -20,9 +20,11 @@ See [database-structure](/reference/database-structure) for in-depth information
## Generating the database-schema
The SilverStripe database-schema is generated automatically by visiting the URL.
`http://`<mysite>`/dev/build`
`http://<mysite>/dev/build`
> Note: You need to be logged in as an administrator to perform this command.
<div class="notice" markdown='1'>
Note: You need to be logged in as an administrator to perform this command.
</div>
## Querying Data
@ -46,8 +48,8 @@ Passing a *$join* statement to DataObject::get will filter results further by th
table. **It will NOT return the additionally joined data.** The returned *$records* will always be a
`[api:DataObject]`.
When using *$join* statements be sure the string is in the proper format for the respective database engine. In MySQL
the use of backticks may be necessary when referring Table Names and potentially Columns. (see [MySQL
When using *$join* statements be sure the string is in the proper format for the respective database engine. In MySQL
the use of back-ticks may be necessary when referring Table Names and potentially Columns. (see [MySQL
Identifiers](http://dev.mysql.com/doc/refman/5.0/en/identifiers.html)):
:::php
@ -60,7 +62,6 @@ Identifiers](http://dev.mysql.com/doc/refman/5.0/en/identifiers.html)):
"0, 10");
## Properties
@ -121,11 +122,15 @@ Here we combined a Player's first name and surname, accessible through $myPlayer
}
}
**CAUTION: It is common practice to make sure that pairs of custom getters/setter deal with the same data, in a consistent
format.**
<div class="warning" markdown='1'>
**CAUTION:** It is common practice to make sure that pairs of custom getters/setter deal with the same data, in a consistent
format.
</div>
**CAUTION: Custom setters can be hard to debug: Please double check if you could transform your data in more
straight-forward logic embedded to your custom controller or form-saving.**
<div class="warning" markdown='1'>
**CAUTION:** Custom setters can be hard to debug: Please double check if you could transform your data in more
straight-forward logic embedded to your custom controller or form-saving.
</div>
### Default Values
@ -139,15 +144,17 @@ new object is created.
);
}
> Note: Alternatively you can set defaults directly in the database-schema (rather than the object-model). See
<div class="notice" markdown='1'>
Note: Alternatively you can set defaults directly in the database-schema (rather than the object-model). See
[data-types](data-types) for details.
</div>
### Casting
Properties defined in *static $db* are automatically casted to their [data-types](data-types) when used in templates.
You can also cast the return-values of your custom functions (e.g. your "virtual properties").
Calling those functions directly will still return whatever type your php-code generates,
but using the *obj()*-method or accessing through a template will cast the value accordig to the $casting-definition.
but using the *obj()*-method or accessing through a template will cast the value according to the $casting-definition.
:::php
class Player extends DataObject {
@ -164,15 +171,9 @@ but using the *obj()*-method or accessing through a template will cast the value
}
## Relations
Relations are built through static array definitions on a class, in the format:\\
`<relationship-name>` => `<classname>`{php}
Relations are built through static array definitions on a class, in the format `<relationship-name> => <classname>`
### has_one
@ -202,8 +203,10 @@ parent element in the tree:
Defines 1-to-many joins. A database-column named ""`<relationship-name>`ID"" will to be created in the child-class.
**CAUTION: Please specify a $has_one-relationship on the related child-class as well, in order to have the necessary
accessors available on both ends.**
<div class="warning" markdown='1'>
**CAUTION:** Please specify a $has_one-relationship on the related child-class as well, in order to have the necessary
accessors available on both ends.
</div>
:::php
// access with $myTeam->Players() or $player->Team()
@ -219,7 +222,7 @@ accessors available on both ends.**
}
To specify multiple has_manys to the same object you can use dot notation to distinguish them like below
To specify multiple $has_manys to the same object you can use dot notation to distinguish them like below
:::php
class Person {
@ -241,7 +244,6 @@ Multiple $has_one relationships are okay if they aren't linking to the same obje
:::php
/**
* THIS IS BAD
*/
class Team extends DataObject {
@ -261,8 +263,10 @@ Multiple $has_one relationships are okay if they aren't linking to the same obje
Defines many-to-many joins. A new table, (this-class)_(relationship-name), will be created with a pair of ID fields.
**CAUTION: Please specify a $belongs_many_many-relationship on the related class as well, in order to have the necessary
accessors available on both ends.**
<div class="warning" markdown='1'>
**CAUTION:** Please specify a $belongs_many_many-relationship on the related class as well, in order to have the necessary
accessors available on both ends.
</div>
:::php
// access with $myTeam->Categories() or $myCategory->Teams()
@ -372,10 +376,6 @@ casting data before saving.
);
### onBeforeWrite
You can customize saving-behaviour for each DataObject, e.g. for adding security. These functions are private, obviously
@ -411,8 +411,10 @@ Example: Disallow creation of new players if the currently logged-in player is n
}
> Note: There are no separate methods for *onBeforeCreate* and *onBeforeUpdate*. Please check for the existence of
<div class="notice" markdown='1'>
Note: There are no separate methods for *onBeforeCreate* and *onBeforeUpdate*. Please check for the existence of
$this->ID to toggle these two modes, as shown in the example above.
</div>
### onBeforeDelete
@ -453,17 +455,13 @@ See `[api:SQLQuery]` for custom *INSERT*, *UPDATE*, *DELETE* queries.
## Decorating DataObjects
You can add properties and methods to existing DataObjects like `[api:Member]` (a core class) without hacking core
You can add properties and methods to existing `[api:DataObjects]`s like `[api:Member]` (a core class) without hacking core
code or subclassing.
Please see `[api:DataObjectDecorator]` for a general description, and `[api:Hierarchy]` for our most
popular examples.
## FAQ
### Whats the difference between DataObject::get() and a relation-getter?
@ -471,7 +469,7 @@ You can work with both in pretty much the same way, but relationship-getters ret
A `[api:ComponentSet]` with relation-specific functionality.
:::php
$myTeam = DataObject::get_by_id('Team',$myPlayer->TeamID); // returns DataObjectSet
$myTeam = DataObject::get_by_id('Team',$myPlayer->TeamID); // returns DataObject
$myTeam->add(new Player()); // fails
$myTeam = $myPlayer->Team(); // returns Componentset

View File

@ -32,17 +32,17 @@ use devmode on a public server very very carefully
Test mode is designed for staging environments or other private collaboration sites before deploying a site live. You do
not need to use test mode if you do not have a staging environment or a place for testing which is on a public server)
In this mode error messages are hidden from the user and it includes BasicAuth integration if you want to password
In this mode error messages are hidden from the user and it includes `[api:BasicAuth]` integration if you want to password
protect the site.
To set your site to test mode set this in your mysite/_config.php file
To set your site to test mode set this in your `mysite/_config.php` file
:::php
Director::set_environment_type("test");
A common situation is to enable password protected site viewing on your test site only. You can enable that but adding
this to your mysite/_config file
this to your `mysite/_config` file
:::php
if(Director::isTest()) BasicAuth::protect_entire_site();
@ -54,7 +54,7 @@ Live sites should always run in live mode. Error messages are suppressed from th
to email the developers. This enables near real time reporting of any fatal errors or warnings on the site and can help
find any bugs users run into.
To set your site to live mode set this in your mysite/_config.php file
To set your site to live mode set this in your `mysite/_config.php` file
:::php
Director::set_environment_type("live");

View File

@ -2,7 +2,7 @@
## Introduction
The directory-structure in Silverstripe it built on "convention over configuration", so the placement of some files and
The directory-structure in SilverStripe it built on "convention over configuration", so the placement of some files and
directories is meaningful to its logic.
## Core Structure
@ -16,7 +16,7 @@ Directory | Description
## Custom Code Structure
We're using `<mysite>` as an example - arbitrary directory-names are allowed, as long as they don't collide with
existing modules or the directories listes in "Core Structure".
existing modules or the directories lists in "Core Structure".
| Directory | Description |
| --------- | ----------- |
@ -30,7 +30,7 @@ existing modules or the directories listes in "Core Structure".
## Themes Structure
| `themes/blackcandy/` | Standard "blackcandy" theme |
| ------------------ | --------------------------- |
| ------------------ | --------------------------- |
| `themes/blackcandy_blog/` | Theme additions for the blog module |
| `themes/yourtheme/` | The themes folder can contain more than one theme - here's your own |

View File

@ -15,7 +15,7 @@ an external SMTP server (see [PHP documentation for mail()](http://php.net/mail)
By default, emails are sent in both HTML and Plaintext format.
A plaintext representation is automatically generated from the system
by stripping HTML markup, or transformining it where possible
by stripping HTML markup, or transforming it where possible
(e.g. `<strong>text</strong>` is converted to `*text*`).
:::php
@ -35,7 +35,7 @@ The default HTML template is located in `sapphire/templates/email/GenericEmail.s
**Requirements: SilverStripe 2.3+**
* Create a SS-template file called, in this example we will use 'MyEmail.ss' inside mysite/templates/email.
* Create a SS-template file called, in this example we will use 'MyEmail.ss' inside `mysite/templates/email`.
* Fill this out with the body text for your email. You can use any [SS-template syntax](/topics/templates) (e.g. `<% control %>`,
`<% if %>`, $FirstName etc)
* Choose your template with **setTemplate()**
@ -86,14 +86,14 @@ Usage:
### Administrator Emails
The static function `Email::setAdminEmail()` can be called from a _config.php file to set the address that these
The static function `Email::setAdminEmail()` can be called from a `_config.php` file to set the address that these
emails should originate from. This address is used if the `from` field is empty.
### Redirecting Emails
* Email::send_all_emails_to($address) will redirect all emails sent to the given address. Handy for testing!
* Email::cc_all_emails_to() and Email::bcc_all_emails_to() will keep the email going to its original recipients, but
add an additional receipient in the BCC/CC header. Good for monitoring system-generated correspondence on the live
* `Email::send_all_emails_to($address)` will redirect all emails sent to the given address. Handy for testing!
* `Email::cc_all_emails_to()` and `Email::bcc_all_emails_to()` will keep the email going to its original recipients, but
add an additional recipient in the BCC/CC header. Good for monitoring system-generated correspondence on the live
systems.
:::php
@ -112,7 +112,7 @@ $value)**
..
See http://en.wikipedia.org/wiki/E-mail#Message_header for a list of header names.
See [Wikipedia E-mail Message header](http://en.wikipedia.org/wiki/E-mail#Message_header) for a list of header names.
### Newsletters
@ -120,4 +120,4 @@ The [newsletter module](http://silverstripe.org/newsletter-module) provides a UI
## API Documentation
`[api:Email]`
`[api:Email]`

View File

@ -8,17 +8,17 @@ them. Why should we have to go through the installation process and re-enter th
when we deploy them to our servers. Additionally, our production host's database connection details will likely be
different than our local server.
SilverStripe comes with a solution to this: the "_ss_environment.php" file. You can put a single _ss_environment.php
SilverStripe comes with a solution to this: the `_ss_environment.php` file. You can put a single `_ss_environment.php`
file in your "projects" folder on your development box, and it will be used by each of your development sites.
## Setting up your development machine with _ss_environment.php
In this example, we assume that you are managing multiple projects as subfolders of "~/Sites/", and that you can visit
these at "http://localhost/". For example, you might have a project at "~/Sites/myproject/", and visit it at
"http://localhost/myproject/".
In this example, we assume that you are managing multiple projects as subfolders of `~/Sites/`, and that you can visit
these at `http://localhost/`. For example, you might have a project at `~/Sites/myproject/`, and visit it at
`http://localhost/myproject/`.
Create a new file, ~/Sites/_ss_environment.php. Put the following content in it, editing the values of the
"SS_DATABASE_..."" and "SS_DEFAULT_ADMIN_..." defines as appropriate.
Create a new file, `~/Sites/_ss_environment.php`. Put the following content in it, editing the values of the
"SS_DATABASE_..." and "SS_DEFAULT_ADMIN_..." defines as appropriate.
:::php
<?php
@ -53,21 +53,21 @@ of `$databaseConfig` and `Director::set_dev_servers`, and instead make sure that
## How it works
The mechanism by which the "_ss_environment.php" files work is quite simple. Here's how it works:
The mechanism by which the `_ss_environment.php` files work is quite simple. Here's how it works:
* At the beginning of SilverStripe's execution, the _ss_environment.php file is searched for, and if it is found, it's
* At the beginning of SilverStripe's execution, the `_ss_environment.php` file is searched for, and if it is found, it's
included. SilverStripe looks in 3 places for the file:
* The site's base folder (ie, a sibling of sapphire, jsparty, and cms)
* The parent of the base folder
* The grandparent of the base folder
* The "_ss_environment.php" file sets a number of "define()".
* "conf/ConfigureFromEnv.php" is included from within your "mysite/_config.php". This file has a number of regular
* The `_ss_environment.php` file sets a number of "define()".
* "conf/ConfigureFromEnv.php" is included from within your `mysite/_config.php`. This file has a number of regular
configuration commands that use those defines as their arguments. If you are curious, open up
"sapphire/conf/ConfigureFromEnv.php" and see for yourself!
`sapphire/conf/ConfigureFromEnv.php` and see for yourself!
### An Example
This is my '_ss_environment.php' file. I have it placed in '/var', as each of the sites are in a subfolder of '/var'.
This is my `_ss_environment.php` file. I have it placed in `/var`, as each of the sites are in a subfolder of `/var`.
:::php
<?php
@ -98,7 +98,7 @@ This is my '_ss_environment.php' file. I have it placed in '/var', as each of th
// This causes errors to be written to the silverstripe.log file in the same directory as this file, so /var.
// Before PHP 5.3.0, you'll need to use dirname(__FILE__) instead of __DIR__
define('SS_ERROR_LOG', __DIR__ . '/silverstripe.log');
// This is used by sake to know which directory points to which URL
global $_FILE_TO_URL_MAPPING;
$_FILE_TO_URL_MAPPING['/var/www'] = 'http://simon.geek.nz';
$_FILE_TO_URL_MAPPING['/var/www'] = 'http://simon.geek.nz';

View File

@ -40,7 +40,7 @@ friendlier - much like the 404 page, the error content can be edited within the
* Set the error code to 500
* Publish the page.
**HOW IT WORKS: **The publication script for ErrorPage will write the full HTML content, including the template styling,
**HOW IT WORKS: **The publication script for `[api:ErrorPage]` will write the full HTML content, including the template styling,
to assets/error-500.html. The fatal error handler looks for the presence of this file, and if it exists, dumps the
content. This means that database access isn't required to provide a 500 error page.
@ -55,7 +55,7 @@ You can indicate a log file relative to the site root. The named file will have
(an encoded file containing backtraces and things) will go to a file of a similar name, but with the suffix ".full"
added.
<mysite>/_config.php:
`<mysite>/_config.php`:
:::php
// log errors and warnings
@ -66,7 +66,7 @@ added.
#### Deprecated method (SS 2.3 ?)
<mysite>/_config.php:
`<mysite>/_config.php`:
:::php
Debug::log_errors_to("/my/logfile/path");
@ -77,7 +77,7 @@ added.
In addition to SilverStripe-integrated logging, it is adviseable to fall back to PHPs native logging functionality. A
script might terminate before it reaches the SilverStripe errorhandling, for example in the case of a fatal error.
<mysite>/_config.php:
`<mysite>/_config.php`:
:::php
ini_set("log_errors", "On");
@ -88,7 +88,8 @@ script might terminate before it reaches the SilverStripe errorhandling, for exa
## Email Logs
You can send both fatal errors and warnings in your code to a specified email-address.
<mysite>/_config.php:
`<mysite>/_config.php`:
:::php
// log errors and warnings

View File

@ -5,14 +5,13 @@ CMSMain is part of the CMS. It is the controller for the content editor.
## Creating another hierarchical editor by subclassing CMSMain
Sometimes you'll want to provide an administration interface that is pretty much exactly what CMSMain provides, but it's
not appropriate to include your data in with the site content. For example, Hayden developed a hierarchical category
administrator on the Guano application.
not appropriate to include your data in with the site content.
Here's how you can do this:
Here's how you can do this:
## Using classes other than SiteTree in the site tree
It is possible to use to different classes in two separate site trees. In Guano for example, there is the usual site
It is possible to use to different classes in two separate site trees. For example, there is the usual site
content tree and a category tree. To change that find:
:::php
@ -50,12 +49,12 @@ where url is the relative link to the page (eg 'admin/categories'). You can chan
## Overloading EditForm
You may need to overload EditForm if your class does not use the Versioned extension.
You may need to overload EditForm if your class does not use the `[api:Versioned]` extension.
## Overloading SiteTreeAsUL
The tree hints can sometimes cause problems when reorganising the tree, and the CMSMain::SiteTreeAsUL function uses
SiteTree explicitly. Use:
`[api:SiteTree]` explicitly. Use:
:::php
public function SiteTreeAsUL() {
@ -64,4 +63,3 @@ SiteTree explicitly. Use:
return $this->getSiteTreeFor( $this->stat('tree_class') );
}

View File

@ -6,8 +6,8 @@ Form validation is a combination of PHP and JavaScript
### Introduction
Validators are implemented as an argument to the [api:Form] constructor. You create a required fields validator like
so. In this case, we're creating a [api:RequiredFields] validator - the [api:Validator] class itself is an abstract
Validators are implemented as an argument to the `[api:Form]` constructor. You create a required fields validator like
so. In this case, we're creating a `[api:RequiredFields]` validator - the `[api:Validator]` class itself is an abstract
class.

View File

@ -33,7 +33,7 @@ Example:
## Subclassing a form
It's the reponsibility of your subclass' constructor to call
It's the responsibility of your subclass' constructor to call
:::php
parent::__construct()
@ -56,6 +56,8 @@ $name must be passed - their values depend on where the form is instantiated.
The real difference, however, is that you can then define your controller methods within the form class itself.
## Form Field Types
There are many classes extending `[api:FormField]`. Some examples:
@ -71,6 +73,7 @@ There are many classes extending `[api:FormField]`. Some examples:
Full overview at [form-field-types](/reference/form-field-types)
### Using Form Fields
To get these fields automatically rendered into a form element, all you need to do is create a new instance of the
@ -192,8 +195,8 @@ First of all, you need to create your form on it's own class, that way you can d
}
`forTemplate()` tells the Form class to render with a template of return value of `$this->class`, which in this case
is *MyForm*, the name of the class. If the template doesn't exist, then it falls back to using Form.ss
`forTemplate()` tells the `[api:Form]` class to render with a template of return value of `$this->class`, which in this case
is *MyForm*, the name of the class. If the template doesn't exist, then it falls back to using Form.ss.
*MyForm.ss* should then be placed into your *templates/Includes* directory for your project. Here is an example of
basic customisation:
@ -232,7 +235,7 @@ this case `TextField->Field()` or `EmailField->Field()` which returns an `<input
for the type of field. Pass in the name of the field as the first parameter, as done above, to render it into the
template.
To find more methods, have a look at the Form class, as there is a lot of different methods of customising the form
To find more methods, have a look at the `[api:Form]` class, as there is a lot of different methods of customising the form
templates, for example, you could use `<% control Fields %>` instead of specifying each field manually, as we've done
above.

View File

@ -2,7 +2,7 @@
## Introduction
The i18n class (short for "internationalization") in Silverstripe enables you to display templates and PHP code in
The i18n class (short for "internationalization") in SilverStripe enables you to display templates and PHP code in
different languages based on your global settings and the preferences of your website users. This process is also known
as l10n (short for "localization").
@ -28,8 +28,8 @@ The i18n class is enabled by default.
### Setting the locale
To set the locale you just need to call `[api:i18n::set_locale()]` passing, as a parameter, the name of the locale that you want to
set.
To set the locale you just need to call `[api:i18n::set_locale()]` passing, as a parameter, the name of the locale that you
want to set.
:::php
//Example 1: setting the locale
@ -53,7 +53,7 @@ To let browsers know which language they're displaying a document in, you can de
:::html
//'Page.ss' (HTML)
<html lang="$ContentLocale">
//'Page.ss' (XHTML)
<html lang="$ContentLocale" xml:lang="$ContentLocale" xmlns="http://www.w3.org/1999/xhtml">
@ -197,9 +197,10 @@ Sprintf enables us to dynamically replace parts of a translated string, e.g. by
$title
)
<div class="warning" markdown='1'>
**Caution**: In templates (*.ss)-files you can only use ONE argument for your sprintf-support, and can't use spaces
between parameters.
</div>
:::php
// in SS-template ($title must be available in the current template-scope)
@ -219,7 +220,9 @@ If you want to run the text collector for just one module you can use the 'modul
`http://<mysite>/dev/tasks/i18nTextCollectorTask/?module=cms`
<div class="notice" markdown='1'>
**Note**: You'll need to install PHPUnit to run the text collector (see [testing-guide](/topics/testing)).
</div>
## Language tables in PHP
@ -317,8 +320,9 @@ Example Translation Table (mymodule/javascript/lang/de_DE.js)
* No detecting/conversion of character encodings (we rely fully on UTF-8)
* Translation of graphics/assets
* Usage of gettext (too clumsy, too many requirements)
* Displaying multipe languages/encodings on the same page
* Displaying multiple languages/encodings on the same page
## Links
* [http://www.i18nguy.com/](http://www.i18nguy.com/)
* [balbus.tk i18n notes](http://www.balbus.tk/internationalize)

View File

@ -10,7 +10,7 @@ It is where most documentation should live, and is the natural "second step" aft
* [Data Types](data-types): Types that properties on `DataObject` can have (e.g. `Text` or `Date`)
* [Datamodel](datamodel): How we use an "Object-relational model" to expose database information in a useful way
* [Debugging](debugging): Tracking down errors via logs, URL parameters and profiling
* [Directory Structure](directory-structure): Whats core files, where do modules and my own project files go?
* [Directory Structure](directory-structure): What are core files, where do modules and my own project files go?
* [Emails](email): Configuring and sending emails
* [Environment management](environment-management): Sharing configuration details (e.g. database login, passwords) with multiple websites via a `_ss_environment.php` file
* [Error Handling](error-handling): Error messages and filesystem logs
@ -20,7 +20,7 @@ It is where most documentation should live, and is the natural "second step" aft
* [Forms](forms): Create your own form, add fields and create your own form template using the existing `Form` class
* [Internationalization (i18n)](i18n): Displaying templates and PHP code in different languages using i18n
* [Javascript](javascript): Best practices for developing with JavaScript in SilverStripe
* [Module Development](module-development): Creating a module (also known as "extension" or "plugin") to contain reuseable functionality
* [Module Development](module-development): Creating a module (also known as "extension" or "plugin") to contain reusable functionality
* [Modules](modules): Introduction, how to download and install a module (e.g. with blog or forum functionality)
* [Page Types](page-types): What is a "page type" and how do you create one?
* [Search](search): Searching for properties in the database as well as other documents
@ -29,7 +29,7 @@ It is where most documentation should live, and is the natural "second step" aft
* [Testing](testing): Functional and Unit Testing with PHPUnit and SilverStripe's testing framework
* [Developing Themes](theme-development): Package templates, images and CSS to a reusable theme
* [Translation](translation): Creating content in multiple languages
* [Widgets](widgets): Small feature blocks which can be placed on a page by the CMS editor
* [Widgets](widgets): Small feature blocks which can be placed on a page by the CMS editor, also outlines how to create and add widgets
## Feedback

View File

@ -9,9 +9,9 @@ practices can be applied to other libraries as well.
## File Inclusion
SilverStripe-driven code should use the `Requirements` class to manage clientside dependencies like CSS and JavaScript
SilverStripe-driven code should use the `[api:Requirements]` class to manage clientside dependencies like CSS and JavaScript
files, rather than including `<script>` and `<link>` tags in your templates. This has the advantage that a registry
of requirements can be built up from different places outside of the main controller, for example included `FormField`
of requirements can be built up from different places outside of the main controller, for example included `[api:FormField]`
instances.
See [requirements](/reference/requirements) documentation.
@ -27,10 +27,12 @@ SilverStripe CMS uses [jQuery UI](http://ui.jquery.com) on top of jQuery.
For any custom code developed with jQuery, you have four choices to structure it: Custom jQuery Code, a jQuery Plugin, a
jQuery UI Widget, or a `jQuery.entwine` behaviour. We'll detail below where each solution is appropriate.
<div class="hint" markdown='1'>
**Important**: Historically we have been using [PrototypeJS](http://prototypejs.com), which is now discouraged. SilverStripe as a framework doesn't impose a choice of library. It
tries to generate meaningful markup which you can alter with other JavaScript libraries as well. Only the CMS itself and
certain form widgets require jQuery to function correctly. You can also use jQuery in parallel with other libraries, see
[here](http://docs.jquery.com/Using_jQuery_with_Other_Libraries).
</div>
### Custom jQuery Code
@ -229,7 +231,7 @@ jQuery with a few lines of code. Your jQuery code will normally end up as a ser
### Don't claim global properties
Global properties are evil. They are accesible by other scripts, might be overwritten or mis-used. 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
// you can't rely on '$' being defined outside of the closure
@ -506,7 +508,7 @@ To generate documentation for SilverStripe code, use [JSDoc toolkit](http://code
JavaScript, take a look at the [jsdoc cookbook](http://code.google.com/p/jsdoc-toolkit/wiki/CookBook). The `@lends`
and `@borrows` properties are particularly useful for documenting jQuery-style code.
JSDoc-toolkit is a commandline utility, see [usage](http://code.google.com/p/jsdoc-toolkit/wiki/CommandlineOptions).
JSDoc-toolkit is a command line utility, see [usage](http://code.google.com/p/jsdoc-toolkit/wiki/CommandlineOptions).
Example: jQuery.entwine
@ -619,11 +621,11 @@ Here's an example of hooking the 'PageLoaded' and 'BeforeSave' methods:
this.observeMethod('BeforeSave', this.beforeSave);
this.pageLoaded(); // call pageload initially too.
},
pageLoaded : function() {
alert("You loaded a page");
},
beforeSave: function() {
alert("You clicked save");
}

View File

@ -36,7 +36,7 @@ init() function on your module controller classes:
}
This will use your_project/css/forum.css if it exists, otherwise it falls back to using forum/css/forum.css.
This will use `<projectname>/css/forum.css` if it exists, otherwise it falls back to using `forum/css/forum.css`.
## Publication
@ -46,10 +46,13 @@ adherence to conventions, writing documentation, and releasing updates. See [con
## Reference
**How To:**
* [Add a link to your module in the main SilverStripe Admin Menu](/reference/leftandmain)
**
Useful Links:**
* [Add a link to your module in the main SilverStripe Admin Menu](/reference/leftandmain)
**Useful Links:**
* [Modules](modules)
* [Module Release Process](module-release-process)
* [Debugging methods](/topics/debugging)
* [URL Variable Tools](/reference/urlvariabletools) - Lists a number of “page options” , “rendering tools” or “special
URL variables” that you can use to debug your sapphire applications

View File

@ -86,3 +86,8 @@ Exit the editor and then run
svn up
**Useful Links:**
* [Modules](module-developement)
* [Module Release Process](module-release-process)

View File

@ -17,9 +17,9 @@ and use this template to lay out the basic design elements that dont change.
It contains standard HTML markup, with some differences. Well go over these later, but for now, you can see that this
file only generates some of the content it sets up the `<html>` tags, deals with the `<head>` section, creates the
first-level navigation, and then closes it all off again. See $Layout? Thats what is doing most of the work when you
visit a page. Now take a look at mysite/templates/Layout/Page.ss. This as you can see has a lot more markup in it
visit a page. Now take a look at `mysite/templates/Layout/Page.ss`. This as you can see has a lot more markup in it
its what is included into $Layout when the Page page type is rendered. Similarly,
mysite/templates/Layout/HomePage.ss would be rendered into $Layout when the HomePage page type is selected for the
`mysite/templates/Layout/HomePage.ss` would be rendered into $Layout when the HomePage page type is selected for the
current page youre viewing.
Why do we sub-class Page for everything? The easiest way to explain this is to use the example of a search form. If we
@ -39,7 +39,7 @@ we want to do to the CMS for this page type in here.
Page types are created using PHP classes. If youre not sure about how these work, [click here for a gentler
introduction to PHP classes](http://www-128.ibm.com/developerworks/opensource/library/os-phpobj/).
We put the Page class into a file called Page.php inside mysite/code. We also put Page_Controller in here. Any other
We put the Page class into a file called Page.php inside `mysite/code`. We also put Page_Controller in here. Any other
classes that are based on Page for example, the class Page_AnythingElse will also go into Page.php. Likewise, the
StaffPage_Image class will go into StaffPage.php.
@ -78,8 +78,8 @@ See [form](/topics/forms) and [tutorial:2-extending-a-basic-site](/tutorials/2-e
### removeFieldFromTab()
Overloading `getCMSFields()` you can call `removeFieldFromTab()` on a `FieldSet` object. For example, if you don't
want the MenuTitle field to show on your page, which is inherited from SiteTree.
Overloading `getCMSFields()` you can call `removeFieldFromTab()` on a `[api:FieldSet]` object. For example, if you don't
want the MenuTitle field to show on your page, which is inherited from `[api:SiteTree]`.
:::php
class StaffPage extends Page {
@ -157,4 +157,5 @@ and [tutorial:3-forms](/tutorials/3-forms).
$stageRecord = Versioned::get_one_by_stage('SiteTree', 'Stage', "SiteTree.ID = $pageID");
if ($stageRecord) $stageRecord->delete();
$liveRecord = Versioned::get_one_by_stage('SiteTree', 'Live', "SiteTree_Live.ID = $pageID");
if ($liveRecord) $liveRecord->delete();
if ($liveRecord) $liveRecord->delete();

View File

@ -5,10 +5,12 @@
Fulltext search for page content (and other attributes like "Title" or "MetaTags") can be easily added to SilverStripe.
See [Tutorial: Site Search](/tutorials/4-site-search) for details.
## Searching for DataObjects
## Searching for DataObject's
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 [api:ModelAdmin] class.
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 `[api:ModelAdmin]` class.
[SearchContext](/reference/searchcontext) goes into more detail about setting up a default search form for `[api:DataObject]`s.
## Searching for Documents
@ -21,6 +23,7 @@ dedicated search service like the [sphinx module](http://silverstripe.org/sphinx
* `[api:ModelAdmin]`
* `[api:RestfulServer]`
* [Tutorial: Site Search](/tutorials/4-site-search)
* [SearchContext](/reference/searchcontext)
* [genericviews module](http://silverstripe.org/generic-views-module)
* [sphinx module](http://silverstripe.org/sphinx-module)
* [lucene module](http://silverstripe.org/lucene-module)

View File

@ -2,22 +2,21 @@
## Introduction
This page details notes on how to ensure that we develop secure SilverStripe applications. See [security](/topics/security) for
the Silverstripe-class as a starting-point for most security-related functionality.
This page details notes on how to ensure that we develop secure SilverStripe applications. See [security](/topics/security)
for the Silverstripe-class as a starting-point for most security-related functionality.
See our [contributing guidelines](/misc/contributing#reporting-security-issues) on how
to report security issues.
See our [contributing guidelines](/misc/contributing#reporting-security-issues) on how to report security issues.
## SQL Injection
The [coding-conventions](/misc/coding-conventions) help guard against SQL injection attacks but still require developer
dilligence: ensure that any variable you insert into a filter / sort / join clause has been escaped.
diligence: ensure that any variable you insert into a filter / sort / join clause has been escaped.
See [http://shiflett.org/articles/sql-injection](http://shiflett.org/articles/sql-injection).
### Automatic escaping
Silverstripe automatically runs [addslashes()](http://php.net/addslashes) in DataObject::write() wherever possible. Data
SilverStripe automatically runs [addslashes()](http://php.net/addslashes) in DataObject::write() wherever possible. Data
is escaped when saving back to the database, not when writing to object-properties.
* DataObject::get_by_id()
@ -29,8 +28,10 @@ is escaped when saving back to the database, not when writing to object-properti
* FormField->saveInto()
* DBField->saveInto()
Note: It is NOT good practice to "be sure" and convert the data passed to the functions below manually. This might
<div class="warning" markdown='1'>
It is NOT good practice to "be sure" and convert the data passed to the functions below manually. This might
result in *double escaping* and alters the actually saved data (e.g. by adding slashes to your content).
</div>
### Manual escaping
@ -106,8 +107,10 @@ XSS (Cross-Site-Scripting). With some basic guidelines, you can ensure your outp
displaying a blog post in HTML from a trusted author, or escaping a search parameter from an untrusted visitor before
redisplaying it).
<div class="notice" markdown='1'>
Note: SilverStripe templates do not remove tags, please use [strip_tags()](http://php.net/strip_tags) for this purpose
or [sanitize](http://htmlpurifier.org/) it correctly.
</div>
See [http://shiflett.org/articles/foiling-cross-site-attacks](http://shiflett.org/articles/foiling-cross-site-attacks)
for in-depth information about "Cross-Site-Scripting".
@ -253,7 +256,7 @@ Template:
Some rules of thumb:
* Don't concatenate URLs in a template. It only works in extremely simple cases that usually contain bugs.
* Use *Controller::join_links()* to concatenate URLs. It deals with querystrings and other such edge cases.
* Use *Controller::join_links()* to concatenate URLs. It deals with query strings and other such edge cases.
## Cross-Site Request Forgery (CSRF)
@ -292,7 +295,7 @@ Below is an example with different ways you would use this casting technique:
function CaseStudies() {
// cast an ID from URL parameters e.g. (mysite.com/home/action/ID)
$anotherID = (int)Director::urlParams['ID'];
$anotherID = (int)Director::urlParam['ID'];
// perform a calculation, the prerequisite being $anotherID must be an integer
$calc = $anotherID + (5 - 2) / 2;
@ -331,7 +334,6 @@ disallow certain filetypes.
Example configuration for Apache2:
<VirtualHost *:80>
...
<LocationMatch assets/>
@ -346,7 +348,6 @@ file in the assets directory. This requires PHP to be loaded as an Apache modul
**/assets/.htaccess**
php_flag engine off
Options -ExecCGI -Includes -Indexes

View File

@ -93,7 +93,7 @@ by using the `$Layout` variable so it makes sense to add the .typography style a
$Layout
</div>
## Designing reuseable templates
## Designing reusable templates
Although SilverStripe is ultimately flexible in how you create your templates, there's a couple of best practices. These
will help you to design templates for modules, and make it easier for other site developers to integrate them into their
@ -101,7 +101,7 @@ own base templates.
* Most of your templates should be Layout templates
* Build your templates as a [Theme](/topics/themes) so you can easily re-use and exchange them
* Your layout template should include a standard markup structure (`<div id="Layout">`$Layout`</div>`)
* Your layout template should include a standard markup structure (`<div id="Layout">$Layout</div>`)
* Layout templates only include content that could be completely replaced by another module (e.g. a forum thread). It
might be infeasible to do this 100%, but remember that every piece of navigation that needs to appear inside `$Layout`
will mean that you have to customise templates when integrating the module.

View File

@ -2,7 +2,7 @@
Functional tests test your controllers. The core of these are the same as unit tests:
* Create a subclass of SapphireTest in the mysite/tests or (module)/tests folder.
* Create a subclass of `[api:SapphireTest]` in the `mysite/tests` or `(module)/tests` folder.
* Define static $fixture_file to point to a database YAML file.
* Create methods that start with "test" to create your tests.
* Assertions are used to work out if a test passed or failed.
@ -15,7 +15,6 @@ URLs. Here is an example from the subsites module:
static $fixture_file = 'subsites/tests/SubsiteTest.yml';
/**
* Return a session that has a user logged in as an administrator
*/
function adminLoggedInSession() {
@ -25,7 +24,6 @@ URLs. Here is an example from the subsites module:
}
/**
* Test generation of the view
*/
function testBasicView() {
@ -50,7 +48,7 @@ URLs. Here is an example from the subsites module:
We are using a new static method here: **Director::test($url, $postVars, $sessionObj)**
Director::test() lets us execute a URL and see what happens. It bypasses HTTP, instead relying on the cleanly
encapsulated execution model of Controller.
encapsulated execution model of `[api:Controller]`.
It takes 3 arguments:
@ -58,7 +56,7 @@ It takes 3 arguments:
* $postVars: Post variables to pass to the URL
* $sessionObj: A Session object representing the current session.
And it returns an HTTPResponse object, which will give you the response headers (including redirection), status code,
And it returns an `[api:HTTPResponse]` object, which will give you the response headers (including redirection), status code,
and body.
We can use string processing on the body of the response to then see if it fits with our expectations.

View File

@ -1,7 +1,7 @@
# How To Create a Sapphire Test
A unit test class will test the behaviour of one of your DataObjects. This simple fragment of SiteTreeTest provides us
the basics of creating unit tests.
A unit test class will test the behaviour of one of your `[api:DataObjects]`. This simple fragment of `[api:SiteTreeTest]`
provides us the basics of creating unit tests.
:::php
<?php
@ -47,7 +47,7 @@ the basics of creating unit tests.
There are a number of points to note in this code fragment:
* Your test is a **subclass of SapphireTest**. Both unit tests and functional tests are a subclass of SapphireTest.
* Your test is a **subclass of SapphireTest**. Both unit tests and functional tests are a subclass of `[api:SapphireTest]`.
* **static $fixture_file** is defined. The testing framework will automatically set up a new database for **each** of
your tests. The initial database content will be sourced from the YML file that you list in $fixture_file. You must
define this value. Note also that, for the time being, you can only point to one YML file for each test class.
@ -55,7 +55,7 @@ define this value. Note also that, for the time being, you can only point to on
database will be rebuilt for each of these.
* **$this->objFromFixture($className, $identifier)** can be used to select one of the objects named in your fixture
file. To identify to the object, we provide a class name and an identifier. The identifier is specified in the YML
file but not saved in the database anywhere. objFromFixture() looks the DataObject up in memory rather than using the
file but not saved in the database anywhere. objFromFixture() looks the `[api:DataObject]` up in memory rather than using the
database. This means that you can use it to test the functions responsible for looking up content in the database.
* **$this->assertEquals()** is one of the many assert... functions that PHPUnit provides us. See below for more
information.
@ -78,7 +78,7 @@ if it starts with "/".
## The Database YAML file
The main feature of SapphireTest over the raw PHPUnit classes is that SapphireTest will prepare a temporary database for
The main feature of `[api:SapphireTest]` over the raw PHPUnit classes is that SapphireTest will prepare a temporary database for
you. The content of that database is provided in a special YAML file. YAML is a simple markup languages that uses tabs
and colons instead of the more verbose XML tags, and because of this much better for developers creating files by hand.

View File

@ -15,8 +15,8 @@ send emails in your SilverStripe application. Here is a simple example of how y
$e->send();
Normally, the send() method would send an email using PHP's mail() function. However, if you are running a `SapphireTest` test, then it holds off actually sending the email, and instead lets you assert that an email was sent
using this method.
Normally, the send() method would send an email using PHP's mail() function. However, if you are running a `[api:SapphireTest]`
test, then it holds off actually sending the email, and instead lets you assert that an email was sent using this method.
:::php
$this->assertEmailSent("someone@example.com", null, "/th.*e$/");
@ -25,7 +25,7 @@ using this method.
The arguments are `$to`, `$from`, `$subject`, `$body`, and can be take one of the following three forms:
* A string: match exactly that string
* `null`/''false'': match anything
* `null/false`: match anything
* A PERL regular expression (starting with '/'): match that regular expression
## How to use it

View File

@ -217,28 +217,31 @@ Maybe even a nice link saying Website Powered by SilverStripe to show your suppo
A bunch of resources feel free to use to make your template awesome
* http://kuler.adobe.com - Kuler is a great color scheming tool
* http://blog.html.it/layoutgala/ - 40 super cool CSS layouts for you to use
* http://designmeltdown.com - Great gallery of websites. Browse through and get inspired.
* http://validator.w3.org/ - Your template must pass 'or get near' validation.
* http://famfamfam.com/lab/icons/ - free, beautiful icons.
* http://cssremix.com - Another CSS site gallery for inspiration.
* http://www.maxdesign.com.au/presentation/process/ - a good process for creating a design
* [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://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://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://www.maxdesign.com.au/presentation/process/](http://www.maxdesign.com.au/presentation/process/) - a good process for creating a design
## Reference
### Overriding
The templating system will search for the appropriate files in the following order:
1. mysite (or other name given to site folder)
2. themes
3. module (eg blog)
1. mysite (or other name given to site folder)
2. themes
3. module (eg blog)
So if, for example, you had a typography.css file for a module in the module folder (eg blog/css/), in the theme module
directory (eg themes/blackcandy_blog/css/), and in your site folder (eg mysite/css/), the system would use the file
mysite/css/typography.css
<div class="notice" markdown='1'>
Note: This only applies for CSS and template files. PHP files **do not** get overridden!
</div>
### Requirements

View File

@ -24,7 +24,7 @@ See [Developing Themes](theme-development) to get an idea of how themes actually
## 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
customise them.

View File

@ -60,15 +60,18 @@ Enabling Translatable through *Object::add_extension()* in your *mysite/_config.
}
Make sure to rebuild the database through /dev/build after enabling translatable.
Make sure to rebuild the database through /dev/build after enabling `[api:Translatable]`.
Use the correct set_default_locale() before building the database
for the first time, as this locale will be written on all new records.
#### Setting the default locale
Important: If the "default language" of your site is not english (en_US),
please ensure to set the appropriate default language for
your content before building the database with Translatable enabled:
<div class="notice" markdown='1'>
**Important:** If the "default language" of your site is not english (en_US), please ensure to set the appropriate default
language for your content before building the database with Translatable enabled
</div>
Example:
:::php
Translatable::set_default_locale(<locale>);
@ -98,7 +101,7 @@ Getting a translation for an existing instance:
Getting translations through Translatable::set_reading_locale().
This is *not* a recommended approach, but sometimes inavoidable (e.g. for Versioned methods).
This is *not* a recommended approach, but sometimes unavoidable (e.g. for `[api:Versioned]` methods).
:::php
$origLocale = Translatable::get_reading_locale();
@ -117,7 +120,7 @@ Creating a translation:
### Usage for SiteTree
Translatable can be used for subclasses of SiteTree as well.
`[api:Translatable]` can be used for subclasses of SiteTree as well.
If a child page translation is requested without the parent
page already having a translation in this language, the extension
will recursively create translations up the tree.
@ -126,7 +129,7 @@ languages by auto-appending the language code at the end.
You'll need to ensure that the appropriate "reading language" is set
before showing links to other pages on a website through $_GET['locale'].
Pages in different languages can have different publication states
through the Versioned extension.
through the `[api:Versioned]` extension.
Note: You can't get Children() for a parent page in a different language
through set_reading_locale(). Get the translated parent first.
@ -145,13 +148,13 @@ through set_reading_locale(). Get the translated parent first.
### Translating custom properties
Keep in mind that the Translatable extension currently doesn't support the exclusion of properties from being translated
- all custom properties will automatically be fetched from their translated record on the database. This means you don't
have to explicitly mark any custom properties as being translatable.
Keep in mind that the `[api:Translatable]` extension currently doesn't support the exclusion of properties from being
translated - all custom properties will automatically be fetched from their translated record on the database. This means
you don't have to explicitly mark any custom properties as being translatable.
The Translatable decorator applies only to the getCMSFields() method on DataObject or SiteTree, not to any fields added
in overloaded getCMSFields() implementations. See Translatable->updateCMSFields() for details. By default, custom fields
in the CMS won't show an original readonly value on a translated record, although they will save correctly. You can
The `[api:Translatable]` decorator applies only to the getCMSFields() method on DataObject or SiteTree, not to any fields
added in overloaded getCMSFields() implementations. See Translatable->updateCMSFields() for details. By default, custom
fields in the CMS won't show an original readonly value on a translated record, although they will save correctly. You can
attach this behaviour to custom fields by using Translatable_Transformation as shown below.
:::php
@ -195,7 +198,7 @@ URL, add a "locale" GET parameter. The German homepage would also be accessible
For this to work, please ensure that the translated homepage is a direct translation of the default homepage, and not a
new page created through "Create page...".
### Translationgroups
### Translation groups
Each translation can have an associated "master" object in another language which it is based on,
as defined by the "MasterTranslationID" property. This relation is optional, meaning you can
@ -223,26 +226,33 @@ SiteTree_translationgroups database table
### CharacterSets
Caution: Does not apply any character-set conversion, it is assumed that all content
<div class="warning" markdown='1'>
**Caution:** Does not apply any character-set conversion, it is assumed that all content
is stored and represented in UTF-8 (Unicode). Please make sure your database and
HTML-templates adjust to this.
</div>
### "Default"languages
### "Default" languages
Important: If the "default language" of your site is not english (en_US),
<div class="warning" markdown='1'>
**Important:** If the "default language" of your site is not english (en_US),
please ensure to set the appropriate default language for
your content before building the database with Translatable enabled:
your content before building the database with Translatable enabled
</div>
Example:
:::php
Translatable::set_default_locale(<locale>);
### Locales and languagetags
### Locales and language tags
For the Translatable class, a "locale" consists of a language code plus a region code separated by an underscore,
for example "de_AT" for German language ("de") in the region Austria ("AT").
See http://www.w3.org/International/articles/language-tags/ for a detailed description.
See [http://www.w3.org/International/articles/language-tags/](http://www.w3.org/International/articles/language-tags/)
for a detailed description.
Uninstalling/Disabling
@ -257,9 +267,9 @@ in the database.
### Switching languages
A widget now exists to switch between languages, and is [available
here](http://www.silverstripe.org/Language-Chooser-Widget/). You can easily make your own switchers with the following
basic tools. To stay friendly to caches and search engines, each translation of a page must have a unique URL
A widget now exists to switch between languages, and is [available here](http://www.silverstripe.org/Language-Chooser-Widget/).
You can easily make your own switchers with the following basic tools. To stay friendly to caches and search engines, each
translation of a page must have a unique URL.
By URL:
@ -284,7 +294,7 @@ By default, SilverStripe core doesn't provide any switching of languages through
SEO-friendly CMS, it contains all this information in the URL. Each page in SilverStripe is aware of its translations
through the *getTranslations()* method. We can use this method in our template to build a simple language switcher. It
shows all available translations in an unordered list with links to the same page in a different language. The example
below can be inserted in any of your templates, for example *themes/blackcandy/templates/Layout/Page.ss*.
below can be inserted in any of your templates, for example `themes/blackcandy/templates/Layout/Page.ss`.
:::php
<% if Translations %>
@ -306,9 +316,10 @@ just work if your locale value is registered in i18n::get_common_locales().
### Page-control
If you want to put static links in your template, which link to a site by their url, normally you can use the <% control
Page(page-url) %>. For sites which use Translatable, this is not possible for more than one language, because the url's
If you want to put static links in your template, which link to a site by their url, normally you can use the `<% control
Page(page-url) %>`. For sites which use Translatable, this is not possible for more than one language, because the url's
of different pages differ.
For this case place the following function in your Page_Controller:
:::php
@ -328,7 +339,8 @@ So, for example if you have a german page "Kontakt", which should be translated
<% control PageByLang(Kontakt,de_DE) %>
The control displays the link in the right language, depending on the current locale.\\
The control displays the link in the right language, depending on the current locale.
Example:
<% control PageByLang(Kontakt,de_DE) %>
@ -349,11 +361,11 @@ files, you'll need to [set the i18n locale](/topics/translation#setting_the_i18n
(The reasoning is as follows: Translatable doesn't set the i18n locale. Historically these were two separate systems,
but they're reasonably interchangeable for a front-end website. The distinction is mainly valid for the CMS, because you
want the CMS to be in English (i18n), but edit pages in different languages (Translatable).)
want the CMS to be in English (`[api:i18n]`), but edit pages in different languages (`[api:Translatable]`).)
### Migrating from 2.1 datamodel
The datamodel of Translatable changed significantly between its original release in SilverStripe 2.1 and SilverStripe
The datamodel of `[api:Translatable]` changed significantly between its original release in SilverStripe 2.1 and SilverStripe
2.3.2. See our [discussion on the
mailinglist](http://groups.google.com/group/silverstripe-dev/browse_thread/thread/91e26e1f78d3c1b4/bd276dd5bbc56283?lnk=gst&q=translatable#bd276dd5bbc56283).
@ -362,8 +374,8 @@ To migrate a database that was built with SilverStripe 2.1.x or 2.2.x, follow th
* Upgrade your SilverStripe installation to at least 2.3.2 (see [upgrading](/installation/upgrading))
* Backup your database content
* Login as an administrator
* Run http://mysite.com/dev/build
* Run http://mysite.com/dev/tasks/MigrateTranslatableTask
* Run `http://mysite.com/dev/build`
* Run `http://mysite.com/dev/tasks/MigrateTranslatableTask`
Please see the `[api:MigrateTranslatableTask]` for
limitations of this migration task - not all your data will be preserved.
@ -371,8 +383,8 @@ limitations of this migration task - not all your data will be preserved.
### Setting the i18n locale
You can set the i18n locale value which is used to format dates, currencies and other regionally different values to the
same as your current page locale.
You can set the `[api:i18n]` locale value which is used to format dates, currencies and other regionally different values to
the same as your current page locale.
:::php
class Page_Controller extends ContentController {
@ -388,8 +400,8 @@ same as your current page locale.
### Adding a new locale
The i18n logic has lookup tables for common locales in i18n::$common_locales, which is a subset of i18n::$all_locales.
If your locale is not present here, you can simply add it through mysite/_config.php:
The `[api:i18n]` logic has lookup tables for common locales in i18n::$common_locales, which is a subset of i18n::$all_locales.
If your locale is not present here, you can simply add it through `mysite/_config.php`:
:::php
i18n::$common_locales['de_AT'] = 'Deutsch (Oestereich)';
@ -403,4 +415,4 @@ This should e.g. enable you to use `$Locale.Nice` in template code.
* [i18n](i18n): Developer-level documentation of Silverstripe's i18n capabilities
* `[api:Translatable]`: DataObject-interface powering the website-content translations
* ["Translatable ModelAdmin" module](http://silverstripe.org/translatablemodeladmin-module/): An extension which allows
translations of DataObjects inside `[api:ModelAdmin]`
translations of `[api:DataObject]`s inside `[api:ModelAdmin]`

View File

@ -2,39 +2,46 @@
## Introduction
Widgets are small pieces of functionality such as showing the latest Comments or Flickr Photos. They normally display on
the sidebar of your website. To check out a what a Widget can do watch the video http://silverstripe.org/widgets and try
out the demo site http://silverstripe.com/assets/screencasts/SilverStripe-Blog-DragDrop-Widgets.swf
[Widgets](http://silverstripe.org/widgets) are small pieces of functionality such as showing the latest Comments or Flickr Photos. They normally display on
the sidebar of your website. To check out a what a [Widget](http://silverstripe.org/widgets) can do watch the
[Widget video](http://silverstripe.com/assets/screencasts/SilverStripe-Blog-DragDrop-Widgets.swf) and try out the
[demo site](http://demo.silverstripe.org/)
## How to Use A Widget
### Downloading and Contributing Widgets
* To download widgets visit [Widgets section](http://silverstripe.org/widgets)
* Upload widgets you want to share to
[http://silverstripe.org/widgets/manage/add](http://silverstripe.org/widgets/manage/add). Make sure you read the
packaging instructions at the bottom of the page about how to make your widget package.
### Installing a widget
By following the "Packaging" rules below, widgets are easily installed.
* Download the file and unzip to the main folder of your SilverStripe website, e.g. to "/widget_twitter/". The folder
* Install the [blog module](http://www.silverstripe.org/blog-module/) (by default only the Blog has widgets enabled)
* Download the file and unzip to the main folder of your SilverStripe website, e.g. to `/widget_<widget-name>/`. The folder
will contain a few files, which generally won't need editing or reading.
* Run dev/build
* Login to the CMS and go to the 'Blog' page. Choose the "widgets" tab and drag n drop the new widget to activate it.
* Your blog will now have the widget shown.
* Run `http://my-website.com/dev/build`
* Login to the CMS and go to the 'Blog' page. Choose the "widgets" tab and drag n drop the new widget to activate it.
* Your blog will now have the widget shown
### Adding widgets to other pages
As of 2.2.1 this is this is a way to add widgets to other pages (by default only the Blog has widgets enabled). In the
future releases we will hopefully make widgets part of SiteTree therefore available on every page. In the mean time you
have to do a couple things to get a Widget to work on a page.
<div class="notice" markdown='1'>
As of version 2.2.1 there is a way to add widgets to other pages. In future releases we will hopefully make widgets part
of SiteTree therefore available on every page.
</div>
You have to do a couple things to get a Widget to work on a page.
First step is to add an WidgetArea to the Database to store the widget details. Then you have to edit the CMS to add a
Widget Form to manage the widgets. An example of this is below
** mysite/code/Page.php **
**mysite/code/Page.php**
:::php
class Page extends SiteTree {
@ -53,18 +60,16 @@ Widget Form to manage the widgets. An example of this is below
}
Then in your Template you need to call $SideBar whereever you want to render the widget
Then in your Template you need to call $SideBar wherever you want to render the widget
Eg for blackcandy I put this above the closing `</div>`
For example: using the blackcandy theme I put this piece of code above the closing `</div>`
** themes/myThemeName/templates/Includes/Sidebar.ss **
**themes/blackcandy/templates/Includes/Sidebar.ss**
:::ss
$Sidebar
## Writing your own widgets
To create a Widget you need at least three files - a php file containing the class, a template file of the same name and
@ -180,7 +185,7 @@ To render the widget, simply include $SilverStripeFeed in your template:
As directed in the definition of SilverStripeFeed(), the Widget will be rendered through the WidgetHolder template. This
is pre-defined at /sapphire/templates/WidgetHolder.ss and simply consists of:
is pre-defined at `/sapphire/templates/WidgetHolder.ss` and simply consists of:
:::ss
<div class="WidgetHolder">
@ -190,14 +195,14 @@ is pre-defined at /sapphire/templates/WidgetHolder.ss and simply consists of:
You can override the WidgetHolder.ss and Widget.ss templates in your theme too by adding WidgetHolder and Widget
templates to ** themes/myThemeName/templates/Includes/ **
templates to `themes/myThemeName/templates/Includes/`
### Changing the title of your widget
To change the title of your widget, you need to override the Title() method. By default, this simply returns the $title
variable. For example, to set your widgets title to 'Hello World!', you could use:
** widgets_yourWidget/YourWidgetWidget.php **
**widgets_yourWidget/YourWidgetWidget.php**
:::php
function Title() {
@ -221,13 +226,13 @@ This returns the value inputted in the CMS, if it's set or what is in the $title
### Forms within Widgets
*Requires SilverStripe 2.4 or newer*
**Requires SilverStripe 2.4 or newer**
To implement a form inside a widget, you need to implement a custom controller for your widget to return this form. Make
sure that your controller follows the usual naming conventions, and it will be automatically picked up by the
`[api:WidgetArea]` rendering in your *Page.ss* template.
*mysite/code/MyWidget.php*
**mysite/code/MyWidget.php**
:::php
class MyWidget extends Widget {
@ -258,26 +263,27 @@ sure that your controller follows the usual naming conventions, and it will be a
To output this form, modify your widget template.
*mysite/templates/MyWidget.ss*
**mysite/templates/MyWidget.ss**
:::ss
$Content
$MyFormName
Note: The necessary controller actions are only present in subclasses of `[api:Page_Controller]`. To use
<div class="notice" markdown='1'>
**Note:** The necessary controller actions are only present in subclasses of `[api:Page_Controller]`. To use
widget forms in other controller subclasses, have a look at *ContentController->handleWidget()* and
*ContentController::$url_handlers*.
</div>
See an [alternative recipe for SilverStripe 2.3 or earlier](http://doc.silverstripe.org/old/recipes/widget-forms-2.3).
## But what if I have widgets on my blog currently??
## But what if I have widgets on my blog currently??
If you currently have a blog installed, the widget fields are going to double up on those pages (as the blog extends the
Page class). One way to fix this is to comment out line 30 in BlogHolder.php and remove the DB entry by running a
/db/build.
`http://www.mysite.com/db/build`.
** blog/code/BlogHolder.php **
**blog/code/BlogHolder.php**
:::php
<?php
@ -304,7 +310,7 @@ Then you can use the Widget area you defined on Page.php
### Packaging
For a widget to be put in our official widget database they must follow this convention - If the name of your widget was
"TwitterWidget" then:
"YourName" then:
#### File Structure for your widget
@ -323,19 +329,21 @@ would understand, then make it configurable in the _config.php file.
This way, the CMS remains an application designed for content authors, and not developers.
** widget_name/_config.php **
*widget_name/_config.php*
:::php
<?php /* */ ?>
** Example Widget Structure **
**Example Widget Structure**
![](_images/widget_demo.gif)
#### How to make the Package
* Make a tar.gz file called widgets_flickr-0.1.tar.gz (where 0.1 is the version number).
* Ensure when you "unzip" the compressed file it has everything the "widgets_flickr" folder with everything inside
* Make a tar.gz file called widgets_YourName-0.1.tar.gz (where 0.1 is the version number).
* Ensure when you "unzip" the compressed file it has everything the "widgets_YourName" folder with everything inside
it.
* If made official, it will be given these locations at silverstripe.com:
* SVN location: http://svn.silverstripe.com/open/modules/widgets/flickr/trunk

View File

@ -627,7 +627,7 @@ a new *StaffHolder* called "Staff" in the "About Us" section, and create some *S
### Creating the staff section templates
The staff section templates aren't too difficult to create, thanks to the utility methods provided by the *Image* class.
The staff section templates aren't too difficult to create, thanks to the utility methods provided by the `[api:Image]` class.
**themes/tutorial/templates/Layout/StaffHolder.ss**
@ -650,7 +650,7 @@ The staff section templates aren't too difficult to create, thanks to the utilit
</div>
This template is very similar to the *ArticleHolder* template. The *FirstSentence* method of the `[api:Text]` class
This template is very similar to the *ArticleHolder* template. The *SetWidth* method of the `[api:Image]` class
will resize the image before sending it to the browser. The resized image is cached, so the server doesn't have to
resize the image every time the page is viewed.

View File

@ -47,7 +47,7 @@ instructions below as well.
If you are using SilverStripe 2.2 or earlier then you need to define your own code. The first step in implementing
search on your site is to create a form for the user to type their query. Create a function named *SearchForm* on the
*Page_Controller* class (//mysite/code/Page.php//).
*Page_Controller* class (/mysite/code/Page.php).
:::php
class Page_Controller extends ContentController {
@ -66,6 +66,69 @@ search on your site is to create a form for the user to type their query. Create
}
}
### Custom CSS code
Add the following css code to the *themes/tutorial/css/layout.css* file. This will style the header form and search
results page.
:::css
#Header form {
float:right;
width:160px;
margin:25px 25px 0px 25px;
}
#Header form * {
display:inline !important;
}
#Header form div {
}
#Header form input.text {
width:110px;
color:#000;
background:#f0f0f0;
border:1px solid #aaa;
padding:3px;
}
#Header form input.action {
font-weight:bold;
}
.searchResults h2 {
font-size:2.2em;
font-weight:normal;
color:#0083C8;
margin-bottom:15px;
}
.searchResults p.searchQuery {
color:#333;
margin-bottom:10px;
}
.searchResults ul#SearchResults li {
margin-bottom:20px;
}
ul#SearchResults p {
font-size:1.1em;
font-weight:normal;
line-height:2em;
color:#333;
}
ul#SearchResults a.searchResultHeader {
font-size:1.3em;
font-weight:bold;
color:#0083C8;
text-decoration:none;
margin:20px 0 8px 0;
padding-left:20px;
background:url(../images/treeicons/search-file.gif) no-repeat left center;
}
ul#SearchResults a {
text-decoration:none;
color:#0083C8;
}
ul#SearchResults a:hover {
border-bottom:1px dotted #0083C8;
}
## Adding the search form

View File

@ -7,6 +7,11 @@ to the *$db* array and how to add an image using the *$has_one* array and so cre
the *Image* table by storing the id of the respective *Image* in the first table. This tutorial explores all this
relations between [DataObjects](/topics/datamodel#relations) and the way to manage them easily.
<div class="notice" markdown='1'>
I'm using the default tutorial theme in the following examples so the templates may vary or you may need to change
the template code in this example to fit your theme
</div>
## What are we working towards?
To simulate these relations between objects, we are going to simulate the management via the CMS of the **[Google Summer
@ -79,9 +84,11 @@ The first step is to create the student and project objects.
function getCMSFields_forPopup() {
$fields = new FieldSet();
$fields->push( new TextField( 'FirstName', 'First Name' ) );
$fields->push( new TextField( 'Lastname' ) );
$fields->push( new TextField( 'Nationality' ) );
return $fields;
}
@ -262,6 +269,8 @@ The first step is to create the mentor object and set the relation with the *Stu
}
class Mentor_Controller extends Page_Controller {}
*tutorial/code/Student.php*
:::php
class Student extends DataObject {
@ -279,6 +288,8 @@ respective *Mentor* in the *Student* table.
The second step is to add the table in the method *getCMSFields* which will allow you to manage the *has_many* relation.
*tutorial/code/Mentor.php*
:::php
class Mentor extends Page {
@ -308,6 +319,7 @@ The second step is to add the table in the method *getCMSFields* which will allo
}
}
class Mentor_Controller extends Page_Controller {}
To know more about the parameters of the *HasManyComplexTableField* constructor, [check](#project_-_student_relation)
those of the *HasOneComplexTableField* constructor.
@ -356,6 +368,8 @@ The first step is to create the module object and set the relation with the *Pro
*tutorial/code/Module.php*
:::php
<?php
class Module extends DataObject {
static $db = array(
@ -374,6 +388,8 @@ The first step is to create the module object and set the relation with the *Pro
}
*tutorial/code/Project.php*
:::php
class Project extends Page {
@ -424,9 +440,10 @@ To know more about the parameters of the *ManyManyComplexTableField* constructor
[check](#project_-_student_relation) those of the *HasOneComplexTableField*
constructor.
Don't forget to rebuild the database using
[http://localhost:3000/db/build?flush=1](http://localhost:3000/db/build?flush=1) before you proceed to the next part of
this tutorial.
<div class="tip" markdown='1'>
Don't forget to rebuild the database using *dev/build?flush=1* before you
proceed to the next part of this tutorial.
</div>
Select now one of the *Project* page, go in the tab panel *Modules* and add all the modules listed
[above](#what-are-we-working-towards) by clicking on the link **Add A
@ -459,7 +476,7 @@ We will see in this section how to display all these relations but also how to c
For every kind of *Page* or *DataObject*, you can access to their relations thanks to the **control** loop.
**__1. GSOC Projects__**
**1. GSOC Projects**
Let's start with the *ProjectsHolder* page created before. For this template, we are will display the same table than
[above](#what-are-we-working-towards).
@ -469,94 +486,79 @@ Let's start with the *ProjectsHolder* page created before. For this template, we
*tutorial/templates/Layout/ProjectsHolder.ss*
:::ss
<div class="typography">
<% if Menu(2) %>
<% include SideBar %>
<div id="Content">
<% end_if %>
<% if Level(2) %>
<% include Menu2 %>
<div id="Content" class="typography">
<% if Level(2) %>
<% include BreadCrumbs %>
<% end_if %>
<h2>$Title</h2>
$Content
<table>
<thead>
$Content
<table>
<thead>
<tr>
<th>Project</th>
<th>Student</th>
<th>Mentor</th>
<th>Modules</th>
</tr>
</thead>
<tbody>
<% control Children %>
<tr>
<th>Project</th>
<th>Student</th>
<th>Mentor</th>
<th>Modules</th>
<td>$Title</td>
<td>
<% if MyStudent %>
<% control MyStudent %>
$FirstName $Lastname
<% end_control %>
<% else %>
No Student
<% end_if %>
</td>
<td>
<% if MyStudent %>
<% control MyStudent %>
<% if MyMentor %>
<% control MyMentor %>
$FirstName $Lastname
<% end_control %>
<% else %>
No Mentor
<% end_if %>
<% end_control %>
<% else %>
No Mentor
<% end_if %>
</td>
<td>
<% if Modules %>
<% control Modules %>
$Name &nbsp;
<% end_control %>
<% else %>
No Modules
<% end_if %>
</td>
</tr>
</thead>
<tbody>
<% control Children %>
<tr>
<td>$Title</td>
<td>
<% if MyStudent %>
<% control MyStudent %>
$FirstName $Lastname
<% end_control %>
<% else %>
No Student
<% end_if %>
</td>
<td>
<% if MyStudent %>
<% control MyStudent %>
<% if MyMentor %>
<% control MyMentor %>
$FirstName $Lastname
<% end_control %>
<% else %>
No Mentor
<% end_if %>
<% end_control %>
<% else %>
No Mentor
<% end_if %>
</td>
<td>
<% if Modules %>
<% control Modules %>
$Name &nbsp;
<% end_control %>
<% else %>
No Modules
<% end_if %>
</td>
</tr>
<% end_control %>
</tbody>
</table>
$Form
$PageComments
<% if Menu(2) %>
</div>
<% end_if %>
<% end_control %>
</tbody>
</table>
$Form
</div>
*tutorial/templates/Includes/SideBar.ss*
You might want to move the include above the typography div in your layouts to get rid of the bullets.
:::ss
<% if Menu(2) %>
<ul id="Menu2">
<% control Menu(2) %>
<li class="$LinkingMode"><a href="$Link" title="Go to the &quot;{$Title}&quot; page">$MenuTitle</a></li>
<% end_control %>
</ul>
<% end_if %>
<div class="notice" markdown='1'>
If you are using the blackcandy template: You might want to move the `<% include Sidebar %>`
(tutorial/templates/Includes/SideBar.ss) include in the *tutorial/templates/Layout/Page.ss* template above
the typography div to get rid of the bullets
</div>
**__2. Project__**
**2. Project**
We know now how to easily access and show [relations](../topics/datamodel#relations) between *DataObject* in a template.
@ -567,62 +569,51 @@ We can now do the same for every *Project* page by creating its own template.
*tutorial/templates/Layout/Project.ss*
:::ss
<div class="typography">
<% if Menu(2) %>
<% include SideBar %>
<div id="Content">
<% end_if %>
<% if Level(2) %>
<% include Menu2 %>
<div id="Content" class="typography">
<% if Level(2) %>
<% include BreadCrumbs %>
<% end_if %>
<h2>$Title</h2>
$Content
<h3>Student</h3>
<% if MyStudent %>
<% control MyStudent %>
<p>First Name: <strong>$FirstName</strong></p>
<p>Lastname: <strong>$Lastname</strong></p>
<p>Nationality: <strong>$Nationality</strong></p>
<h3>Mentor</h3>
<% if MyMentor %>
<% control MyMentor %>
<p>First Name: <strong>$FirstName</strong></p>
<p>Lastname: <strong>$Lastname</strong></p>
<p>Nationality: <strong>$Nationality</strong></p>
<% end_control %>
<% else %>
<p>This student doesn't have any mentor.</p>
<% end_if %>
<% end_control %>
<% else %>
<p>There is no any student working on this project.</p>
<% end_if %>
<h3>Modules</h3>
<% if Modules %>
<ul>
<% control Modules %>
<li>$Name</li>
$Content
<% if MyStudent %>
<% control MyStudent %>
<p>First Name: <strong>$FirstName</strong></p>
<p>Lastname: <strong>$Lastname</strong></p>
<p>Nationality: <strong>$Nationality</strong></p>
<h3>Mentor</h3>
<% if MyMentor %>
<% control MyMentor %>
<p>First Name: <strong>$FirstName</strong></p>
<p>Lastname: <strong>$Lastname</strong></p>
<p>Nationality: <strong>$Nationality</strong></p>
<% end_control %>
</ul>
<% else %>
<p>This project has not used any modules.</p>
<% end_if %>
$Form
$PageComments
<% if Menu(2) %>
</div>
<% else %>
<p>This student doesn't have any mentor.</p>
<% end_if %>
<% end_control %>
<% else %>
<p>There is no any student working on this project.</p>
<% end_if %>
<h3>Modules</h3>
<% if Modules %>
<ul>
<% control Modules %>
<li>$Name</li>
<% end_control %>
</ul>
<% else %>
<p>This project has not used any modules.</p>
<% end_if %>
$Form
</div>
@ -647,37 +638,39 @@ from templates either within a control block or dot notation.
*tutorial/code/Student.php, tutorial/code/Mentor.php*
:::php
function PersonalInfo() {
$template = 'GSOCPerson';
return $this->renderWith( $template );
}
function PersonalInfo() {
$template = 'GSOCPerson';
return $this->renderWith( $template );
}
We can now modify the *Project* template.
We can now modify the *Project.ss* template.
:::ss
...
...
<% if MyStudent %>
$MyStudent.PersonalInfo
<% if MyStudent %>
$MyStudent.PersonalInfo
<h3>Mentor</h3>
<h3>Mentor</h3>
<% control MyStudent %>
<% if MyMentor %>
$MyMentor.PersonalInfo
<% else %>
<p>This student doesn't have any mentor.</p>
<% end_if %>
<% end_control %>
<% else %>
<p>There is no any student working on this project.</p>
<% end_if %>
...
<% control MyStudent %>
<% if MyMentor %>
$MyMentor.PersonalInfo
<% else %>
<p>This student doesn't have any mentor.</p>
<% end_if %>
<% end_control %>
<% else %>
<p>There is no any student working on this project.</p>
<% end_if %>
...
<div class="notice" markdown='1'>
Remember to add `?flush=1` to the url when refreshing the project page or otherwise you will get a template error
</div>
In the *Project* template, it has been really easy to display the **1-to-1** relation with a *Student* object just by
calling the variable **$MyStudent**. This has been made possible thanks to the code below present in the *Project*
@ -692,7 +685,7 @@ class.
However, in the *Student* class, there is no any code relating to the **1-to-1** relation with a *Project* *Page*. So
how to access it from a *Student* *DataObject* ?
**__3. Mentor__**
**3. Mentor**
In this template, we are gonna try to access the *Project* details from a *Student* *DataObject*.
@ -707,11 +700,11 @@ it *MyProject* for instance.
:::php
class Student extends DataObject {
...
...
function MyProject() {
return DataObject::get( 'Project', "`MyStudentID` = '{$this->ID}'" );
}
function MyProject() {
return DataObject::get( 'Project', "`MyStudentID` = '{$this->ID}'" );
}
}
@ -722,65 +715,51 @@ That's how we can use this function in the *Mentor* template.
*tutorial/templates/Layout/Mentor.ss*
:::ss
<div class="typography">
<% if Menu(2) %>
<% include SideBar %>
<div id="Content">
<% end_if %>
<% if Level(2) %>
<% include BreadCrumbs %>
<% end_if %>
<h2>$Title</h2>
$Content
<h3>Personal Details</h3>
<p>First Name: <strong>$FirstName</strong></p>
<p>Lastname: <strong>$Lastname</strong></p>
<p>Nationality: <strong>$Nationality</strong></p>
<h3>Students</h3>
<% if Students %>
<table>
<thead>
<tr>
<th>Student</th>
<th>Project</th>
</tr>
</thead>
<tbody>
<% control Students %>
<tr>
<td>$FirstName $Lastname</td>
<td>
<% if MyProject %>
<% control MyProject %>
$Title
<% end_control %>
<% else %>
No Project
<% end_if %>
</td>
</tr>
<% end_control %>
</tbody>
</table>
<% else %>
<p>There is no any student working with this mentor.</p>
<% end_if %>
$Form
$PageComments
<% if Menu(2) %>
</div>
<% end_if %>
</div>
<% include Menu2 %>
<div id="Content" class="typography">
<% include Breadcrumbs %>
$Content
<h3>Personal Details</h3>
<p>First Name: <strong>$FirstName</strong></p>
<p>Lastname: <strong>$Lastname</strong></p>
<p>Nationality: <strong>$Nationality</strong></p>
<h3>Students</h3>
<% if Students %>
<table>
<thead>
<tr>
<th>Student</th>
<th>Project</th>
</tr>
</thead>
<tbody>
<% control Students %>
<tr>
<td>$FirstName $Lastname</td>
<td>
<% if MyProject %>
<% control MyProject %>
$Title
<% end_control %>
<% else %>
No Project
<% end_if %>
</td>
</tr>
<% end_control %>
</tbody>
</table>
<% else %>
<p>There is no any student working with this mentor.</p>
<% end_if %>
$Form
</div>
## Summary
@ -791,4 +770,6 @@ CMS and how to display them on the website.
## Download the code
You can download all the [complete code](http://doc.silverstripe.org/src/github/master/sapphire/docs/en/tutorials/_images/tutorial5-completecode.zip) of this tutorial.
Download all the [code](http://doc.silverstripe.org/src/github/master/sapphire/docs/en/tutorials/_images/tutorial5-completecode.zip) for this tutorial.
You can also download the [code](http://doc.silverstripe.org/src/github/master/sapphire/docs/en/tutorials/_images/tutorial5-completecode-blackcandy.zip) for use in the blackcandy template.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

After

Width:  |  Height:  |  Size: 50 KiB