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
|
||||
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.
|
||||
fe
|
||||
|
||||
### 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
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
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
|
||||
[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
|
||||
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.
|
||||
*/
|
||||
|
||||
public function populateDefaults() {
|
||||
$this->Date = date('Y-m-d');
|
||||
parent::populateDefaults();
|
||||
@ -27,7 +26,6 @@ methods. For example:
|
||||
* This method combines the Title of the parent object with the Title of this
|
||||
* object in the FullTitle field.
|
||||
*/
|
||||
|
||||
public function populateDefaults() {
|
||||
if($parent = $this->Parent()) {
|
||||
$this->FullTitle = $parent->Title . ': ' . $this->Title;
|
||||
|
@ -85,9 +85,8 @@ Create a new file called `zzz_admin/code/BookmarkedPageExtension.php` and insert
|
||||
:::php
|
||||
<?php
|
||||
class BookmarkedPageExtension extends DataExtension {
|
||||
public function extraStatics() {
|
||||
return array('db' => array('IsBookmarked' => 'Boolean'));
|
||||
}
|
||||
static $db = array('IsBookmarked' => 'Boolean');
|
||||
|
||||
public function updateCMSFields(&$fields) {
|
||||
$fields->addFieldToTab('Root.Main',
|
||||
new CheckboxField('IsBookmarked', "Show in CMS bookmarks?")
|
||||
|
@ -2,6 +2,10 @@
|
||||
|
||||
## 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]`.)
|
||||
|
||||
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->DetailForm() - form output
|
||||
* 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))
|
||||
* ComplexTableField_Popup->saveComplexTableField() - saving
|
@ -45,56 +45,42 @@ For example above we want to override Member with a Custom Member so we would wr
|
||||
|
||||
### 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:
|
||||
|
||||
:::php
|
||||
class CustomMember extends DataExtension {
|
||||
|
||||
public function extraStatics() {
|
||||
return array(
|
||||
'db' => array(
|
||||
'AvatarURL' => 'Varchar',
|
||||
),
|
||||
'has_one' => array(
|
||||
'RelatedMember' => 'Member',
|
||||
),
|
||||
);
|
||||
}
|
||||
static $db = array(
|
||||
'AvatarURL' => 'Varchar',
|
||||
);
|
||||
static $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
|
||||
|
||||
The member class demonstrates an extension that allows you to update the default CMS fields for an object in a
|
||||
extension:
|
||||
The member class demonstrates an extension that allows you to update the default CMS fields for an
|
||||
object in an extension:
|
||||
|
||||
:::php
|
||||
public function getCMSFields() {
|
||||
...
|
||||
$this->extend('updateCMSFields', $fields);
|
||||
return $fields;
|
||||
// ...
|
||||
$this->extend('updateCMSFields', $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
|
||||
public function updateCMSFields(FieldList $fields) {
|
||||
$fields->push(new TextField('Position', 'Position Title'));
|
||||
$fields->push(new UploadField('Image', 'Profile Image'));
|
||||
$fields->push(new TextField('Position', 'Position Title'));
|
||||
$fields->push(new UploadField('Image', 'Profile Image'));
|
||||
}
|
||||
|
||||
|
||||
|
||||
### Custom database generation
|
||||
|
||||
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'
|
||||
);
|
||||
public function getCMSFields() {
|
||||
return new FieldSet(
|
||||
return new FieldList(
|
||||
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'].
|
||||
|
||||
## 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
|
||||
|
||||
|
@ -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: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: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: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(){
|
||||
//http://www.v-nessa.net/2010/08/02/using-php-to-extract-image-exif-data
|
||||
$image = $this->AbsoluteURL;
|
||||
$d=new DataObjectSet();
|
||||
$d=new ArrayList();
|
||||
$exif = exif_read_data($image, 0, true);
|
||||
foreach ($exif as $key => $section) {
|
||||
$a=new DataObjectSet();
|
||||
$a=new ArrayList();
|
||||
foreach ($section as $name => $val)
|
||||
$a->push(new ArrayData(array("Title"=>$name,"Content"=>$val)));
|
||||
$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() {
|
||||
// Return an array containing keys 'db', 'has_one', 'many_many', 'belongs_many_many',
|
||||
}
|
||||
// define additional properties
|
||||
static $db = array();
|
||||
static $has_one = array();
|
||||
static $has_many = array();
|
||||
static $many_many = array();
|
||||
static $belongs_many_many = array();
|
||||
|
||||
public function somethingElse() {
|
||||
// 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
|
||||
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.
|
||||
|
||||
## Usage
|
||||
@ -187,6 +187,6 @@ See `[api:SearchFilter]` API Documentation
|
||||
|
||||
## Related
|
||||
|
||||
* `[api:ModelAdmin]`
|
||||
* [ModelAdmin](/reference/modeladmin)
|
||||
* [RestfulServer module](https://github.com/silverstripe/silverstripe-restfulserver)
|
||||
* [Tutorial: Site Search](/tutorials/4-site-search)
|
||||
|
@ -39,13 +39,9 @@ Create a mysite/code/CustomSiteConfig.php file.
|
||||
|
||||
class CustomSiteConfig extends DataExtension {
|
||||
|
||||
public function extraStatics() {
|
||||
return array(
|
||||
'db' => array(
|
||||
'FooterContent' => 'HTMLText'
|
||||
)
|
||||
);
|
||||
}
|
||||
static $db = array(
|
||||
'FooterContent' => 'HTMLText'
|
||||
);
|
||||
|
||||
public function updateCMSFields(FieldList $fields) {
|
||||
$fields->addFieldToTab("Root.Main", new HTMLEditorField("FooterContent", "Footer Content"));
|
||||
|
@ -2,45 +2,40 @@
|
||||
|
||||
## Introduction
|
||||
|
||||
An object representing a SQL query. It is easier to deal with object-wrappers than string-parsing a raw SQL-query. This
|
||||
object is used by `[api:DataObject]`, though...
|
||||
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.
|
||||
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
|
||||
reasons. You'll break the behaviour of:
|
||||
You'll run the risk of breaking various assumptions the ORM and code based on it have:
|
||||
|
||||
* Custom getters/setters
|
||||
* DataObject::onBeforeWrite/onBeforeDelete
|
||||
* Custom getters/setters (object property can differ from database column)
|
||||
* DataObject hooks like onBeforeWrite() and onBeforeDelete()
|
||||
* Automatic casting
|
||||
* Default-setting through object-model
|
||||
* `[api:DataObject]`
|
||||
* Default values set through objects
|
||||
* Database abstraction
|
||||
|
||||
We'll explain some ways to use *SELECT* with the full power of SQL, but still maintain a connection to the SilverStripe
|
||||
[datamodel](/topics/datamodel).
|
||||
We'll explain some ways to use *SELECT* with the full power of SQL,
|
||||
but still maintain a connection to the ORM where possible.
|
||||
|
||||
## Usage
|
||||
|
||||
|
||||
### SELECT
|
||||
|
||||
:::php
|
||||
$sqlQuery = new SQLQuery();
|
||||
$sqlQuery->select = array(
|
||||
'Firstname AS Name',
|
||||
'YEAR(Birthday) AS BirthYear'
|
||||
$sqlQuery->setFrom('Player');
|
||||
$sqlQuery->selectField('FieldName', 'Name');
|
||||
$sqlQuery->selectField('YEAR("Birthday")', 'BirthYear');
|
||||
$sqlQuery->addLeftJoin(
|
||||
'Team',
|
||||
'"Player"."TeamID" = "Team"."ID"'
|
||||
);
|
||||
$sqlQuery->from = "
|
||||
Player
|
||||
LEFT JOIN Team ON Player.TeamID = Team.ID
|
||||
";
|
||||
$sqlQuery->where = "
|
||||
YEAR(Birthday) = 1982
|
||||
";
|
||||
// $sqlQuery->orderby = "";
|
||||
// $sqlQuery->groupby = "";
|
||||
// $sqlQuery->having = "";
|
||||
// $sqlQuery->limit = "";
|
||||
// $sqlQuery->distinct = true;
|
||||
$sqlQuery->addWhere('YEAR("Birthday") = 1982');
|
||||
// $sqlQuery->setOrderBy(...);
|
||||
// $sqlQuery->setGroupBy(...);
|
||||
// $sqlQuery->setHaving(...);
|
||||
// $sqlQuery->setLimit(...);
|
||||
// $sqlQuery->setDistinct(true);
|
||||
|
||||
// get the raw 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
|
||||
// ...
|
||||
$sqlQuery->delete = true;
|
||||
$sqlQuery->setDelete(true);
|
||||
|
||||
|
||||
### INSERT/UPDATE
|
||||
@ -80,10 +75,10 @@ Raw SQL is handy for performance-optimized calls.
|
||||
:::php
|
||||
class Team extends DataObject {
|
||||
public function getPlayerCount() {
|
||||
$sqlQuery = new SQLQuery(
|
||||
"COUNT(Player.ID)",
|
||||
"Team LEFT JOIN Player ON Team.ID = Player.TeamID"
|
||||
);
|
||||
$sqlQuery = new SQLQuery();
|
||||
$sqlQuery->setFrom('Player');
|
||||
$sqlQuery->addSelect('COUNT("Player"."ID")');
|
||||
$sqlQuery->addLeftJoin('Team', '"Team"."ID" = "Player"."TeamID"');
|
||||
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.
|
||||
|
||||
:::php
|
||||
$sqlQuery = new SQLQuery(
|
||||
array('YEAR(Birthdate)', 'Birthdate'),
|
||||
'Player'
|
||||
);
|
||||
$sqlQuery = new SQLQuery();
|
||||
$sqlQuery->setFrom('Player');
|
||||
$sqlQuery->selectField('YEAR("Birthdate")', 'Birthdate');
|
||||
$map = $sqlQuery->execute()->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:
|
||||
|
||||
:::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:
|
||||
|
||||
:::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.
|
||||
|
||||
:::php
|
||||
$sqlQuery = singleton('Player')->buildSQL(
|
||||
'YEAR(Birthdate) = 1982'
|
||||
);
|
||||
$sqlQuery = singleton('Player')->buildSQL('YEAR("Birthdate") = 1982');
|
||||
|
||||
|
||||
This form of building a query has the following advantages:
|
||||
|
||||
* 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
|
||||
* Filtering records for correct *ClassName*
|
||||
|
||||
### 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
|
||||
`[api:DataObject]`s.
|
||||
|
||||
:::php
|
||||
$sqlQuery = new SQLQuery();
|
||||
$sqlQuery->select = array(
|
||||
'Firstname AS Name',
|
||||
'YEAR(Birthday) AS BirthYear',
|
||||
$sqlQuery->setSelect(array(
|
||||
'"Firstname" AS "Name"',
|
||||
'YEAR("Birthday") AS "BirthYear"',
|
||||
// IMPORTANT: Needs to be set after other selects to avoid overlays
|
||||
'Player.ClassName AS ClassName',
|
||||
'Player.ClassName AS RecordClassName',
|
||||
'Player.ID AS ID'
|
||||
);
|
||||
$sqlQuery->from = array(
|
||||
"Player",
|
||||
"LEFT JOIN Team ON Player.TeamID = Team.ID"
|
||||
);
|
||||
$sqlQuery->where = array(
|
||||
"YEAR(Player.Birthday) = 1982"
|
||||
);
|
||||
'"Player"."ClassName" AS "ClassName"',
|
||||
'"Player"."ClassName" AS "RecordClassName"',
|
||||
'"Player"."ID" AS "ID"'
|
||||
));
|
||||
$sqlQuery->setFrom('Player');
|
||||
$sqlQuery->addLeftJoin('Team', '"Player"."TeamID" = "Team"."ID"');
|
||||
$sqlQuery->addWhere("YEAR("Player"."Birthday") = 1982");
|
||||
|
||||
$result = $sqlQuery->execute();
|
||||
var_dump($result->first()); // array
|
||||
|
||||
// let Silverstripe work the magic
|
||||
$myDataObjectSet = singleton('Player')->buildDataObjectSet($result);
|
||||
$myList = singleton('Player')->buildDataObjectSet($result);
|
||||
var_dump($myDataObjectSet->First()); // DataObject
|
||||
|
||||
// this is where it gets tricky
|
||||
|
@ -2,6 +2,10 @@
|
||||
|
||||
## 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.
|
||||
Provides customizeable columns, record-deletion by ajax, paging, sorting, CSV-export, printing, input by
|
||||
`[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
|
||||
|
||||
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 %>`
|
||||
|
||||
|
@ -49,20 +49,10 @@ Append the option and corresponding value to your URL in your browser's address
|
||||
|
||||
| URL Variable | | Values | | Description |
|
||||
| ------------ | | ------ | | ----------- |
|
||||
| debug_memory | | 1 | | Output the number of bytes of memory used for this
|
||||
| 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 |
|
||||
| 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
|
||||
|
||||
|
@ -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::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. |
|
||||
| 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) |
|
||||
| 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) |
|
||||
@ -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::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) |
|
||||
| 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 |
|
||||
| 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)). |
|
||||
|
@ -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.
|
||||
|
||||
## 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:Controller]`
|
||||
|
@ -10,7 +10,7 @@ TODO Screenshot of admin interface
|
||||
|
||||
## Upload
|
||||
|
||||
TODO Link to Upload and FileIframeField classes
|
||||
TODO Link to UploadField and FileField classes
|
||||
|
||||
## Image Resizing
|
||||
|
||||
|
@ -60,78 +60,42 @@ The real difference, however, is that you can then define your controller method
|
||||
|
||||
## Form Field Types
|
||||
|
||||
There are many classes extending `[api:FormField]`. Some examples:
|
||||
|
||||
* `[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)
|
||||
There are many classes extending `[api:FormField]`,
|
||||
there's a full overview at [form-field-types](/reference/form-field-types)
|
||||
|
||||
|
||||
### Using Form Fields
|
||||
|
||||
To get these fields automatically rendered into a form element, all you need to do is create a new instance of the
|
||||
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.
|
||||
|
||||
:::php
|
||||
$form = new Form(
|
||||
$controller = $this,
|
||||
$name = "SignupForm",
|
||||
$fields = new FieldList(
|
||||
new TextField(
|
||||
$name = "FirstName",
|
||||
$title = "First name"
|
||||
),
|
||||
new TextField("Surname"),
|
||||
new EmailField("Email", "Email address"),
|
||||
),
|
||||
$actions = new FieldList(
|
||||
// List the action buttons here
|
||||
new FormAction("signup", "Sign up")
|
||||
),
|
||||
$requiredFields = new RequiredFields(
|
||||
// List the required fields here: "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"
|
||||
)
|
||||
$this, // controller
|
||||
"SignupForm", // form name
|
||||
new FieldList( // fields
|
||||
TextField::create("FirstName")
|
||||
->setTitle('First name')
|
||||
TextField::create("Surname")
|
||||
->setTitle('Last name')
|
||||
->setMaxLength(50),
|
||||
EmailField::create("Email")
|
||||
->setTitle("Email address")
|
||||
->setAttribute('type', 'email')
|
||||
),
|
||||
new FieldList( // actions
|
||||
FormAction::create("signup")->setTitle("Sign up")
|
||||
),
|
||||
new RequiredFields( // validation
|
||||
"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
|
||||
|
||||
@ -144,7 +108,7 @@ Readonly on a Form
|
||||
Readonly on a FieldList
|
||||
|
||||
:::php
|
||||
$myFieldSet->makeReadonly();
|
||||
$myFieldList->makeReadonly();
|
||||
|
||||
|
||||
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
|
||||
class MyForm extends Form {
|
||||
|
||||
public function __construct($controller, $name) {
|
||||
$fields = new FieldList(
|
||||
new TextField('FirstName', 'First name'),
|
||||
new EmailField('Email', 'Email address')
|
||||
);
|
||||
public function __construct($controller, $name) {
|
||||
$fields = new FieldList(
|
||||
new TextField('FirstName', 'First name'),
|
||||
new EmailField('Email', 'Email address')
|
||||
);
|
||||
|
||||
$actions = new FieldList(
|
||||
new FormAction('submit', 'Submit')
|
||||
);
|
||||
$actions = new FieldList(
|
||||
new FormAction('submit', 'Submit')
|
||||
);
|
||||
|
||||
parent::__construct($controller, $name, $fields, $actions);
|
||||
}
|
||||
parent::__construct($controller, $name, $fields, $actions);
|
||||
}
|
||||
|
||||
public function forTemplate() {
|
||||
return $this->renderWith(array(
|
||||
$this->class,
|
||||
'Form'
|
||||
));
|
||||
}
|
||||
public function forTemplate() {
|
||||
return $this->renderWith(array(
|
||||
$this->class,
|
||||
'Form'
|
||||
));
|
||||
}
|
||||
|
||||
public function submit($data, $form) {
|
||||
// do stuff here
|
||||
}
|
||||
public function submit($data, $form) {
|
||||
// do stuff here
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -201,31 +165,31 @@ basic customisation:
|
||||
|
||||
:::ss
|
||||
<form $FormAttributes>
|
||||
<% if Message %>
|
||||
<p id="{$FormName}_error" class="message $MessageType">$Message</p>
|
||||
<% else %>
|
||||
<p id="{$FormName}_error" class="message $MessageType" style="display: none"></p>
|
||||
<% end_if %>
|
||||
|
||||
<fieldset>
|
||||
<div id="FirstName" class="field text">
|
||||
<label class="left" for="{$FormName}_FirstName">First name</label>
|
||||
$dataFieldByName(FirstName)
|
||||
</div>
|
||||
<% if Message %>
|
||||
<p id="{$FormName}_error" class="message $MessageType">$Message</p>
|
||||
<% else %>
|
||||
<p id="{$FormName}_error" class="message $MessageType" style="display: none"></p>
|
||||
<% end_if %>
|
||||
|
||||
<fieldset>
|
||||
<div id="FirstName" class="field text">
|
||||
<label class="left" for="{$FormName}_FirstName">First name</label>
|
||||
$dataFieldByName(FirstName)
|
||||
</div>
|
||||
|
||||
<div id="Email" class="field email">
|
||||
<label class="left" for="{$FormName}_Email">Email</label>
|
||||
$dataFieldByName(Email)
|
||||
</div>
|
||||
<div id="Email" class="field email">
|
||||
<label class="left" for="{$FormName}_Email">Email</label>
|
||||
$dataFieldByName(Email)
|
||||
</div>
|
||||
|
||||
$dataFieldByName(SecurityID)
|
||||
</fieldset>
|
||||
$dataFieldByName(SecurityID)
|
||||
</fieldset>
|
||||
|
||||
<% if Actions %>
|
||||
<div class="Actions">
|
||||
<% loop Actions %>$Field<% end_loop %>
|
||||
</div>
|
||||
<% end_if %>
|
||||
<% if Actions %>
|
||||
<div class="Actions">
|
||||
<% loop Actions %>$Field<% end_loop %>
|
||||
</div>
|
||||
<% end_if %>
|
||||
</form>
|
||||
|
||||
`$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() {
|
||||
$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.
|
||||
|
@ -70,9 +70,9 @@ to write your own logic for any frontend output.
|
||||
i18n::set_date_format('dd.MM.YYYY');
|
||||
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
|
||||
[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).
|
||||
|
||||
### 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)).
|
||||
|
||||
Example: sapphire/lang/en.yml (extract)
|
||||
Example: framework/lang/en.yml (extract)
|
||||
|
||||
:::yml
|
||||
en:
|
||||
ImageUploader:
|
||||
Attach: 'Attach %s'
|
||||
FileIFrameField:
|
||||
UploadField:
|
||||
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:
|
||||
ImageUploader:
|
||||
ATTACH: '%s anhängen'
|
||||
FileIframeField:
|
||||
UploadField:
|
||||
NOTEADDFILES: 'Sie können Dateien hinzufügen sobald Sie das erste mal gespeichert haben'
|
||||
|
||||
Note that translations are cached across requests.
|
||||
@ -262,7 +260,7 @@ Example: framework/lang/en_US.php (extract)
|
||||
'Attach %s',
|
||||
'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
|
||||
$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 your `mysite/_config.php`:
|
||||
|
@ -52,14 +52,11 @@ especially useful if you know how long your source data needs to be.
|
||||
|
||||
:::php
|
||||
class StaffPage extends Page {
|
||||
|
||||
static $db = array(
|
||||
'Author' => 'Varchar(50)'
|
||||
);
|
||||
|
||||
}
|
||||
class StaffPage_Controller extends Page_Controller {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -68,7 +65,8 @@ model works.
|
||||
|
||||
## 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
|
||||
|
||||
|
@ -17,7 +17,7 @@ It is usually added through the `[api:DataObject->getCMSFields()]` method:
|
||||
static $db = array('Content' => 'HTMLText');
|
||||
|
||||
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
|
||||
|
||||
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.
|
||||
|
||||
@ -33,7 +33,7 @@ dedicated search service like the [sphinx module](http://silverstripe.org/sphinx
|
||||
|
||||
## Related
|
||||
|
||||
* `[api:ModelAdmin]`
|
||||
* [ModelAdmin](/reference/modeladmin)
|
||||
* [RestfulServer module](https://github.com/silverstripe/silverstripe-restfulserver)
|
||||
* [Tutorial: Site Search](/tutorials/4-site-search)
|
||||
* [SearchContext](/reference/searchcontext)
|
||||
|
@ -99,7 +99,6 @@ our theme in action. The code for mine is below.
|
||||
<h1>$Title</h1>
|
||||
$Content
|
||||
$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
|
||||
|
@ -207,7 +207,7 @@ that the *BrowserPollSubmission* table is created. Now we just need to define 'd
|
||||
$submission = new BrowserPollSubmission();
|
||||
$form->saveInto($submission);
|
||||
$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
|
||||
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.
|
||||
|
||||
|
||||
@ -237,11 +237,8 @@ Change the end of the 'BrowserPollForm' function so it looks like this:
|
||||
|
||||
:::php
|
||||
public function BrowserPollForm() {
|
||||
...
|
||||
|
||||
// Create validator
|
||||
// ...
|
||||
$validator = new RequiredFields('Name', 'Browser');
|
||||
|
||||
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*
|
||||
|
||||
:::php
|
||||
...
|
||||
|
||||
HomePage_Controller extends Page_Controller {
|
||||
...
|
||||
|
||||
// ...
|
||||
class HomePage_Controller extends Page_Controller {
|
||||
// ...
|
||||
public function doBrowserPoll($data, $form) {
|
||||
$submission = new BrowserPollSubmission();
|
||||
$form->saveInto($submission);
|
||||
$submission->write();
|
||||
|
||||
Session::set('BrowserPollVoted', true);
|
||||
|
||||
Director::redirectBack();
|
||||
return $this->redirectBack();
|
||||
}
|
||||
|
||||
...
|
||||
}
|
||||
|
||||
|
||||
@ -293,59 +284,55 @@ it is.
|
||||
if(Session::get('BrowserPollVoted')) {
|
||||
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
|
||||
can start a new session by closing and reopening your browser (or if you're using Firefox and have installed the [Web
|
||||
Developer](http://chrispederick.com/work/web-developer/) extension, you can use its Clear Session Cookies command).
|
||||
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 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
|
||||
the bar graph of the results, we'll modify the template to show the graph instead of the form if the user has already
|
||||
voted.
|
||||
Now that we're collecting data, it would be nice to show the results
|
||||
on the website as well. We could simply output every vote, but that's boring.
|
||||
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
|
||||
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.
|
||||
Create the function 'BrowserPollResults' on the *HomePage_Controller* class.
|
||||
|
||||
** mysite/code/HomePage.php **
|
||||
|
||||
:::php
|
||||
public function BrowserPollResults() {
|
||||
$submissions = BrowserPollSubmission::get();
|
||||
$submissions = new GroupedList(BrowserPollSubmission::get());
|
||||
$total = $submissions->Count();
|
||||
|
||||
$doSet = new DataObjectSet();
|
||||
foreach($submissions->groupBy('Browser') as $browser => $data) {
|
||||
$list = new ArrayList();
|
||||
foreach($submissions->groupBy('Browser') as $browserName => $browserSubmissions) {
|
||||
$percentage = (int) ($data->Count() / $total * 100);
|
||||
$record = array(
|
||||
'Browser' => $browser,
|
||||
$list->push(new ArrayData(array(
|
||||
'Browser' => $browserName,
|
||||
'Percentage' => $percentage
|
||||
);
|
||||
$doSet->push(new ArrayData($record));
|
||||
)));
|
||||
}
|
||||
|
||||
return $doSet;
|
||||
return $list;
|
||||
}
|
||||
|
||||
|
||||
This introduces a few new concepts, so let's step through it.
|
||||
This code introduces a few new concepts, so let's step through it.
|
||||
|
||||
:::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
|
||||
DataObjectSet, which contains the submissions as *BrowserPollSubmission* objects.
|
||||
First we get all of the `BrowserPollSubmission` records from the database.
|
||||
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
|
||||
$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.
|
||||
|
||||
:::php
|
||||
$doSet = new DataObjectSet();
|
||||
foreach($submissions->groupBy('Browser') as $browser => $data) {
|
||||
$percentage = (int) ($data->Count() / $total * 100);
|
||||
$record = array(
|
||||
'Browser' => $browser,
|
||||
$list = new ArrayList();
|
||||
foreach($submissions->groupBy('Browser') as $browserName => $browserSubmissions) {
|
||||
$percentage = (int) ($browserSubmissions->Count() / $total * 100);
|
||||
$list->push(new ArrayData(array(
|
||||
'Browser' => $browserName,
|
||||
'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'
|
||||
method of DataObjectSet splits our DataObjectSet by the 'Browser' field passed to it. The percentage of submissions for each
|
||||
browser is calculated using the size of the DataObjectSet. It puts these new DataObjectSets into an array indexed
|
||||
by the value of the field. The `[api:ArrayData]` class wraps an array into a ViewableData object, so we finally create a new
|
||||
ArrayData object, which we can add to our *$doSet* DataObjectSet of results.
|
||||
|
||||
:::php
|
||||
return $doSet;
|
||||
|
||||
|
||||
After we have iterated through all the browsers, the DataObjectSet contains all the results, which is then
|
||||
returned.
|
||||
Now we create an empty `[api:ArrayList]` to hold the data we'll pass to the template.
|
||||
Its similar to `[api:DataList]`, but can hold arbitrary objects rather than just `DataObject` instances.
|
||||
Then iterate over the 'Browser' submissions field.
|
||||
The `groupBy()` method splits our list by the 'Browser' field passed to it,
|
||||
creating new lists with submissions just for a specific browser.
|
||||
Each of those lists is keyed by the browser name.
|
||||
The aggregated result is then contained in an `[api:ArrayData]` object,
|
||||
which behaves much like a standard PHP array, but allows us to use it in SilverStripe templates.
|
||||
|
||||
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.
|
||||
@ -408,6 +390,9 @@ a complete poll.
|
||||
|
||||
![](_images/pollresults.jpg)
|
||||
|
||||
<div class="hint" markdown="1">
|
||||
While the ORM is
|
||||
</div>
|
||||
|
||||
## Summary
|
||||
|
||||
|
@ -98,7 +98,7 @@ function, and then attempt to render it with *Page_results.ss*, falling back to
|
||||
## Creating the template
|
||||
|
||||
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.
|
||||
|
||||
*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();
|
||||
|
||||
$fields->addFieldToTab( 'Root.Content.Student', $tablefield );
|
||||
$fields->addFieldToTab( 'Root.Student', $tablefield );
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user