mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Fixed references to deprecated APIs in docs
This commit is contained in:
parent
0236a3c03a
commit
19e087d226
@ -625,7 +625,7 @@ Note that its just necessary if SilverStripe is used in a language other than th
|
|||||||
The SS_Report::register() method is deprecated. You no longer need to explicitly register reports. The CMS now
|
The SS_Report::register() method is deprecated. You no longer need to explicitly register reports. The CMS now
|
||||||
automatically picks up and adds all Report classes to the list of reports in ReportAdmin. You can choose to exclude
|
automatically picks up and adds all Report classes to the list of reports in ReportAdmin. You can choose to exclude
|
||||||
certain reports by using the SS_Report::add_excluded_reports() method.
|
certain reports by using the SS_Report::add_excluded_reports() method.
|
||||||
fe
|
|
||||||
### Removed the ability use a SQLQuery object in a SS_Report
|
### Removed the ability use a SQLQuery object in a SS_Report
|
||||||
|
|
||||||
You can no longer create reports that using the deprecated DataObject->buildSQL and DataObject->extendedSQL
|
You can no longer create reports that using the deprecated DataObject->buildSQL and DataObject->extendedSQL
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
The [api:DataObject::$defaults] array allows you to specify simple static values to be the default value for when a
|
The [api:DataObject::$defaults] array allows you to specify simple static values to be the default value for when a
|
||||||
record is created, but in many situations default values needs to be dynamically calculated. In order to do this, the
|
record is created, but in many situations default values needs to be dynamically calculated. In order to do this, the
|
||||||
[api:DataObjectSet->populateDefaults()] method will need to be overloaded.
|
`[api:DataObject->populateDefaults()]` method will need to be overloaded.
|
||||||
|
|
||||||
This method is called whenever a new record is instantiated, and you must be sure to call the method on the parent
|
This method is called whenever a new record is instantiated, and you must be sure to call the method on the parent
|
||||||
object!
|
object!
|
||||||
@ -13,7 +13,6 @@ A simple example is to set a field to the current date and time:
|
|||||||
/**
|
/**
|
||||||
* Sets the Date field to the current date.
|
* Sets the Date field to the current date.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public function populateDefaults() {
|
public function populateDefaults() {
|
||||||
$this->Date = date('Y-m-d');
|
$this->Date = date('Y-m-d');
|
||||||
parent::populateDefaults();
|
parent::populateDefaults();
|
||||||
@ -27,7 +26,6 @@ methods. For example:
|
|||||||
* This method combines the Title of the parent object with the Title of this
|
* This method combines the Title of the parent object with the Title of this
|
||||||
* object in the FullTitle field.
|
* object in the FullTitle field.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public function populateDefaults() {
|
public function populateDefaults() {
|
||||||
if($parent = $this->Parent()) {
|
if($parent = $this->Parent()) {
|
||||||
$this->FullTitle = $parent->Title . ': ' . $this->Title;
|
$this->FullTitle = $parent->Title . ': ' . $this->Title;
|
||||||
|
@ -85,9 +85,8 @@ Create a new file called `zzz_admin/code/BookmarkedPageExtension.php` and insert
|
|||||||
:::php
|
:::php
|
||||||
<?php
|
<?php
|
||||||
class BookmarkedPageExtension extends DataExtension {
|
class BookmarkedPageExtension extends DataExtension {
|
||||||
public function extraStatics() {
|
static $db = array('IsBookmarked' => 'Boolean');
|
||||||
return array('db' => array('IsBookmarked' => 'Boolean'));
|
|
||||||
}
|
|
||||||
public function updateCMSFields(&$fields) {
|
public function updateCMSFields(&$fields) {
|
||||||
$fields->addFieldToTab('Root.Main',
|
$fields->addFieldToTab('Root.Main',
|
||||||
new CheckboxField('IsBookmarked', "Show in CMS bookmarks?")
|
new CheckboxField('IsBookmarked', "Show in CMS bookmarks?")
|
||||||
|
@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
## Introduction
|
## Introduction
|
||||||
|
|
||||||
|
<div class="warning" markdown="1">
|
||||||
|
This field is deprecated in favour of the new [GridField](/topics/grid-field) API.
|
||||||
|
</div>
|
||||||
|
|
||||||
Shows a group of DataObjects as a (readonly) tabular list (similiar to `[api:TableListField]`.)
|
Shows a group of DataObjects as a (readonly) tabular list (similiar to `[api:TableListField]`.)
|
||||||
|
|
||||||
You can specify limits and filters for the resultset by customizing query-settings (mostly the ID-field on the other
|
You can specify limits and filters for the resultset by customizing query-settings (mostly the ID-field on the other
|
||||||
@ -128,23 +132,4 @@ Most of the time, you need to override the following methods:
|
|||||||
|
|
||||||
* ComplexTableField->sourceItems() - querying
|
* ComplexTableField->sourceItems() - querying
|
||||||
* ComplexTableField->DetailForm() - form output
|
* ComplexTableField->DetailForm() - form output
|
||||||
* ComplexTableField_Popup->saveComplexTableField() - saving
|
* ComplexTableField_Popup->saveComplexTableField() - saving
|
||||||
|
|
||||||
### Examples
|
|
||||||
|
|
||||||
* `[api:AssetTableField]`
|
|
||||||
* `[api:MemberTableField]`
|
|
||||||
|
|
||||||
## API Documentation
|
|
||||||
|
|
||||||
`[api:ComplexTableField]`
|
|
||||||
|
|
||||||
## Todo
|
|
||||||
|
|
||||||
* 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 `[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/](http://www.activewidgets.com/grid/) and [http://openrico.org/rico/livegrid.page](http://openrico.org/rico/livegrid.page))
|
|
@ -45,56 +45,42 @@ For example above we want to override Member with a Custom Member so we would wr
|
|||||||
|
|
||||||
### Adding extra database fields
|
### Adding extra database fields
|
||||||
|
|
||||||
Extra database fields can be added with a extension by defining an **extraStatics()** method. These will be added to the table of the base object - the extension will actually edit the $db, $has_one, etc static variables on load.
|
Extra database fields can be added with a extension in the same manner as if they
|
||||||
|
were placed on the `DataObject` class they're applied to. These will be added to the table of the base object - the extension will actually edit the $db, $has_one, etc static variables on load.
|
||||||
|
|
||||||
The function should return a map where the keys are the names of the static variables to update:
|
The function should return a map where the keys are the names of the static variables to update:
|
||||||
|
|
||||||
:::php
|
:::php
|
||||||
class CustomMember extends DataExtension {
|
class CustomMember extends DataExtension {
|
||||||
|
static $db = array(
|
||||||
public function extraStatics() {
|
'AvatarURL' => 'Varchar',
|
||||||
return array(
|
);
|
||||||
'db' => array(
|
static $has_one = array(
|
||||||
'AvatarURL' => 'Varchar',
|
'RelatedMember' => 'Member',
|
||||||
),
|
);
|
||||||
'has_one' => array(
|
|
||||||
'RelatedMember' => 'Member',
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
*NOTE*
|
|
||||||
If you want to add has_one or db items to a particular class, then that class **must** have that static variable
|
|
||||||
explicitly defined, even if it's just a blank array. For example, the extension method above wouldn't work if you added
|
|
||||||
to a class that didn't have static $has_one explicitly declared on the object. This is because of PHP's crappy support
|
|
||||||
for statics.
|
|
||||||
|
|
||||||
|
|
||||||
### Modifying CMS Fields
|
### Modifying CMS Fields
|
||||||
|
|
||||||
The member class demonstrates an extension that allows you to update the default CMS fields for an object in a
|
The member class demonstrates an extension that allows you to update the default CMS fields for an
|
||||||
extension:
|
object in an extension:
|
||||||
|
|
||||||
:::php
|
:::php
|
||||||
public function getCMSFields() {
|
public function getCMSFields() {
|
||||||
...
|
// ...
|
||||||
$this->extend('updateCMSFields', $fields);
|
$this->extend('updateCMSFields', $fields);
|
||||||
return $fields;
|
return $fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
The $fields parameter is passed by reference, as it is an object.
|
The `$`fields parameter is passed by reference, as it is an object.
|
||||||
|
|
||||||
:::php
|
:::php
|
||||||
public function updateCMSFields(FieldList $fields) {
|
public function updateCMSFields(FieldList $fields) {
|
||||||
$fields->push(new TextField('Position', 'Position Title'));
|
$fields->push(new TextField('Position', 'Position Title'));
|
||||||
$fields->push(new UploadField('Image', 'Profile Image'));
|
$fields->push(new UploadField('Image', 'Profile Image'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Custom database generation
|
### Custom database generation
|
||||||
|
|
||||||
Some extensions are designed to transparently add more sophisticated data-collection capabilities to your data object.
|
Some extensions are designed to transparently add more sophisticated data-collection capabilities to your data object.
|
||||||
|
@ -31,7 +31,7 @@ by adding, removing or configuring fields.
|
|||||||
'IsActive' => 'Boolean'
|
'IsActive' => 'Boolean'
|
||||||
);
|
);
|
||||||
public function getCMSFields() {
|
public function getCMSFields() {
|
||||||
return new FieldSet(
|
return new FieldList(
|
||||||
new CheckboxField('IsActive')
|
new CheckboxField('IsActive')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -10,24 +10,6 @@ the viewer and/or perform processing steps.
|
|||||||
|
|
||||||
* Checking for an Ajax-Request: Use Director::is_ajax() instead of checking for $_REQUEST['ajax'].
|
* Checking for an Ajax-Request: Use Director::is_ajax() instead of checking for $_REQUEST['ajax'].
|
||||||
|
|
||||||
## 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.
|
|
||||||
* **Director::redirect("relative/url")**: If there is a slash in the URL, it's taken to be a normal URL. Relative URLs
|
|
||||||
will are assumed to be relative to the site-root; so Director::redirect("home/") will work no matter what the current
|
|
||||||
URL is.
|
|
||||||
* **Director::redirect("http://www.absoluteurl.com")**: Of course, you can pass redirect() absolute URL s too.
|
|
||||||
* **Director::redirectPerm("any-url")**: redirectPerm takes the same arguments as redirect, but it will send a 301
|
|
||||||
(permanent) instead of a 302 (temporary) header. It improves search rankings, so this should be used whenever the
|
|
||||||
following two conditions are true:
|
|
||||||
* Nothing happens server-side prior to the redirection
|
|
||||||
* The redirection will always occur
|
|
||||||
* **Director::redirectBack()**: This will return you to the previous page. There's no permanent version of
|
|
||||||
redirectBack().
|
|
||||||
|
|
||||||
|
|
||||||
## Request processing
|
## Request processing
|
||||||
|
|
||||||
|
@ -34,8 +34,6 @@ This is a highlevel overview of available `[api:apiFormField]` subclasses. An au
|
|||||||
* `[api:NumericField]`: Text input field with validation for numeric values.
|
* `[api:NumericField]`: Text input field with validation for numeric values.
|
||||||
* `[api:OptionsetField]`: Set of radio buttons designed to emulate a dropdown.
|
* `[api:OptionsetField]`: Set of radio buttons designed to emulate a dropdown.
|
||||||
* `[api:PhoneNumberField]`: Field for displaying phone numbers. It separates the number, the area code and optionally the country code and extension.
|
* `[api:PhoneNumberField]`: Field for displaying phone numbers. It separates the number, the area code and optionally the country code and extension.
|
||||||
* `[api:UniqueRestrictedTextField]`: Text field that automatically checks that the value entered is unique for the given set of fields in a given set of tables
|
|
||||||
|
|
||||||
* `[api:SelectionGroup]`: SelectionGroup represents a number of fields which are selectable by a radio button that appears at the beginning of each item.
|
* `[api:SelectionGroup]`: SelectionGroup represents a number of fields which are selectable by a radio button that appears at the beginning of each item.
|
||||||
* `[api:TimeField]`: Input field with time-specific, localized validation.
|
* `[api:TimeField]`: Input field with time-specific, localized validation.
|
||||||
|
|
||||||
|
@ -72,10 +72,10 @@ You can also create your own functions by extending the image class, for example
|
|||||||
public function Exif(){
|
public function Exif(){
|
||||||
//http://www.v-nessa.net/2010/08/02/using-php-to-extract-image-exif-data
|
//http://www.v-nessa.net/2010/08/02/using-php-to-extract-image-exif-data
|
||||||
$image = $this->AbsoluteURL;
|
$image = $this->AbsoluteURL;
|
||||||
$d=new DataObjectSet();
|
$d=new ArrayList();
|
||||||
$exif = exif_read_data($image, 0, true);
|
$exif = exif_read_data($image, 0, true);
|
||||||
foreach ($exif as $key => $section) {
|
foreach ($exif as $key => $section) {
|
||||||
$a=new DataObjectSet();
|
$a=new ArrayList();
|
||||||
foreach ($section as $name => $val)
|
foreach ($section as $name => $val)
|
||||||
$a->push(new ArrayData(array("Title"=>$name,"Content"=>$val)));
|
$a->push(new ArrayData(array("Title"=>$name,"Content"=>$val)));
|
||||||
$d->push(new ArrayData(array("Title"=>strtolower($key),"Content"=>$a)));
|
$d->push(new ArrayData(array("Title"=>strtolower($key),"Content"=>$a)));
|
||||||
|
@ -113,9 +113,12 @@ things, you should add appropriate `[api:Permission::checkMember()]` calls to th
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function extraStatics() {
|
// define additional properties
|
||||||
// Return an array containing keys 'db', 'has_one', 'many_many', 'belongs_many_many',
|
static $db = array();
|
||||||
}
|
static $has_one = array();
|
||||||
|
static $has_many = array();
|
||||||
|
static $many_many = array();
|
||||||
|
static $belongs_many_many = array();
|
||||||
|
|
||||||
public function somethingElse() {
|
public function somethingElse() {
|
||||||
// You can add any other methods you like, which you can call directly on the member object.
|
// You can add any other methods you like, which you can call directly on the member object.
|
||||||
|
@ -12,7 +12,7 @@ The default output of a `[api:SearchContext]` is either a `[api:SQLQuery]` objec
|
|||||||
In case you need multiple contexts, consider namespacing your request parameters by using `FieldList->namespace()` on
|
In case you need multiple contexts, consider namespacing your request parameters by using `FieldList->namespace()` on
|
||||||
the $fields constructor parameter.
|
the $fields constructor parameter.
|
||||||
|
|
||||||
`[api:SearchContext]` is mainly used by `[api:ModelAdmin]`, our generic data administration interface. Another
|
`[api:SearchContext]` is mainly used by `[ModelAdmin](/reference/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.
|
implementation can be found in generic frontend search forms through the [genericviews](http://silverstripe.org/generic-views-module) module.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
@ -187,6 +187,6 @@ See `[api:SearchFilter]` API Documentation
|
|||||||
|
|
||||||
## Related
|
## Related
|
||||||
|
|
||||||
* `[api:ModelAdmin]`
|
* [ModelAdmin](/reference/modeladmin)
|
||||||
* [RestfulServer module](https://github.com/silverstripe/silverstripe-restfulserver)
|
* [RestfulServer module](https://github.com/silverstripe/silverstripe-restfulserver)
|
||||||
* [Tutorial: Site Search](/tutorials/4-site-search)
|
* [Tutorial: Site Search](/tutorials/4-site-search)
|
||||||
|
@ -39,13 +39,9 @@ Create a mysite/code/CustomSiteConfig.php file.
|
|||||||
|
|
||||||
class CustomSiteConfig extends DataExtension {
|
class CustomSiteConfig extends DataExtension {
|
||||||
|
|
||||||
public function extraStatics() {
|
static $db = array(
|
||||||
return array(
|
'FooterContent' => 'HTMLText'
|
||||||
'db' => array(
|
);
|
||||||
'FooterContent' => 'HTMLText'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function updateCMSFields(FieldList $fields) {
|
public function updateCMSFields(FieldList $fields) {
|
||||||
$fields->addFieldToTab("Root.Main", new HTMLEditorField("FooterContent", "Footer Content"));
|
$fields->addFieldToTab("Root.Main", new HTMLEditorField("FooterContent", "Footer Content"));
|
||||||
|
@ -2,45 +2,40 @@
|
|||||||
|
|
||||||
## Introduction
|
## Introduction
|
||||||
|
|
||||||
An object representing a SQL query. It is easier to deal with object-wrappers than string-parsing a raw SQL-query. This
|
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 the SilverStripe ORM internally.
|
||||||
object is used by `[api:DataObject]`, though...
|
Dealing with low-level SQL is not encouraged, since the ORM provides
|
||||||
|
powerful abstraction APIs (see [datamodel](/topics/datamodel).
|
||||||
|
|
||||||
A word of caution: Dealing with low-level SQL is not encouraged in the SilverStripe [datamodel](/topics/datamodel) for various
|
You'll run the risk of breaking various assumptions the ORM and code based on it have:
|
||||||
reasons. You'll break the behaviour of:
|
|
||||||
|
|
||||||
* Custom getters/setters
|
* Custom getters/setters (object property can differ from database column)
|
||||||
* DataObject::onBeforeWrite/onBeforeDelete
|
* DataObject hooks like onBeforeWrite() and onBeforeDelete()
|
||||||
* Automatic casting
|
* Automatic casting
|
||||||
* Default-setting through object-model
|
* Default values set through objects
|
||||||
* `[api:DataObject]`
|
|
||||||
* Database abstraction
|
* 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,
|
||||||
[datamodel](/topics/datamodel).
|
but still maintain a connection to the ORM where possible.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
|
|
||||||
### SELECT
|
### SELECT
|
||||||
|
|
||||||
:::php
|
:::php
|
||||||
$sqlQuery = new SQLQuery();
|
$sqlQuery = new SQLQuery();
|
||||||
$sqlQuery->select = array(
|
$sqlQuery->setFrom('Player');
|
||||||
'Firstname AS Name',
|
$sqlQuery->selectField('FieldName', 'Name');
|
||||||
'YEAR(Birthday) AS BirthYear'
|
$sqlQuery->selectField('YEAR("Birthday")', 'BirthYear');
|
||||||
|
$sqlQuery->addLeftJoin(
|
||||||
|
'Team',
|
||||||
|
'"Player"."TeamID" = "Team"."ID"'
|
||||||
);
|
);
|
||||||
$sqlQuery->from = "
|
$sqlQuery->addWhere('YEAR("Birthday") = 1982');
|
||||||
Player
|
// $sqlQuery->setOrderBy(...);
|
||||||
LEFT JOIN Team ON Player.TeamID = Team.ID
|
// $sqlQuery->setGroupBy(...);
|
||||||
";
|
// $sqlQuery->setHaving(...);
|
||||||
$sqlQuery->where = "
|
// $sqlQuery->setLimit(...);
|
||||||
YEAR(Birthday) = 1982
|
// $sqlQuery->setDistinct(true);
|
||||||
";
|
|
||||||
// $sqlQuery->orderby = "";
|
|
||||||
// $sqlQuery->groupby = "";
|
|
||||||
// $sqlQuery->having = "";
|
|
||||||
// $sqlQuery->limit = "";
|
|
||||||
// $sqlQuery->distinct = true;
|
|
||||||
|
|
||||||
// get the raw SQL
|
// get the raw SQL
|
||||||
$rawSQL = $sqlQuery->sql();
|
$rawSQL = $sqlQuery->sql();
|
||||||
@ -53,7 +48,7 @@ We'll explain some ways to use *SELECT* with the full power of SQL, but still ma
|
|||||||
|
|
||||||
:::php
|
:::php
|
||||||
// ...
|
// ...
|
||||||
$sqlQuery->delete = true;
|
$sqlQuery->setDelete(true);
|
||||||
|
|
||||||
|
|
||||||
### INSERT/UPDATE
|
### INSERT/UPDATE
|
||||||
@ -80,10 +75,10 @@ Raw SQL is handy for performance-optimized calls.
|
|||||||
:::php
|
:::php
|
||||||
class Team extends DataObject {
|
class Team extends DataObject {
|
||||||
public function getPlayerCount() {
|
public function getPlayerCount() {
|
||||||
$sqlQuery = new SQLQuery(
|
$sqlQuery = new SQLQuery();
|
||||||
"COUNT(Player.ID)",
|
$sqlQuery->setFrom('Player');
|
||||||
"Team LEFT JOIN Player ON Team.ID = Player.TeamID"
|
$sqlQuery->addSelect('COUNT("Player"."ID")');
|
||||||
);
|
$sqlQuery->addLeftJoin('Team', '"Team"."ID" = "Player"."TeamID"');
|
||||||
return $sqlQuery->execute()->value();
|
return $sqlQuery->execute()->value();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,10 +94,9 @@ Way faster than dealing with `[api:DataObject]`s, but watch out for premature op
|
|||||||
Useful for creating dropdowns.
|
Useful for creating dropdowns.
|
||||||
|
|
||||||
:::php
|
:::php
|
||||||
$sqlQuery = new SQLQuery(
|
$sqlQuery = new SQLQuery();
|
||||||
array('YEAR(Birthdate)', 'Birthdate'),
|
$sqlQuery->setFrom('Player');
|
||||||
'Player'
|
$sqlQuery->selectField('YEAR("Birthdate")', 'Birthdate');
|
||||||
);
|
|
||||||
$map = $sqlQuery->execute()->map();
|
$map = $sqlQuery->execute()->map();
|
||||||
$field = new DropdownField('Birthdates', 'Birthdates', $map);
|
$field = new DropdownField('Birthdates', 'Birthdates', $map);
|
||||||
|
|
||||||
@ -112,8 +106,11 @@ Useful for creating dropdowns.
|
|||||||
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
|
:::php
|
||||||
DB::query("UPDATE Player SET Status='Active'");
|
DB::query('UPDATE "Player" SET "Status"=\'Active\'');
|
||||||
|
|
||||||
|
<<<<<<< Updated upstream
|
||||||
|
### Transforming a result to `[api:ArrayList]`
|
||||||
|
=======
|
||||||
One example for using a raw DB::query is when you are wanting to order twice in the database:
|
One example for using a raw DB::query is when you are wanting to order twice in the database:
|
||||||
|
|
||||||
:::php
|
:::php
|
||||||
@ -130,46 +127,41 @@ You can gain some ground on the datamodel-side when involving the selected class
|
|||||||
need to call *buildSQL* from a specific object-instance, a *singleton* will do just fine.
|
need to call *buildSQL* from a specific object-instance, a *singleton* will do just fine.
|
||||||
|
|
||||||
:::php
|
:::php
|
||||||
$sqlQuery = singleton('Player')->buildSQL(
|
$sqlQuery = singleton('Player')->buildSQL('YEAR("Birthdate") = 1982');
|
||||||
'YEAR(Birthdate) = 1982'
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
This form of building a query has the following advantages:
|
This form of building a query has the following advantages:
|
||||||
|
|
||||||
* Respects DataObject::$default_sort
|
* Respects DataObject::$default_sort
|
||||||
* Automatically LEFT JOIN on all base-tables (see [database-structure](database-structure))
|
* Automatically `LEFT JOIN` on all base-tables (see [database-structure](database-structure))
|
||||||
* Selection of *ID*, *ClassName*, *RecordClassName*, which are necessary to use *buildDataObjectSet* later on
|
* Selection of *ID*, *ClassName*, *RecordClassName*, which are necessary to use *buildDataObjectSet* later on
|
||||||
* Filtering records for correct *ClassName*
|
* Filtering records for correct *ClassName*
|
||||||
|
|
||||||
### Transforming a result to `[api:DataObjectSet]`
|
### Transforming a result to `[api:DataObjectSet]`
|
||||||
|
>>>>>>> Stashed changes
|
||||||
|
|
||||||
This is a commonly used technique inside SilverStripe: Use raw SQL, but transfer the resulting rows back into
|
This is a commonly used technique inside SilverStripe: Use raw SQL, but transfer the resulting rows back into
|
||||||
`[api:DataObject]`s.
|
`[api:DataObject]`s.
|
||||||
|
|
||||||
:::php
|
:::php
|
||||||
$sqlQuery = new SQLQuery();
|
$sqlQuery = new SQLQuery();
|
||||||
$sqlQuery->select = array(
|
$sqlQuery->setSelect(array(
|
||||||
'Firstname AS Name',
|
'"Firstname" AS "Name"',
|
||||||
'YEAR(Birthday) AS BirthYear',
|
'YEAR("Birthday") AS "BirthYear"',
|
||||||
// IMPORTANT: Needs to be set after other selects to avoid overlays
|
// IMPORTANT: Needs to be set after other selects to avoid overlays
|
||||||
'Player.ClassName AS ClassName',
|
'"Player"."ClassName" AS "ClassName"',
|
||||||
'Player.ClassName AS RecordClassName',
|
'"Player"."ClassName" AS "RecordClassName"',
|
||||||
'Player.ID AS ID'
|
'"Player"."ID" AS "ID"'
|
||||||
);
|
));
|
||||||
$sqlQuery->from = array(
|
$sqlQuery->setFrom('Player');
|
||||||
"Player",
|
$sqlQuery->addLeftJoin('Team', '"Player"."TeamID" = "Team"."ID"');
|
||||||
"LEFT JOIN Team ON Player.TeamID = Team.ID"
|
$sqlQuery->addWhere("YEAR("Player"."Birthday") = 1982");
|
||||||
);
|
|
||||||
$sqlQuery->where = array(
|
|
||||||
"YEAR(Player.Birthday) = 1982"
|
|
||||||
);
|
|
||||||
|
|
||||||
$result = $sqlQuery->execute();
|
$result = $sqlQuery->execute();
|
||||||
var_dump($result->first()); // array
|
var_dump($result->first()); // array
|
||||||
|
|
||||||
// let Silverstripe work the magic
|
// let Silverstripe work the magic
|
||||||
$myDataObjectSet = singleton('Player')->buildDataObjectSet($result);
|
$myList = singleton('Player')->buildDataObjectSet($result);
|
||||||
var_dump($myDataObjectSet->First()); // DataObject
|
var_dump($myDataObjectSet->First()); // DataObject
|
||||||
|
|
||||||
// this is where it gets tricky
|
// this is where it gets tricky
|
||||||
|
@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
## Introduction
|
## Introduction
|
||||||
|
|
||||||
|
<div class="warning" markdown="1">
|
||||||
|
This field is deprecated in favour of the new [GridField](/topics/grid-field) API.
|
||||||
|
</div>
|
||||||
|
|
||||||
Form field that embeds a list of `[api:DataObject]`s into a form, such as a member list or a file list.
|
Form field that embeds a list of `[api:DataObject]`s into a form, such as a member list or a file list.
|
||||||
Provides customizeable columns, record-deletion by ajax, paging, sorting, CSV-export, printing, input by
|
Provides customizeable columns, record-deletion by ajax, paging, sorting, CSV-export, printing, input by
|
||||||
`[api:DataObject]` or raw SQL.
|
`[api:DataObject]` or raw SQL.
|
||||||
|
@ -4,7 +4,7 @@ These are the main changes to the SiverStripe 3 template language.
|
|||||||
|
|
||||||
## Control blocks: Loops vs. Scope
|
## Control blocks: Loops vs. Scope
|
||||||
|
|
||||||
The `<% control var %>...<% end_control %>` in SilverStripe prior to version 3 has two different meanings. Firstly, if the control variable is a collection (e.g. DataObjectSet), then `<% control %>` iterates over that set. If it's a non-iteratable object, however, `<% control %>` introduces a new scope, which is used to render the inner template code. This dual-use is confusing to some people, and doesn't allow a collection of objects to be used as a scope.
|
The `<% control var %>...<% end_control %>` in SilverStripe prior to version 3 has two different meanings. Firstly, if the control variable is a collection (e.g. DataList), then `<% control %>` iterates over that set. If it's a non-iteratable object, however, `<% control %>` introduces a new scope, which is used to render the inner template code. This dual-use is confusing to some people, and doesn't allow a collection of objects to be used as a scope.
|
||||||
|
|
||||||
In SilverStripe 3, the first usage (iteration) is replaced by `<% loop var %>`. The second usage (scoping) is replaced by `<% with var %>`
|
In SilverStripe 3, the first usage (iteration) is replaced by `<% loop var %>`. The second usage (scoping) is replaced by `<% with var %>`
|
||||||
|
|
||||||
|
@ -49,20 +49,10 @@ Append the option and corresponding value to your URL in your browser's address
|
|||||||
|
|
||||||
| URL Variable | | Values | | Description |
|
| URL Variable | | Values | | Description |
|
||||||
| ------------ | | ------ | | ----------- |
|
| ------------ | | ------ | | ----------- |
|
||||||
|
| debug_memory | | 1 | | Output the number of bytes of memory used for this
|
||||||
| debug_memory | | 1 | | Output the number of bytes of memory used for this request |
|
| 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** |
|
| 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 |
|
|
||||||
|
|
||||||
## Misc
|
|
||||||
|
|
||||||
| URL Variable | | Values | | Description |
|
|
||||||
| ------------ | | ------ | | ----------- |
|
|
||||||
| forceFormat | | xhtml,html | | Force the content negotiator to deliver HTML or XHTML is allowed |
|
|
||||||
| showspam | | 1 | | Show comments marked as spam when viewing Comments on a Page (Saving spam to the database must be enabled) |
|
|
||||||
| ajax | | 1 | | Force request to process as AJAX request, useful for debugging from a browser |
|
|
||||||
| force_ajax | | 1 | | Similar to **ajax** |
|
|
||||||
|
|
||||||
## Security Redirects
|
## Security Redirects
|
||||||
|
|
||||||
|
@ -36,9 +36,6 @@ incomplete - please add to it** *Try to keep it in alphabetical order too! :)*
|
|||||||
| Authenticator::register_authenticator($authenticator);| | Enable an authentication method (for more details see [security](/topics/security)). |
|
| Authenticator::register_authenticator($authenticator);| | Enable an authentication method (for more details see [security](/topics/security)). |
|
||||||
| Authenticator::set_default_authenticator($authenticator); | | Modify tab-order on login-form.|
|
| Authenticator::set_default_authenticator($authenticator); | | Modify tab-order on login-form.|
|
||||||
| BBCodeParser::disable_autolink_urls(); | | Disables plain hyperlinks from being turned into links when bbcode is parsed. |
|
| BBCodeParser::disable_autolink_urls(); | | Disables plain hyperlinks from being turned into links when bbcode is parsed. |
|
||||||
| BlogEntry::allow_wysiwyg_editing(); | | Enable rich text editing for blog posts. |
|
|
||||||
| ContentNegotiator::set_encoding(string $encoding) | | The encoding charset to use - UTF-8 by default |
|
|
||||||
| ContentNegotiator::disable() | | Disables the negotiation of content type -usually used to stop it from rewriting the DOCTYPE of the document
|
|
||||||
| DataObject::$create_table_options['MySQLDatabase'] = 'ENGINE=MyISAM';| | Set the default database engine to MyISAM (versions 2.4 and below already default to MyISAM) |
|
| DataObject::$create_table_options['MySQLDatabase'] = 'ENGINE=MyISAM';| | Set the default database engine to MyISAM (versions 2.4 and below already default to MyISAM) |
|
||||||
| Debug::send_errors_to(string $email) | | Send live errors on your site to this address (site has to be in 'live' mode using Director::set_environment_type(live) for this to occur |
|
| Debug::send_errors_to(string $email) | | Send live errors on your site to this address (site has to be in 'live' mode using Director::set_environment_type(live) for this to occur |
|
||||||
| Director::set_environment_type(string dev,test,live) | | Sets the environment type (e.g. dev site will show errors, live site hides them and displays a 500 error instead) |
|
| Director::set_environment_type(string dev,test,live) | | Sets the environment type (e.g. dev site will show errors, live site hides them and displays a 500 error instead) |
|
||||||
@ -48,8 +45,6 @@ incomplete - please add to it** *Try to keep it in alphabetical order too! :)*
|
|||||||
| Email::send_all_emails_to(string $email) | | Sends all emails to this address. Useful for debugging your email sending functions |
|
| Email::send_all_emails_to(string $email) | | Sends all emails to this address. Useful for debugging your email sending functions |
|
||||||
| Email::cc_all_emails_to(string $email) | | Useful for CC'ing all emails to someone checking correspondence |
|
| Email::cc_all_emails_to(string $email) | | Useful for CC'ing all emails to someone checking correspondence |
|
||||||
| Email::bcc_all_emails_to(string $email) | | BCC all emails to this address, similar to CC'ing emails (above) |
|
| Email::bcc_all_emails_to(string $email) | | BCC all emails to this address, similar to CC'ing emails (above) |
|
||||||
| MathSpamProtection::setEnabled() | | Adds a math spam question to all page comment forms |
|
|
||||||
| PageComment::enableModeration(); | | Enables comment moderation |
|
|
||||||
| Requirements::set_suffix_requirements(false); | | Disable appending the current date to included files |
|
| Requirements::set_suffix_requirements(false); | | Disable appending the current date to included files |
|
||||||
| Security::encrypt_passwords($encrypt_passwords); | | Specify if you want store your passwords in clear text or encrypted (for more details see [security](/topics/security)) |
|
| Security::encrypt_passwords($encrypt_passwords); | | Specify if you want store your passwords in clear text or encrypted (for more details see [security](/topics/security)) |
|
||||||
| Security::set_password_encryption_algorithm($algorithm, $use_salt);| | If you choose to encrypt your passwords, you can choose which algorithm is used to and if a salt should be used to increase the security level even more (for more details see [security](/topics/security)). |
|
| Security::set_password_encryption_algorithm($algorithm, $use_salt);| | If you choose to encrypt your passwords, you can choose which algorithm is used to and if a salt should be used to increase the security level even more (for more details see [security](/topics/security)). |
|
||||||
|
@ -88,6 +88,20 @@ after it. If the URLSegment is **order** then `/order/tag/34` and `/order/tag/a
|
|||||||
|
|
||||||
You can use the `debug_request=1` switch from the [urlvariabletools](/reference/urlvariabletools) to see these in action.
|
You can use the `debug_request=1` switch from the [urlvariabletools](/reference/urlvariabletools) to see these in action.
|
||||||
|
|
||||||
|
## Redirection
|
||||||
|
|
||||||
|
Controllers facilitate HTTP redirection.
|
||||||
|
Note: These methods have been formerly located on the `[api:Director]` class.
|
||||||
|
|
||||||
|
* `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.
|
||||||
|
* `redirect("relative/url")`: If there is a slash in the URL, it's taken to be a normal URL. Relative URLs
|
||||||
|
will are assumed to be relative to the site-root.
|
||||||
|
* `redirect("http://www.absoluteurl.com")`: Of course, you can pass `redirect()` absolute URLs too.
|
||||||
|
* `redirectBack()`: This will return you to the previous page.
|
||||||
|
|
||||||
|
The `redirect()` method takes an optional HTTP status code,
|
||||||
|
either `301` for permanent redirects, or `302` for temporary redirects (default).
|
||||||
|
|
||||||
## API Documentation
|
## API Documentation
|
||||||
|
|
||||||
`[api:Controller]`
|
`[api:Controller]`
|
||||||
|
@ -10,7 +10,7 @@ TODO Screenshot of admin interface
|
|||||||
|
|
||||||
## Upload
|
## Upload
|
||||||
|
|
||||||
TODO Link to Upload and FileIframeField classes
|
TODO Link to UploadField and FileField classes
|
||||||
|
|
||||||
## Image Resizing
|
## Image Resizing
|
||||||
|
|
||||||
|
@ -60,78 +60,42 @@ The real difference, however, is that you can then define your controller method
|
|||||||
|
|
||||||
## Form Field Types
|
## Form Field Types
|
||||||
|
|
||||||
There are many classes extending `[api:FormField]`. Some examples:
|
There are many classes extending `[api:FormField]`,
|
||||||
|
there's a full overview at [form-field-types](/reference/form-field-types)
|
||||||
* `[api:TextField]`
|
|
||||||
* `[api:EmailField]`
|
|
||||||
* `[api:NumericField]`
|
|
||||||
* `[api:DateField]`
|
|
||||||
* `[api:CheckboxField]`
|
|
||||||
* `[api:DropdownField]`
|
|
||||||
* `[api:OptionsetField]`
|
|
||||||
* `[api:CheckboxSetField]`
|
|
||||||
|
|
||||||
Full overview at [form-field-types](/reference/form-field-types)
|
|
||||||
|
|
||||||
|
|
||||||
### Using Form Fields
|
### 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
|
To get these fields automatically rendered into a form element,
|
||||||
|
all you need to do is create a new instance of the
|
||||||
class, and add it to the fieldlist of the form.
|
class, and add it to the fieldlist of the form.
|
||||||
|
|
||||||
:::php
|
:::php
|
||||||
$form = new Form(
|
$form = new Form(
|
||||||
$controller = $this,
|
$this, // controller
|
||||||
$name = "SignupForm",
|
"SignupForm", // form name
|
||||||
$fields = new FieldList(
|
new FieldList( // fields
|
||||||
new TextField(
|
TextField::create("FirstName")
|
||||||
$name = "FirstName",
|
->setTitle('First name')
|
||||||
$title = "First name"
|
TextField::create("Surname")
|
||||||
),
|
->setTitle('Last name')
|
||||||
new TextField("Surname"),
|
->setMaxLength(50),
|
||||||
new EmailField("Email", "Email address"),
|
EmailField::create("Email")
|
||||||
),
|
->setTitle("Email address")
|
||||||
$actions = new FieldList(
|
->setAttribute('type', 'email')
|
||||||
// List the action buttons here
|
),
|
||||||
new FormAction("signup", "Sign up")
|
new FieldList( // actions
|
||||||
),
|
FormAction::create("signup")->setTitle("Sign up")
|
||||||
$requiredFields = new RequiredFields(
|
),
|
||||||
// List the required fields here: "Email", "FirstName"
|
new RequiredFields( // validation
|
||||||
)
|
"Email", "FirstName"
|
||||||
);
|
)
|
||||||
|
|
||||||
|
|
||||||
You'll note some of the fields are optional.
|
|
||||||
|
|
||||||
Implementing the more complex fields requires extra arguments.
|
|
||||||
|
|
||||||
:::php
|
|
||||||
$form = new Form(
|
|
||||||
$controller = $this,
|
|
||||||
$name = "SignupForm",
|
|
||||||
$fields = new FieldList(
|
|
||||||
// List the your fields here
|
|
||||||
new TextField(
|
|
||||||
$name = "FirstName",
|
|
||||||
$title = "First name"
|
|
||||||
),
|
|
||||||
new TextField("Surname"),
|
|
||||||
new EmailField("Email", "Email address")
|
|
||||||
new DropdownField(
|
|
||||||
$name = "Country",
|
|
||||||
$title = "Country (if outside nz)",
|
|
||||||
$source = Geoip::getCountryDropDown(),
|
|
||||||
$value = Geoip::visitor_country()
|
|
||||||
)
|
|
||||||
), new FieldList(
|
|
||||||
// List the action buttons here
|
|
||||||
new FormAction("signup", "Sign up")
|
|
||||||
|
|
||||||
), new RequiredFields(
|
|
||||||
// List the required fields here: "Email", "FirstName"
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
You'll notice that we've used a new notation for creating form fields,
|
||||||
|
using `create()` instead of the `new` operator. These are functionally equivalent,
|
||||||
|
but allows PHP to chain operations like `setTitle()` without assigning
|
||||||
|
the field instance to a temporary variable.
|
||||||
|
|
||||||
## Readonly
|
## Readonly
|
||||||
|
|
||||||
@ -144,7 +108,7 @@ Readonly on a Form
|
|||||||
Readonly on a FieldList
|
Readonly on a FieldList
|
||||||
|
|
||||||
:::php
|
:::php
|
||||||
$myFieldSet->makeReadonly();
|
$myFieldList->makeReadonly();
|
||||||
|
|
||||||
|
|
||||||
Readonly on a FormField
|
Readonly on a FormField
|
||||||
@ -167,29 +131,29 @@ First of all, you need to create your form on it's own class, that way you can d
|
|||||||
:::php
|
:::php
|
||||||
class MyForm extends Form {
|
class MyForm extends Form {
|
||||||
|
|
||||||
public function __construct($controller, $name) {
|
public function __construct($controller, $name) {
|
||||||
$fields = new FieldList(
|
$fields = new FieldList(
|
||||||
new TextField('FirstName', 'First name'),
|
new TextField('FirstName', 'First name'),
|
||||||
new EmailField('Email', 'Email address')
|
new EmailField('Email', 'Email address')
|
||||||
);
|
);
|
||||||
|
|
||||||
$actions = new FieldList(
|
$actions = new FieldList(
|
||||||
new FormAction('submit', 'Submit')
|
new FormAction('submit', 'Submit')
|
||||||
);
|
);
|
||||||
|
|
||||||
parent::__construct($controller, $name, $fields, $actions);
|
parent::__construct($controller, $name, $fields, $actions);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function forTemplate() {
|
public function forTemplate() {
|
||||||
return $this->renderWith(array(
|
return $this->renderWith(array(
|
||||||
$this->class,
|
$this->class,
|
||||||
'Form'
|
'Form'
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function submit($data, $form) {
|
public function submit($data, $form) {
|
||||||
// do stuff here
|
// do stuff here
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,31 +165,31 @@ basic customisation:
|
|||||||
|
|
||||||
:::ss
|
:::ss
|
||||||
<form $FormAttributes>
|
<form $FormAttributes>
|
||||||
<% if Message %>
|
<% if Message %>
|
||||||
<p id="{$FormName}_error" class="message $MessageType">$Message</p>
|
<p id="{$FormName}_error" class="message $MessageType">$Message</p>
|
||||||
<% else %>
|
<% else %>
|
||||||
<p id="{$FormName}_error" class="message $MessageType" style="display: none"></p>
|
<p id="{$FormName}_error" class="message $MessageType" style="display: none"></p>
|
||||||
<% end_if %>
|
<% end_if %>
|
||||||
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<div id="FirstName" class="field text">
|
<div id="FirstName" class="field text">
|
||||||
<label class="left" for="{$FormName}_FirstName">First name</label>
|
<label class="left" for="{$FormName}_FirstName">First name</label>
|
||||||
$dataFieldByName(FirstName)
|
$dataFieldByName(FirstName)
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="Email" class="field email">
|
<div id="Email" class="field email">
|
||||||
<label class="left" for="{$FormName}_Email">Email</label>
|
<label class="left" for="{$FormName}_Email">Email</label>
|
||||||
$dataFieldByName(Email)
|
$dataFieldByName(Email)
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
$dataFieldByName(SecurityID)
|
$dataFieldByName(SecurityID)
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<% if Actions %>
|
<% if Actions %>
|
||||||
<div class="Actions">
|
<div class="Actions">
|
||||||
<% loop Actions %>$Field<% end_loop %>
|
<% loop Actions %>$Field<% end_loop %>
|
||||||
</div>
|
</div>
|
||||||
<% end_if %>
|
<% end_if %>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
`$dataFieldByName(FirstName)` will return the form control contents of `Field()` for the particular field object, in
|
`$dataFieldByName(FirstName)` will return the form control contents of `Field()` for the particular field object, in
|
||||||
|
@ -14,7 +14,7 @@ This example might come from a Controller designed to manage the members of a gr
|
|||||||
*/
|
*/
|
||||||
public function MemberForm() {
|
public function MemberForm() {
|
||||||
$field = new GridField("Members", "Members of this group", $this->group->Members());
|
$field = new GridField("Members", "Members of this group", $this->group->Members());
|
||||||
return new Form("MemberForm", $this, new FieldSet($field), new FieldSet());
|
return new Form("MemberForm", $this, new FieldList($field), new FieldList());
|
||||||
}
|
}
|
||||||
|
|
||||||
Note that the only way to specify the data that is listed in a grid field is with `SS_List` argument. If you want to customise the data displayed, you can do so by customising this object.
|
Note that the only way to specify the data that is listed in a grid field is with `SS_List` argument. If you want to customise the data displayed, you can do so by customising this object.
|
||||||
|
@ -70,9 +70,9 @@ to write your own logic for any frontend output.
|
|||||||
i18n::set_date_format('dd.MM.YYYY');
|
i18n::set_date_format('dd.MM.YYYY');
|
||||||
i18n::set_time_format('HH:mm');
|
i18n::set_time_format('HH:mm');
|
||||||
|
|
||||||
Most localization routines in SilverStripe use the [http://framework.zend.com/manual/en/zend.date.html](Zend_Date API).
|
Most localization routines in SilverStripe use the [Zend_Date API](http://framework.zend.com/manual/en/zend.date.html).
|
||||||
This means all formats are defined in
|
This means all formats are defined in
|
||||||
[http://framework.zend.com/manual/en/zend.date.constants.html#zend.date.constants.selfdefinedformats](ISO date format),
|
[ISO date format](http://framework.zend.com/manual/en/zend.date.constants.html#zend.date.constants.selfdefinedformats),
|
||||||
not PHP's built-in [date()](http://nz.php.net/manual/en/function.date.php).
|
not PHP's built-in [date()](http://nz.php.net/manual/en/function.date.php).
|
||||||
|
|
||||||
### i18n in URLs
|
### i18n in URLs
|
||||||
@ -227,22 +227,20 @@ which supports different translation adapters, dealing with different storage fo
|
|||||||
|
|
||||||
By default, SilverStripe 3.x uses a YAML format (through the [Zend_Translate_RailsYAML adapter](https://github.com/chillu/zend_translate_railsyaml)).
|
By default, SilverStripe 3.x uses a YAML format (through the [Zend_Translate_RailsYAML adapter](https://github.com/chillu/zend_translate_railsyaml)).
|
||||||
|
|
||||||
Example: sapphire/lang/en.yml (extract)
|
Example: framework/lang/en.yml (extract)
|
||||||
|
|
||||||
:::yml
|
|
||||||
en:
|
en:
|
||||||
ImageUploader:
|
ImageUploader:
|
||||||
Attach: 'Attach %s'
|
Attach: 'Attach %s'
|
||||||
FileIFrameField:
|
UploadField:
|
||||||
NOTEADDFILES: 'You can add files once you have saved for the first time.'
|
NOTEADDFILES: 'You can add files once you have saved for the first time.'
|
||||||
|
|
||||||
Translation table: sapphire/lang/de.yml (extract)
|
Translation table: framework/lang/de.yml (extract)
|
||||||
|
|
||||||
:::yml
|
|
||||||
de:
|
de:
|
||||||
ImageUploader:
|
ImageUploader:
|
||||||
ATTACH: '%s anhängen'
|
ATTACH: '%s anhängen'
|
||||||
FileIframeField:
|
UploadField:
|
||||||
NOTEADDFILES: 'Sie können Dateien hinzufügen sobald Sie das erste mal gespeichert haben'
|
NOTEADDFILES: 'Sie können Dateien hinzufügen sobald Sie das erste mal gespeichert haben'
|
||||||
|
|
||||||
Note that translations are cached across requests.
|
Note that translations are cached across requests.
|
||||||
@ -262,7 +260,7 @@ Example: framework/lang/en_US.php (extract)
|
|||||||
'Attach %s',
|
'Attach %s',
|
||||||
'Attach image/file'
|
'Attach image/file'
|
||||||
);
|
);
|
||||||
$lang['en_US']['FileIFrameField']['NOTEADDFILES'] = 'You can add files once you have saved for the first time.';
|
$lang['en_US']['UploadField']['NOTEADDFILES'] = 'You can add files once you have saved for the first time.';
|
||||||
// ...
|
// ...
|
||||||
|
|
||||||
|
|
||||||
@ -270,7 +268,7 @@ Translation table: framework/lang/de_DE.php (extract)
|
|||||||
|
|
||||||
:::php
|
:::php
|
||||||
$lang['de_DE']['ImageUploader']['ATTACH'] = '%s anhängen';
|
$lang['de_DE']['ImageUploader']['ATTACH'] = '%s anhängen';
|
||||||
$lang['de_DE']['FileIframeField']['NOTEADDFILES'] = 'Sie können Dateien hinzufügen sobald Sie das erste mal gespeichert haben';
|
$lang['de_DE']['UploadField']['NOTEADDFILES'] = 'Sie können Dateien hinzufügen sobald Sie das erste mal gespeichert haben';
|
||||||
|
|
||||||
In order to enable usage of PHP language definitions in 3.x, you need to register a legacy adapter
|
In order to enable usage of PHP language definitions in 3.x, you need to register a legacy adapter
|
||||||
in your `mysite/_config.php`:
|
in your `mysite/_config.php`:
|
||||||
|
@ -52,14 +52,11 @@ especially useful if you know how long your source data needs to be.
|
|||||||
|
|
||||||
:::php
|
:::php
|
||||||
class StaffPage extends Page {
|
class StaffPage extends Page {
|
||||||
|
|
||||||
static $db = array(
|
static $db = array(
|
||||||
'Author' => 'Varchar(50)'
|
'Author' => 'Varchar(50)'
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
class StaffPage_Controller extends Page_Controller {
|
class StaffPage_Controller extends Page_Controller {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -68,7 +65,8 @@ model works.
|
|||||||
|
|
||||||
## Adding Form Fields and Tabs
|
## Adding Form Fields and Tabs
|
||||||
|
|
||||||
See [form](/topics/forms) and [tutorial:2-extending-a-basic-site](/tutorials/2-extending-a-basic-site)
|
See [form](/topics/forms) and [tutorial:2-extending-a-basic-site](/tutorials/2-extending-a-basic-site).
|
||||||
|
Note: To modify fields in the "Settings" tab, you need to use `updateSettingsFields()` instead.
|
||||||
|
|
||||||
## Removing inherited form fields and tabs
|
## Removing inherited form fields and tabs
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ It is usually added through the `[api:DataObject->getCMSFields()]` method:
|
|||||||
static $db = array('Content' => 'HTMLText');
|
static $db = array('Content' => 'HTMLText');
|
||||||
|
|
||||||
public function getCMSFields() {
|
public function getCMSFields() {
|
||||||
return new FieldSet(new HTMLEditorField('Content'));
|
return new FieldList(new HTMLEditorField('Content'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ See [Tutorial: Site Search](/tutorials/4-site-search) for details.
|
|||||||
## Searching for DataObjects
|
## Searching for DataObjects
|
||||||
|
|
||||||
The `[api:SearchContext]` class provides a good base implementation that you can hook into your own controllers.
|
The `[api:SearchContext]` class provides a good base implementation that you can hook into your own controllers.
|
||||||
A working implementation of searchable DataObjects can be seen in the `[api:ModelAdmin]` class.
|
A working implementation of searchable DataObjects can be seen in the `[ModelAdmin](/reference/modeladmin)` class.
|
||||||
|
|
||||||
[SearchContext](/reference/searchcontext) goes into more detail about setting up a default search form for `[api:DataObject]`s.
|
[SearchContext](/reference/searchcontext) goes into more detail about setting up a default search form for `[api:DataObject]`s.
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ dedicated search service like the [sphinx module](http://silverstripe.org/sphinx
|
|||||||
|
|
||||||
## Related
|
## Related
|
||||||
|
|
||||||
* `[api:ModelAdmin]`
|
* [ModelAdmin](/reference/modeladmin)
|
||||||
* [RestfulServer module](https://github.com/silverstripe/silverstripe-restfulserver)
|
* [RestfulServer module](https://github.com/silverstripe/silverstripe-restfulserver)
|
||||||
* [Tutorial: Site Search](/tutorials/4-site-search)
|
* [Tutorial: Site Search](/tutorials/4-site-search)
|
||||||
* [SearchContext](/reference/searchcontext)
|
* [SearchContext](/reference/searchcontext)
|
||||||
|
@ -99,7 +99,6 @@ our theme in action. The code for mine is below.
|
|||||||
<h1>$Title</h1>
|
<h1>$Title</h1>
|
||||||
$Content
|
$Content
|
||||||
$Form
|
$Form
|
||||||
$PageComments
|
|
||||||
|
|
||||||
|
|
||||||
All you have to do now is tell your site to use your new theme - This is defined in the **mysite/_config.php** file
|
All you have to do now is tell your site to use your new theme - This is defined in the **mysite/_config.php** file
|
||||||
|
@ -207,7 +207,7 @@ that the *BrowserPollSubmission* table is created. Now we just need to define 'd
|
|||||||
$submission = new BrowserPollSubmission();
|
$submission = new BrowserPollSubmission();
|
||||||
$form->saveInto($submission);
|
$form->saveInto($submission);
|
||||||
$submission->write();
|
$submission->write();
|
||||||
Director::redirectBack();
|
return $this->redirectBack();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,7 +218,7 @@ A function that processes a form submission takes two arguments - the first is t
|
|||||||
In our function we create a new *BrowserPollSubmission* object. Since the name of our form fields and the name of the
|
In our function we create a new *BrowserPollSubmission* object. Since the name of our form fields and the name of the
|
||||||
database fields are the same we can save the form directly into the data object.
|
database fields are the same we can save the form directly into the data object.
|
||||||
|
|
||||||
We call the 'write' method to write our data to the database, and 'Director::redirectBack()' will redirect the user back
|
We call the 'write' method to write our data to the database, and 'redirectBack()' will redirect the user back
|
||||||
to the home page.
|
to the home page.
|
||||||
|
|
||||||
|
|
||||||
@ -237,11 +237,8 @@ Change the end of the 'BrowserPollForm' function so it looks like this:
|
|||||||
|
|
||||||
:::php
|
:::php
|
||||||
public function BrowserPollForm() {
|
public function BrowserPollForm() {
|
||||||
...
|
// ...
|
||||||
|
|
||||||
// Create validator
|
|
||||||
$validator = new RequiredFields('Name', 'Browser');
|
$validator = new RequiredFields('Name', 'Browser');
|
||||||
|
|
||||||
return new Form($this, 'BrowserPollForm', $fields, $actions, $validator);
|
return new Form($this, 'BrowserPollForm', $fields, $actions, $validator);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -266,22 +263,16 @@ First modify the 'doBrowserPoll' to set the session variable 'BrowserPollVoted'
|
|||||||
*mysite/code/HomePage.php*
|
*mysite/code/HomePage.php*
|
||||||
|
|
||||||
:::php
|
:::php
|
||||||
...
|
// ...
|
||||||
|
class HomePage_Controller extends Page_Controller {
|
||||||
HomePage_Controller extends Page_Controller {
|
// ...
|
||||||
...
|
|
||||||
|
|
||||||
public function doBrowserPoll($data, $form) {
|
public function doBrowserPoll($data, $form) {
|
||||||
$submission = new BrowserPollSubmission();
|
$submission = new BrowserPollSubmission();
|
||||||
$form->saveInto($submission);
|
$form->saveInto($submission);
|
||||||
$submission->write();
|
$submission->write();
|
||||||
|
|
||||||
Session::set('BrowserPollVoted', true);
|
Session::set('BrowserPollVoted', true);
|
||||||
|
return $this->redirectBack();
|
||||||
Director::redirectBack();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
...
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -293,59 +284,55 @@ it is.
|
|||||||
if(Session::get('BrowserPollVoted')) {
|
if(Session::get('BrowserPollVoted')) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
// ...
|
||||||
...
|
}
|
||||||
|
|
||||||
|
|
||||||
If you visit the home page now you will see you can only vote once per session; after that the form won't be shown. You
|
If you visit the home page now you will see you can only vote once per session;
|
||||||
can start a new session by closing and reopening your browser (or if you're using Firefox and have installed the [Web
|
after that the form won't be shown.
|
||||||
Developer](http://chrispederick.com/work/web-developer/) extension, you can use its Clear Session Cookies command).
|
You can start a new session by closing and reopening your browser.
|
||||||
|
|
||||||
Although the form is not shown, you'll still see the 'Browser Poll' heading. We'll leave this for now: after we've built
|
Now that we're collecting data, it would be nice to show the results
|
||||||
the bar graph of the results, we'll modify the template to show the graph instead of the form if the user has already
|
on the website as well. We could simply output every vote, but that's boring.
|
||||||
voted.
|
Let's group the results by browser, through the SilverStripe data model.
|
||||||
|
|
||||||
We now need some way of getting the data from the database into the template.
|
In the [second tutorial](/tutorials/2-extending-a-basic-site),
|
||||||
|
we got a collection of news articles for the home page by
|
||||||
|
using the 'ArticleHolder::get()' function, which returns a `[api:DataList]`.
|
||||||
|
We can get all submissions in the same fashion, through `BrowserPollSubmission::get()`.
|
||||||
|
This list will be the starting point for our result aggregation.
|
||||||
|
|
||||||
In the second tutorial we got the latest news articles for the home page by using the 'DataObject::get' function. We
|
Create the function 'BrowserPollResults' on the *HomePage_Controller* class.
|
||||||
can't use the 'DataObject::get' function here directly as we wish to count the total number of votes for each browser.
|
|
||||||
By looking at the documentation for 'DataObject::get', we can see that it returns a `[api:DataObjectSet]`
|
|
||||||
object. In fact, all data that can be iterated over in a template with a page control is contained in a DataObjectSet.
|
|
||||||
|
|
||||||
A `[api:DataObjectSet]` is a set of not just DataObjects, but of ViewableData, which the majority of
|
|
||||||
SilverStripe's classes (including DataObject) inherit from. We can create a DataObjectSet, fill it with our data, and
|
|
||||||
then create our graph using a page control in the template. Create the function 'BrowserPollResults' on the
|
|
||||||
*HomePage_Controller* class.
|
|
||||||
|
|
||||||
** mysite/code/HomePage.php **
|
** mysite/code/HomePage.php **
|
||||||
|
|
||||||
:::php
|
:::php
|
||||||
public function BrowserPollResults() {
|
public function BrowserPollResults() {
|
||||||
$submissions = BrowserPollSubmission::get();
|
$submissions = new GroupedList(BrowserPollSubmission::get());
|
||||||
$total = $submissions->Count();
|
$total = $submissions->Count();
|
||||||
|
|
||||||
$doSet = new DataObjectSet();
|
$list = new ArrayList();
|
||||||
foreach($submissions->groupBy('Browser') as $browser => $data) {
|
foreach($submissions->groupBy('Browser') as $browserName => $browserSubmissions) {
|
||||||
$percentage = (int) ($data->Count() / $total * 100);
|
$percentage = (int) ($data->Count() / $total * 100);
|
||||||
$record = array(
|
$list->push(new ArrayData(array(
|
||||||
'Browser' => $browser,
|
'Browser' => $browserName,
|
||||||
'Percentage' => $percentage
|
'Percentage' => $percentage
|
||||||
);
|
)));
|
||||||
$doSet->push(new ArrayData($record));
|
|
||||||
}
|
}
|
||||||
|
return $list;
|
||||||
return $doSet;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
This code introduces a few new concepts, so let's step through it.
|
||||||
This introduces a few new concepts, so let's step through it.
|
|
||||||
|
|
||||||
:::php
|
:::php
|
||||||
$submissions = BrowserPollSubmission::get();
|
$submissions = new GroupedList(BrowserPollSubmission::get());
|
||||||
|
|
||||||
|
|
||||||
First we get all of the *BrowserPollSubmission*s from the database. This returns the submissions as a
|
First we get all of the `BrowserPollSubmission` records from the database.
|
||||||
DataObjectSet, which contains the submissions as *BrowserPollSubmission* objects.
|
This returns the submissions as a `[api:DataList]`.
|
||||||
|
Then we wrap it inside a `[api:GroupedList]`, which adds the ability
|
||||||
|
to group those records. The resulting object will behave just like
|
||||||
|
the original `DataList`, though (with the addition of a `groupBy()` method).
|
||||||
|
|
||||||
:::php
|
:::php
|
||||||
$total = $submissions->Count();
|
$total = $submissions->Count();
|
||||||
@ -354,29 +341,24 @@ DataObjectSet, which contains the submissions as *BrowserPollSubmission* objects
|
|||||||
We get the total number of submissions, which is needed to calculate the percentages.
|
We get the total number of submissions, which is needed to calculate the percentages.
|
||||||
|
|
||||||
:::php
|
:::php
|
||||||
$doSet = new DataObjectSet();
|
$list = new ArrayList();
|
||||||
foreach($submissions->groupBy('Browser') as $browser => $data) {
|
foreach($submissions->groupBy('Browser') as $browserName => $browserSubmissions) {
|
||||||
$percentage = (int) ($data->Count() / $total * 100);
|
$percentage = (int) ($browserSubmissions->Count() / $total * 100);
|
||||||
$record = array(
|
$list->push(new ArrayData(array(
|
||||||
'Browser' => $browser,
|
'Browser' => $browserName,
|
||||||
'Percentage' => $percentage
|
'Percentage' => $percentage
|
||||||
);
|
)));
|
||||||
$doSet->push(new ArrayData($record));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Now we create an empty DataObjectSet to hold our data and then iterate over the 'Browser' submissions field. The 'groupBy'
|
Now we create an empty `[api:ArrayList]` to hold the data we'll pass to the template.
|
||||||
method of DataObjectSet splits our DataObjectSet by the 'Browser' field passed to it. The percentage of submissions for each
|
Its similar to `[api:DataList]`, but can hold arbitrary objects rather than just `DataObject` instances.
|
||||||
browser is calculated using the size of the DataObjectSet. It puts these new DataObjectSets into an array indexed
|
Then iterate over the 'Browser' submissions field.
|
||||||
by the value of the field. The `[api:ArrayData]` class wraps an array into a ViewableData object, so we finally create a new
|
The `groupBy()` method splits our list by the 'Browser' field passed to it,
|
||||||
ArrayData object, which we can add to our *$doSet* DataObjectSet of results.
|
creating new lists with submissions just for a specific browser.
|
||||||
|
Each of those lists is keyed by the browser name.
|
||||||
:::php
|
The aggregated result is then contained in an `[api:ArrayData]` object,
|
||||||
return $doSet;
|
which behaves much like a standard PHP array, but allows us to use it in SilverStripe templates.
|
||||||
|
|
||||||
|
|
||||||
After we have iterated through all the browsers, the DataObjectSet contains all the results, which is then
|
|
||||||
returned.
|
|
||||||
|
|
||||||
The final step is to create the template to display our data. Change the 'BrowserPoll' div in
|
The final step is to create the template to display our data. Change the 'BrowserPoll' div in
|
||||||
*themes/tutorial/templates/Layout/HomePage.ss* to the below.
|
*themes/tutorial/templates/Layout/HomePage.ss* to the below.
|
||||||
@ -408,6 +390,9 @@ a complete poll.
|
|||||||
|
|
||||||
![](_images/pollresults.jpg)
|
![](_images/pollresults.jpg)
|
||||||
|
|
||||||
|
<div class="hint" markdown="1">
|
||||||
|
While the ORM is
|
||||||
|
</div>
|
||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@ function, and then attempt to render it with *Page_results.ss*, falling back to
|
|||||||
## Creating the template
|
## Creating the template
|
||||||
|
|
||||||
Lastly we need the template for the search page. This template uses all the same techniques used in previous
|
Lastly we need the template for the search page. This template uses all the same techniques used in previous
|
||||||
tutorials. It also uses a number of pagination variables, which are provided by the `[api:DataObjectSet]`
|
tutorials. It also uses a number of pagination variables, which are provided by the `[api:PaginatedList]`
|
||||||
class.
|
class.
|
||||||
|
|
||||||
*themes/simple/templates/Layout/Page_results.ss*
|
*themes/simple/templates/Layout/Page_results.ss*
|
||||||
|
@ -214,7 +214,7 @@ To use your *HasOneComplexTableField* table for a **1-to-1** relation, make this
|
|||||||
|
|
||||||
$tablefield->setOneToOne();
|
$tablefield->setOneToOne();
|
||||||
|
|
||||||
$fields->addFieldToTab( 'Root.Content.Student', $tablefield );
|
$fields->addFieldToTab( 'Root.Student', $tablefield );
|
||||||
|
|
||||||
return $fields;
|
return $fields;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user