Review, cleanup and refresh of integration section

This commit is contained in:
Will Rossiter 2014-09-28 16:59:48 +13:00 committed by Cam Findlay
parent 0c73768e8c
commit 3d8c9232e0
9 changed files with 469 additions and 235 deletions

View File

@ -1,49 +1,66 @@
summary: Consume external data through their RESTFul interfaces.
# Restful Service
## Introduction
`[api:RestfulService]` uses the php curl library, enabling connections to remote web services which support a REST interface and consuming those web services. (Examples: [Flickr](http://www.flickr.com/services/api/), [Youtube](http://code.google.com/apis/youtube/overview.html), Amazon and etc). `[api:RestfulService]` can parse the XML response (sorry no JSON support)
returned from the web service. Further it supports caching of the response, and you can customize the cache interval.
To gain the functionality you can either create a new `[api:RestfulService]` object or create a class extending the
RestfulService (see [flickrservice](http://silverstripe.org/flickr-module/) and
[youtubeservice](http://silverstripe.org/youtube-gallery-module/) modules).
`[api:RestfulService]` is used to enable connections to remote web services through PHP's `curl` command. It provides an
interface and utility functions for generating a valid request and parsing the response returned from the web service.
<div class="alert" markdown="1">
RestfulService currently only supports XML. It has no JSON support at this stage.
</div>
## Examples
### Creating a new RestfulObject
:::php
//example for using RestfulService to connect and retrive latest twitter status of an user.
$twitter = new RestfulService("http://twitter.com/statuses/user_timeline/user.xml", $cache_expiry );
$params = array('count' => 1);
$twitter->setQueryString($params);
$conn = $twitter->request();
$msgs = $twitter->getValues($conn, "status");
`getWellingtonWeather` queries the Yahoo Weather API for an XML file of the latest weather information. We pass a query
string parameter `q` with the search query and then convert the resulting XML data to an `ArrayList` object to display
in the template.
### Extending to a new class
**mysite/code/Page.php**
:::php
//example for extending RestfulService
class FlickrService extends RestfulService {
public function getWellingtonWeather() {
$fetch = new RestfulService(
'https://query.yahooapis.com/v1/public/yql'
);
public function __construct($expiry=NULL){
parent::__construct('http://www.flickr.com/services/rest/', $expiry);
$this->checkErrors = true;
$fetch->setQueryString(array(
'q' => 'select * from weather.forecast where woeid in (select woeid from geo.places(1) where text="Wellington, NZ")'
));
// perform the query
$conn = $fetch->request();
// parse the XML body
$msgs = $fetch->getValues($conn->getBody(), "results");
// generate an object our templates can read
$output = new ArrayList();
if($msgs) {
foreach($msgs as $msg) {
$output->push(new ArrayData(array(
'Description' => Convert::xml2raw($msg->channel_item_description)
)));
}
}
......
return $output;
}
### Multiple requests by using the $subURL argument on connect()
## Features
### Basic Authenication
:::php
// Set up REST service
$service = new RestfulService("http://example.harvestapp.com");
$service->basicAuth('username', 'password');
$service->httpHeader('Accept: application/xml');
$service->httpHeader('Content-Type: application/xml');
### Make multiple requests
:::php
$service = new RestfulService("http://example.harvestapp.com");
$peopleXML = $service->request('/people');
$people = $service->getValues($peopleXML, 'user');
@ -54,21 +71,20 @@ RestfulService (see [flickrservice](http://silverstripe.org/flickr-module/) and
$tasks = $service->getValues($taskXML, 'task');
## Features
### Caching
To set the cache interval you can pass it as the 2nd argument to constructor.
:::php
new RestfulService("http://twitter.com/statuses/user_timeline/user.xml", 3600 );
$expiry = 60 * 60; // 1 hour;
$request = new RestfulService("http://example.harvestapp.com", $expiry );
### Getting Values & Attributes
You can traverse throught document tree to get the values or attribute of a particular node.
for example you can traverse
You can traverse through document tree to get the values or attribute of a particular node using XPath. Take for example
the following XML that is returned.
:::xml
<entries>
@ -78,62 +94,77 @@ for example you can traverse
<entry id='22'>John</entry>
</entries>
to extract the id attributes of the entries use:
To extract the id attributes of the entries use:
:::php
$this->getAttributes($xml, "entries", "entry") //will return all attributes of each entry node
$this->getAttributes($xml, "entries", "entry");
// array(array('id' => 12), array('id' => '15'), ..)
to extract the values (the names) of the entries use:
To extract the values (the names) of the entries use:
:::php
$this->getValues($xml, "entries", "entry") //will return all values of each entry node
$this->getValues($xml, "entries", "entry");
// array('Sally', 'Ted', 'Matt', 'John')
### Searching for Values & Attributes
If you don't know the exact position of dom tree where the node will appear you can use xpath to search for the
node.Recommended for retrieving values of namespaced nodes.
If you don't know the exact position of DOM tree where the node will appear you can use xpath to search for the node.
<div class="note">
This is the recommended method for retrieving values of name spaced nodes.
</div>
:::xml
<media:guide>
<media:entry id="2030">video</media:entry>
</media:guide>
to get the value of entry node with the namespace media, use:
To get the value of entry node with the namespace media, use:
:::php
$this->searchValue($response, "//media:guide/media:entry")
$this->searchValue($response, "//media:guide/media:entry");
// array('video');
## Best Practices
### Handling Errors
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
If the web service returned an error (for example, API key not available or inadequate parameters),
`[api:RestfulService]` can delegate the error handling to it's descendant class. To handle the errors, subclass
`RestfulService and define a function called errorCatch.
:::php
// This will raise Youtube API specific error messages (if any).
<?php
class MyRestfulService extends RestfulService {
public function errorCatch($response) {
$err_msg = $response;
if(strpos($err_msg, '<') === false) {
user_error("YouTube Service Error : $err_msg", E_USER_ERROR);
}
return $response;
}
}
If you want to bypass error handling on your sub-classes you could define that in the constructor.
If you want to bypass error handling, define `checkErrors` in the constructor for `RestfulService`
:::php
<?php
class MyRestfulService extends RestfulService {
public function __construct($expiry = NULL) {
parent::__construct('http://www.flickr.com/services/rest/', $expiry);
$this->checkErrors = false; //Set checkErrors to false to bypass error checking
$this->checkErrors = false;
}
}
@ -182,41 +213,11 @@ $service->request('service.json', 'GET', null, null, $curlOptions);
```
## Other Uses
### 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
Put something like this code in mysite/code/Page.php inside class Page_Controller
:::php
// Accepts an RSS feed URL and outputs a list of links from it
public function RestfulLinks($url){
$service = new RestfulService($url);
$request = $service->request();
$body = $request->getBody();
$items = $service->getValues($body,"channel","item");
$output = '';
foreach($items as $item) {
// Fix quote encoding
$description = str_replace('&amp;quot;', '&quot;', $item->description);
$output .= "<li><a href=\"{$item->link}\">{$item->title}</a><br />{$description}</li>";
}
return $output;
}
Put something like this code in `themes/<your-theme>/templates/Layout/HomePage.ss`:
:::ss
<h3>My Latest Del.icio.us Links</h3>
<ul>
$RestfulLinks(http://del.icio.us/rss/elijahlofgren)
</ul>
## How to's
* [Embed an RSS Feed](how_to/embed_rss)
## API Documentation
`[api:RestfulService]`
* `[api:RestfulService]`

View File

@ -1,27 +1,26 @@
title: RSS Feed
summary: Output records from your database as an RSS Feed.
# RSS Feed
## Introduction
Generating RSS / Atom-feeds is a matter of rendering a `[api:SS_List]` instance through the `[api:RSSFeed]` class.
Generating RSS/Atom-feeds is a matter of rendering a `[api:SS_List]` through
the `[api:RSSFeed]` class.
The `[api:RSSFeed]` class doesn't limit you to generating article based feeds, it is just as easy to create a feed of
your current staff members, comments or any other custom `[api:DataObject]` subclasses you have defined. The only
logical limitation here is that every item in the RSS-feed should be accessible through a URL on your website, so it's
advisable to just create feeds from subclasses of `[api:SiteTree]`.
The `[api:RSSFeed]` class doesn't limit you to generating article based feeds,
it is just as easy to create a feed of your current staff members, comments or
any other custom `[api:DataObject]` subclasses you have defined. The only
logical limitation here is that every item in the RSS-feed should be accessible
through a URL on your website, so its advisable to just create feeds from sub
classes of `[api:SiteTree]`.
If you wish to generate an RSS feed for `[api:DataObject]` instances, ensure they
define an AbsoluteLink() method.
<div class="warning" markdown="1">
If you wish to generate an RSS feed that contains a `[api:DataObject]`, ensure you define a `AbsoluteLink` method on
the object.
</div>
## Usage
:::php
RSSFeed::linkToFeed($link, $title)
Including an RSS feed has two steps. First, a `Controller` action which responses with the `XML` and secondly, the other
web pages need to link to the URL to notify users that the RSS feed is available and where it is.
This line should go in your `[api:Controller]` subclass in the action you want
to include the HTML link. Not all arguments are required, see `[api:RSSFeed]` and example below. Last Modified Time is expected in seconds like time().
An outline of step one looks like:
:::php
$feed = new RSSFeed(
@ -36,63 +35,48 @@ to include the HTML link. Not all arguments are required, see `[api:RSSFeed]` an
$etag
);
Creates a new `[api:RSSFeed]` instance to be returned. The arguments notify
SilverStripe what values to include in the feed.
$feed->outputToBrowser();
To achieve step two include the following code where ever you want to include the `<link>` tag to the RSS Feed. This
will normally go in your `Controllers` `init` method.
:::php
RSSFeed::linkToFeed($link, $title);
## Examples
### Showing latest blog posts
:::php
class Page_Controller extends ContentController {
private static $allowed_actions = array('rss');
public function init() {
parent::init();
// linkToFeed will add an appropriate HTML link tag to the website
// <head> tag to notify web browsers that an RSS feed is available
// for this page. You can include as many feeds on the page as you
// wish as long as each as a different link. For example:
// ('blog/rss', 'staff/rss').
//
// In this example $this->Link("rss") refers to the *rss* function
// we define below.
RSSFeed::linkToFeed($this->Link("rss"), "RSS feed of this blog");
}
public function rss() {
// Creates a new RSS Feed list
$rss = new RSSFeed(
$list = $this->getBlogPosts(), // an SS_List containing your feed items
$link = $this->Link("rss"), // a HTTP link to this feed
$title = "My feed", // title for this feed, displayed in RSS readers
$description = "This is an example feed." // description
);
// Outputs the RSS feed to the user.
return $rss->outputToBrowser();
}
public function getBlogPosts() {
return BlogPage::get()->limit(10);
}
}
### Showing the 10 most recently updated pages
You can use `[api:RSSFeed]` to easily create a feed showing your latest Page
updates. Update mysite/code/Page.php to something like this:
You can use `[api:RSSFeed]` to easily create a feed showing your latest Page updates. The following example adds a page
`/home/rss/` which displays an XML file the latest updated pages.
**mysite/code/Page.php**
:::php
<?php
class Page extends SiteTree {}
..
class Page_Controller extends ContentController {
private static $allowed_actions = array('rss');
private static $allowed_actions = array(
'rss'
);
public function init() {
parent::init();
RSSFeed::linkToFeed($this->Link() . "rss", "10 Most Recently Updated Pages");
}
public function rss() {
$rss = new RSSFeed($this->LatestUpdates(), $this->Link(), "10 Most Recently Updated Pages", "Shows a list of the 10 most recently updated pages.");
$rss = new RSSFeed(
$this->LatestUpdates(),
$this->Link(),
"10 Most Recently Updated Pages",
"Shows a list of the 10 most recently updated pages."
);
return $rss->outputToBrowser();
}
@ -103,78 +87,109 @@ updates. Update mysite/code/Page.php to something like this:
### Rendering DataObjects in a RSSFeed
DataObjects can be rendered in the feed as well, however, since they aren't explicitly
`[api:SiteTree]` subclasses we need to include a function `AbsoluteLink` to allow the
RSS feed to link through to the item.
DataObjects can be rendered in the feed as well, however, since they aren't explicitly `[api:SiteTree]` subclasses we
need to include a function `AbsoluteLink` to allow the RSS feed to link through to the item.
If the items are all displayed on a single page you may simply hard code the link to
point to a particular page.
<div class="info">
If the items are all displayed on a single page you may simply hard code the link to point to a particular page.
</div>
Take an example, we want to create an RSS feed of all the Students, a DataObject we
defined in the [fifth tutorial](/tutorials/5-dataobject-relationship-management).
Take an example, we want to create an RSS feed of all the `Players` objects in our site. We make sure the `AbsoluteLink`
method is defined and returns a string to the full website URL.
:::php
<?php
class Student extends DataObject {
class Player extends DataObject {
public function AbsoluteLink() {
// see tutorial 5, students are assigned a project, so the 'link'
// to view the student is based on their projects link.
return $this->Project()->AbsoluteLink();
// assumes players can be accessed at yoursite.com/players/2
return Controller::join_links(
Director::absoluteBaseUrl(),
'players',
$this->ID
);
}
}
Then update the Page_Controller class in mysite/code/Page.php to include an RSSFeed
for all the students as we've seen before.
Then in our controller, we add a new action which returns a the XML list of `Players`.
:::php
<?php
class Page_Controller extends ContentController {
private static $allowed_actions = array('students');
private static $allowed_actions = array(
'players'
);
public function init() {
parent::init();
RSSFeed::linkToFeed($this->Link("students"), "Students feed");
RSSFeed::linkToFeed($this->Link("players"), "Players");
}
public function students() {
public function players() {
$rss = new RSSFeed(
$list = $this->getStudents(),
$link = $this->Link("students"),
$title = "Students feed"
Player::get(),
$this->Link("players"),
"Players"
);
return $rss->outputToBrowser();
}
public function getStudents() {
return Student::get()->sort("Created", "DESC")->limit(10);
}
}
### Customizing the RSS Feed template
The default template used is framework/templates/RSSFeed.ss and includes
displaying titles and links to the content. If you have a particular need
for customizing the XML produced (say for additional meta data) use `setTemplate`.
The default template used for XML view is `framework/templates/RSSFeed.ss`. This template displays titles and links to
the object. To customize the XML produced use `setTemplate`.
Taking that last example, we would rewrite the students function to include a
unique template (write your own XML in themes/yourtheme/templates/Students.ss)
Say from that last example we want to include the Players Team in the XML feed we might create the following XML file.
**mysite/templates/PlayersRss.ss**
:::xml
<?xml version="1.0"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>$Title</title>
<link>$Link</link>
<atom:link href="$Link" rel="self" type="application/rss+xml" />
<description>$Description.XML</description>
<% loop $Entries %>
<item>
<title>$Title.XML</title>
<team>$Team.Title</team>
</item>
<% end_loop %>
</channel>
</rss>
`setTemplate` can then be used to tell RSSFeed to use that new template.
**mysite/code/Page.php**
:::php
public function students() {
public function players() {
$rss = new RSSFeed(
$list = $this->getStudents(),
$link = $this->Link("students"),
$title = "Students feed"
Player::get(),
$this->Link("players"),
"Players"
);
$rss->setTemplate('Students');
$rss->setTemplate('PlayersRss');
return $rss->outputToBrowser();
}
## External Sources
<div class="warning">
As we've added a new template (PlayersRss.ss) make sure you clear your SilverStripe cache.
</div>
`[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.
## Related
* [blog module](http://silverstripe.org/blog-module)
## API Documentation

View File

@ -0,0 +1,69 @@
title: Import CSV Data through a Controller
# Import CSV Data through a Controller
You can have more customized logic and interface feedback through a custom controller. Let's create a simple upload
form (which is used for `MyDataObject` instances). You can access it through
`http://yoursite.com/MyController/?flush=all`.
:::php
<?php
class MyController extends Controller {
private static $allowed_actions = array(
'Form'
);
protected $template = "BlankPage";
public function Link($action = null) {
return Controller::join_links('MyController', $action);
}
public function Form() {
$form = new Form(
$this,
'Form',
new FieldList(
new FileField('CsvFile', false)
),
new FieldList(
new FormAction('doUpload', 'Upload')
),
new RequiredFields()
);
return $form;
}
public function doUpload($data, $form) {
$loader = new CsvBulkLoader('MyDataObject');
$results = $loader->load($_FILES['CsvFile']['tmp_name']);
$messages = array();
if($results->CreatedCount()) {
$messages[] = sprintf('Imported %d items', $results->CreatedCount());
}
if($results->UpdatedCount()) {
$messages[] = sprintf('Updated %d items', $results->UpdatedCount());
}
if($results->DeletedCount()) {
$messages[] = sprintf('Deleted %d items', $results->DeletedCount());
}
if(!$messages) {
$messages[] = 'No changes';
}
$form->sessionMessage(implode(', ', $messages), 'good');
return $this->redirectBack();
}
}
<div class="alert" markdown="1">
This interface is not secured, consider using [api:Permission::check()] to limit the controller to users with certain
access rights.
</div>

View File

@ -0,0 +1,103 @@
title: A custom CSVBulkLoader instance
# How to: A custom CSVBulkLoader instance
A an implementation of a custom `CSVBulkLoader` loader. In this example. we're provided with a unique CSV file
containing a list of football players and the team they play for. The file we have is in the format like below.
"SpielerNummer", "Name", "Geburtsdatum", "Gruppe"
11, "John Doe", 1982-05-12,"FC Bayern"
12, "Jane Johnson", 1982-05-12,"FC Bayern"
13, "Jimmy Dole",,"Schalke 04"
This data needs to be imported into our application. For this, we have two `DataObjects` setup. `Player` contains
information about the individual player and a relation set up for managing the `Team`.
**mysite/code/Player.php**.
:::php
<?php
class Player extends DataObject {
private static $db = array(
'PlayerNumber' => 'Int',
'FirstName' => 'Text',
'LastName' => 'Text',
'Birthday' => 'Date'
);
private static $has_one = array(
'Team' => 'FootballTeam'
);
}
**mysite/code/FootballTeam.php**
:::php
<?php
class FootballTeam extends DataObject {
private static $db = array(
'Title' => 'Text'
);
private static $has_many = array(
'Players' => 'Player'
);
}
Now going back to look at the CSV, we can see that what we're provided with does not match what our data model looks
like, so we have to create a sub class of `CsvBulkLoader` to handle the unique file. Things we need to consider with
the custom importer are:
* Convert property names (e.g Number to PlayerNumber) through providing a `$columnMap`.
* Split a combined "Name" field into `FirstName` and `LastName` by calling `importFirstAndLastName` on the `Name`
column
* Prevent duplicate imports by a custom `$duplicateChecks` definition.
* Create a `Team` automatically based on the `Gruppe` column and a entry for `$relationCallbacks`
Our final import looks like this.
**mysite/code/PlayerCsvBulkLoader.php**
:::php
<?php
class PlayerCsvBulkLoader extends CsvBulkLoader {
public $columnMap = array(
'Number' => 'PlayerNumber',
'Name' => '->importFirstAndLastName',
'Geburtsdatum' => 'Birthday',
'Gruppe' => 'Team.Title',
);
public $duplicateChecks = array(
'SpielerNummer' => 'PlayerNumber'
);
public $relationCallbacks = array(
'Team.Title' => array(
'relationname' => 'Team',
'callback' => 'getTeamByTitle'
)
);
public static function importFirstAndLastName(&$obj, $val, $record) {
$parts = explode(' ', $val);
if(count($parts) != 2) return false;
$obj->FirstName = $parts[0];
$obj->LastName = $parts[1];
}
public static function getTeamByTitle(&$obj, $val, $record) {
return FootballTeam::get()->filter('Title', $val)->First();
}
}
## Related
* [api:CsvParser]
* [api:ModelAdmin]

View File

@ -0,0 +1,57 @@
title: Embed an RSS Feed
# Embed an RSS Feed
`[api:RestfulService]` can be used to easily embed an RSS feed from a site. In this How to we'll embed the latest
weather information from the Yahoo Weather API.
First, we write the code to query the API feed.
**mysite/code/Page.php**
:::php
public function getWellingtonWeather() {
$fetch = new RestfulService(
'https://query.yahooapis.com/v1/public/yql'
);
$fetch->setQueryString(array(
'q' => 'select * from weather.forecast where woeid in (select woeid from geo.places(1) where text="Wellington, NZ")'
));
// perform the query
$conn = $fetch->request();
// parse the XML body
$msgs = $fetch->getValues($conn->getBody(), "results");
// generate an object our templates can read
$output = new ArrayList();
if($msgs) {
foreach($msgs as $msg) {
$output->push(new ArrayData(array(
'Description' => Convert::xml2raw($msg->channel_item_description)
)));
}
}
return $output;
}
This will provide our `Page` template with a new `WellingtonWeather` variable (an [api:ArrayList]). Each item has a
single field `Description`.
**mysite/templates/Page.ss**
:::ss
<% if WellingtonWeather %>
<% loop WellingtonWeather %>
$Description
<% end_loop %>
<% end_if %>
## Related
* [RestfulService Documentation](../restfulservice)
* `[api:RestfulService]`

View File

@ -1,7 +1,5 @@
summary: Integrate other web services within your application or make your SilverStripe data available via REST.
summary: Integrate other web services within your application or make your SilverStripe data available.
introduction: Integrate other web services within your application or make your SilverStripe data available.
title: Integration and Web Services
[CHILDREN]
## How-to
[CHILDREN How_To]

View File

@ -5,20 +5,20 @@ summary: Provide your users with advanced search functionality.
## Searching for Pages (and Files)
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.
See [Tutorial: Site Search](/tutorials/site_search) for details.
## Searching for DataObjects
The `[api:SearchContext]` class provides a good base implementation that you can hook into your own controllers.
A working implementation of searchable DataObjects can be seen in the `[ModelAdmin](/reference/modeladmin)` class.
A working implementation of searchable DataObjects can be seen in the [ModelAdmin](../customising_the_cms/modeladmin) class.
[SearchContext](/reference/searchcontext) goes into more detail about setting up a default search form for `[api:DataObject]`s.
[SearchContext](/searchcontext) goes into more detail about setting up a default search form for `[api:DataObject]`s.
### Fulltext search on DataObjects
## Fulltext search on DataObjects
The `[api:MySQLDatabase]` class now defaults to creating tables using the InnoDB storage engine. As Fulltext search in MySQL
requires the MyISAM storage engine, any DataObject you wish to use with Fulltext search must be changed to use MyISAM storage
engine.
The `[api:MySQLDatabase]` class now defaults to creating tables using the InnoDB storage engine. As Fulltext search in
MySQL requires the MyISAM storage engine, any DataObject you wish to use with Fulltext search must be changed to use
MyISAM storage engine.
You can do so by adding this static variable to your class definition:
@ -29,9 +29,9 @@ You can do so by adding this static variable to your class definition:
## Searching for Documents
SilverStripe does not have a built-in method to search through file content (e.g. in PDF or DOC format).
You can either extract any textual file content into the `[File](api:File)->Content` property, or use a
dedicated search service like the [sphinx module](http://silverstripe.org/sphinx-module).
SilverStripe does not have a built-in method to search through file content (e.g. in PDF or DOC format). You can either
extract any textual file content into the `[File](api:File)->Content` property, or use a dedicated search service like
the [Full module](http://silverstripe.org/sphinx-module).
## Related

View File

@ -1,48 +1,41 @@
title: i18n
summary: Display templates and PHP code in different languages based on the preferences of your website users.
# i18n
## Introduction
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").
For translating any content managed through the CMS or stored in the database,
please use the "[translatable](http://github.com/silverstripe/silverstripe-translatable)" module.
For translating any content managed through the CMS or stored in the database, please use the
[translatable](http://github.com/silverstripe/silverstripe-translatable) module.
This page aims to describe the low-level functionality of the i18n-API. It targets developers who:
* are involved in creating templates in different languages
* want to build their own modules with i18n capabilities
* want to make their PHP-code (e.g. form labels) i18n-ready
Please note that this project scope currently **doesn't include full support for format conversion in dates or
currencies**. Check our [roadmap](http://open.silverstripe.com/roadmap).
This page aims to describe the low-level functionality of the i18n API. It targets developers who:
* Are involved in creating templates in different languages.
* Want to build their own modules with i18n capabilities.
* Want to make their PHP-code (e.g. form labels) i18n-ready
## Usage
### Enabling i18n
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
// mysite/_config.php
i18n::set_locale('de_DE'); // Setting the locale to German (Germany)
i18n::set_locale('ca_AD'); // Setting to Catalan (Andorra)
Once we set a locale, all the calls to the translator function will return strings according to the set locale value, if
these translations are available. See
[unicode.org](http://unicode.org/cldr/data/diff/supplemental/languages_and_territories.html) for a complete listing of
available locales.
these translations are available. See [unicode.org](http://unicode.org/cldr/data/diff/supplemental/languages_and_territories.html)
for a complete listing of available locales.
### Getting the locale
@ -60,7 +53,7 @@ To let browsers know which language they're displaying a document in, you can de
<html lang="$ContentLocale" xml:lang="$ContentLocale" xmlns="http://www.w3.org/1999/xhtml">
Setting the '<html>' attribute is the most commonly used technique. There are other ways to specify content languages
Setting the `<html>` attribute is the most commonly used technique. There are other ways to specify content languages
(meta tags, HTTP headers), explained in this [w3.org article](http://www.w3.org/International/tutorials/language-decl/).
You can also set the [script direction](http://www.w3.org/International/questions/qa-scripts),
@ -218,9 +211,10 @@ the PHP version of the function.
#### Caching in Template Files with locale switching
When caching a `<% loop %>` or `<% with %>` with `<%t params %>`. It is important to add the Locale to the cache key otherwise it won't pick up locale changes.
When caching a `<% loop %>` or `<% with %>` with `<%t params %>`. It is important to add the Locale to the cache key
otherwise it won't pick up locale changes.
::::ss
:::ss
<% cached 'MyIdentifier', $CurrentLocale %>
<% loop $Students %>
$Name
@ -229,15 +223,12 @@ When caching a `<% loop %>` or `<% with %>` with `<%t params %>`. It is importan
## Collecting text
To collect all the text in code and template files we have just to visit:
`http://localhost/dev/tasks/i18nTextCollectorTask`
To collect all the text in code and template files we have just to visit: `http://localhost/dev/tasks/i18nTextCollectorTask`
Text collector will then read the files, build the master string table for each module where it finds calls to the
underscore function, and tell you about the created files and any possible entity redeclaration.
If you want to run the text collector for just one module you can use the 'module' parameter:
`http://localhost/dev/tasks/i18nTextCollectorTask/?module=cms`
<div class="hint" markdown='1'>

View File

@ -21,19 +21,19 @@ All files, images and folders in the 'assets' directory are stored in the databa
If you have the CMS module installed, you can manage files, folders and images in the "Files" section of the CMS. Inside this section, you will see a list of files and folders like below:
![](_images/assets.png)
![](/_images/assets.png)
You can click on any file to edit it, or click on any folder to open it. To delete a file or a folder, simply click the red 'X' symbol next to it. If you click to open a folder, you can go back up one level by clicking the 'up' arrow above the folder name (highlighted below):
![](_images/assets_up.png)
![](/_images/assets_up.png)
Once you click to edit a file, you will see a form similar to the one below, in which you can edit the file's title, filename, owner, or even change which folder the file is located in:
![](_images/assets_editform.png)
![](/_images/assets_editform.png)
You may also notice the 'Sync files' button (highlighted below). This button allows CMS users to 'synchronise' the database (remember, all files/folders are stored as database records) with the filesystem. This is particularly useful if someone has uploaded or removed files/folders via FTP, for example.
![](_images/assets_sync.png)
![](/_images/assets_sync.png)
## Upload