mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Fixed usage of DataList etc in docs (fixes #7518)
This commit is contained in:
parent
cb145a0094
commit
868d3697fd
@ -193,6 +193,15 @@ The abstract `RelationList` class and its implementations `ManyManyList` and `Ha
|
||||
are replacing the `ComponentSet` API, which is only relevant if you have instanciated these manually.
|
||||
Relations are retrieved through the same way (e.g. `$myMember->Groups()`).
|
||||
|
||||
### New ORM: DataObjectSet->groupBy() changed to GroupedList decorator
|
||||
|
||||
:::php
|
||||
$members = Member::get();
|
||||
// before
|
||||
$grouped = $members->groupBy('Surname');
|
||||
// after
|
||||
$grouped = GroupedList::create($members)->groupBy('Surname');
|
||||
|
||||
### Aggregate changes for partial caching in templates ###
|
||||
|
||||
`DataObject::Aggregate()` and `DataObject::RelationshipAggregate()` are now deprecated. To replace your deprecated aggregate calls
|
||||
|
@ -184,9 +184,7 @@ Sample implementation of a custom loader. Assumes a CSV-file in a certain format
|
||||
$obj->LastName = $parts[1];
|
||||
}
|
||||
public static function getTeamByTitle(&$obj, $val, $record) {
|
||||
$SQL_val = Convert::raw2sql($val);
|
||||
return DataObject::get_one(
|
||||
'FootballTeam', "Title = '{$SQL_val}'"
|
||||
return FootballTeam::get()->filter('Title', $val)->First();
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -115,7 +115,7 @@ Add the following code to a new file `zzz_admin/code/BookmarkedLeftAndMainExtens
|
||||
<?php
|
||||
class BookmarkedPagesLeftAndMainExtension extends LeftAndMainExtension {
|
||||
public function BookmarkedPages() {
|
||||
return DataList::create('Page')->where('"IsBookmarked" = 1');
|
||||
return Page::get()->filter("IsBookmarked", 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,15 +1,22 @@
|
||||
# Grouping Data Object Sets
|
||||
# Grouping lists of records
|
||||
|
||||
The [api:DataObjectSet] class has a number of methods useful for grouping objects by fields. Together with sorting this
|
||||
can be used to break up long lists of data into more manageable sub-sections.
|
||||
The [api:SS_List] class is designed to return a flat list of records.
|
||||
These lists can get quite long, and hard to present on a single list.
|
||||
[Pagination](/howto/pagination) is one way to solve this problem,
|
||||
by splitting up the list into multiple pages.
|
||||
|
||||
The [api:DataObjectSet->groupBy()] method takes a field name as the single argument, and breaks the set up into a number
|
||||
of arrays, where each array contains only objects with the same value of that field. The [api:DataObjectSet->GroupedBy()]
|
||||
method builds on this and returns the same data in a template-friendly format.
|
||||
In this howto, we present an alternative to pagination:
|
||||
Grouping a list by various criteria, through the `[api:GroupedList]` class.
|
||||
This class is a `[api:SS_ListDecorator]`, which means it wraps around a list,
|
||||
adding new functionality.
|
||||
|
||||
It provides a `groupBy()` method, which takes a field name, and breaks up the managed list
|
||||
into a number of arrays, where each array contains only objects with the same value of that field.
|
||||
Similarly, the `GroupedBy()` method builds on this and returns the same data in a template-friendly format.
|
||||
|
||||
## Grouping Sets By First Letter
|
||||
|
||||
This example deals with breaking up a [api:DataObjectSet] into sub-headings by the first letter.
|
||||
This example deals with breaking up a [api:SS_List] into sub-headings by the first letter.
|
||||
|
||||
Let's say you have a set of Module objects, each representing a SilverStripe module, and you want to output a list of
|
||||
these in alphabetical order, with each letter as a heading; something like the following list:
|
||||
@ -23,31 +30,27 @@ these in alphabetical order, with each letter as a heading; something like the f
|
||||
* Database Plumber
|
||||
* ...
|
||||
|
||||
The first step is to set up the basic data model, along with a method that returns the first letter of the title. This
|
||||
The first step is to set up the basic data model,
|
||||
along with a method that returns the first letter of the title. This
|
||||
will be used both for grouping and for the title in the template.
|
||||
|
||||
:::php
|
||||
class Module extends DataObject {
|
||||
|
||||
public static $db = array(
|
||||
'Title' => 'Varchar(255)'
|
||||
'Title' => 'Text'
|
||||
);
|
||||
|
||||
// ...
|
||||
|
||||
/**
|
||||
* Returns the first letter of the module title, used for grouping.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTitleFirstLetter() {
|
||||
return $this->Title[0];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
The next step is to create a method or variable that will contain/return all the Module objects, sorted by title. For
|
||||
this example this will be a method on the Page class.
|
||||
The next step is to create a method or variable that will contain/return all the objects,
|
||||
sorted by title. For this example this will be a method on the `Page` class.
|
||||
|
||||
:::php
|
||||
class Page extends SiteTree {
|
||||
@ -56,23 +59,22 @@ this example this will be a method on the Page class.
|
||||
|
||||
/**
|
||||
* Returns all modules, sorted by their title.
|
||||
*
|
||||
* @return DataObjectSet
|
||||
* @return GroupedList
|
||||
*/
|
||||
public function getModules() {
|
||||
return DataObject::get('Module', null, '"Title"');
|
||||
public function getGroupedModules() {
|
||||
return GroupedList::create(Module::get()->sort('Title'));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
The final step is to render this into a template. The [api:DataObjectSet->GroupedBy()] method breaks up the set into
|
||||
a number of sets, grouped by the field that is passed as the parameter. In this case, the getTitleFirstLetter method
|
||||
defined earlier is used to break them up.
|
||||
The final step is to render this into a template. The `GroupedBy()` method breaks up the set into
|
||||
a number of sets, grouped by the field that is passed as the parameter.
|
||||
In this case, the `getTitleFirstLetter()` method defined earlier is used to break them up.
|
||||
|
||||
:::ss
|
||||
// Modules list grouped by TitleFirstLetter
|
||||
<%-- Modules list grouped by TitleFirstLetter --%>
|
||||
<h2>Modules</h2>
|
||||
<% control Modules.GroupedBy(TitleFirstLetter) %>
|
||||
<% control GroupedModules.GroupedBy(TitleFirstLetter) %>
|
||||
<h3>$TitleFirstLetter</h3>
|
||||
<ul>
|
||||
<% control Children %>
|
||||
@ -83,61 +85,63 @@ defined earlier is used to break them up.
|
||||
|
||||
## Grouping Sets By Month
|
||||
|
||||
Grouping a set by month is a very similar process. The only difference would be to sort the records by month name, and
|
||||
then create a method on the DataObject that returns the month name, and pass that to the [api:DataObjectSet->GroupedBy()]
|
||||
call.
|
||||
Grouping a set by month is a very similar process.
|
||||
The only difference would be to sort the records by month name, and
|
||||
then create a method on the DataObject that returns the month name,
|
||||
and pass that to the [api:GroupedList->GroupedBy()] call.
|
||||
|
||||
Again, the first step is to create a method on the class in question that will be displayed in a list. For this example,
|
||||
a [api:DataObject] called NewsItem will be used. This will have a method which returns the month it was posted in:
|
||||
We're reusing our example `Module` object,
|
||||
but grouping by its built-in `Created` property instead,
|
||||
which is automatically set when the record is first written to the database.
|
||||
This will have a method which returns the month it was posted in:
|
||||
|
||||
:::php
|
||||
class NewsItem extends DataObject {
|
||||
|
||||
public static $db = array(
|
||||
'Title' => 'Varchar(255)',
|
||||
'Date' => 'Date'
|
||||
);
|
||||
class Module extends DataObject {
|
||||
|
||||
// ...
|
||||
|
||||
/**
|
||||
* Returns the month name this news item was posted in.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getMonthPosted() {
|
||||
return date('F', strtotime($this->Date));
|
||||
public function getMonthCreated() {
|
||||
return date('F', strtotime($this->Created));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
The next step is to create a method that will return all the News records that exist, sorted by month name from
|
||||
January to December. This can be accomplshed by sorting by the Date field:
|
||||
The next step is to create a method that will return all records that exist,
|
||||
sorted by month name from January to December. This can be accomplshed by sorting by the `Created` field:
|
||||
|
||||
:::php
|
||||
class Page extends SiteTree {
|
||||
|
||||
|
||||
// ...
|
||||
|
||||
/**
|
||||
* Returns all news items, sorted by the month they were posted
|
||||
*
|
||||
* @return DataObjectSet
|
||||
* @return GroupedList
|
||||
*/
|
||||
public function getNewsItems() {
|
||||
return DataObject::get('NewsItem', null, '"Date"');
|
||||
public function getGroupedModulesByDate() {
|
||||
return GroupedList::create(Module::get()->sort('Created'));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
The final step is the render this into the template using the [api:DataObjectSet->GroupedBy()] method.
|
||||
The final step is the render this into the template using the [api:GroupedList->GroupedBy()] method.
|
||||
|
||||
:::ss
|
||||
// Modules list grouped by the Month Posted
|
||||
<h2>Modules</h2>
|
||||
<% control NewsItems.GroupedBy(MonthPosted) %>
|
||||
<h3>$MonthPosted</h3>
|
||||
<% control GroupedModulesByDate.GroupedBy(MonthCreated) %>
|
||||
<h3>$MonthCreated</h3>
|
||||
<ul>
|
||||
<% control Children %>
|
||||
<li>$Title ($Date.Nice)</li>
|
||||
<li>$Title ($Created.Nice)</li>
|
||||
<% end_control %>
|
||||
</ul>
|
||||
<% end_control %>
|
||||
<% end_control %>
|
||||
|
||||
## Related
|
||||
|
||||
* [Howto: "Pagination"](/howto/pagination)
|
@ -8,7 +8,7 @@ the language and functions which are used in the guides.
|
||||
|
||||
* [Import CSV Data](csv-import). Build a simple CSV importer using either [api:ModelAdmin] or a custom controller
|
||||
* [Dynamic Default Fields](dynamic-default-fields). Pre populate a [api:DataObject] with data.
|
||||
* [Grouping DataObjectSets](grouping-dataobjectsets). Group results in a [api:DataObjectSet] to create sub sections.
|
||||
* [Grouping Lists](grouping-dataobjectsets). Group results in a [api:SS_List] to create sub sections.
|
||||
* [PHPUnit Configuration](phpunit-configuration). How to setup your testing environment with PHPUnit
|
||||
* [Extend the CMS Interface](extend-cms-interface).
|
||||
* [How to customize CMS Tree](customize-cms-tree).
|
||||
|
@ -1,11 +1,11 @@
|
||||
# Paginating A List
|
||||
|
||||
Adding pagination to a `[api:DataList]` or `[DataObjectSet]` is quite simple. All
|
||||
Adding pagination to a `[api:SS_List]` is quite simple. All
|
||||
you need to do is wrap the object in a `[api:PaginatedList]` decorator, which takes
|
||||
care of fetching a sub-set of the total list and presenting it to the template.
|
||||
|
||||
In order to create a paginated list, you can create a method on your controller
|
||||
that first creates a `DataList` that will return all pages, and then wraps it
|
||||
that first creates a `SS_List` that will return all pages, and then wraps it
|
||||
in a `[api:PaginatedList]` object. The `PaginatedList` object is also passed the
|
||||
HTTP request object so it can read the current page information from the
|
||||
"?start=" GET var.
|
||||
@ -18,8 +18,7 @@ information.
|
||||
* Returns a paginated list of all pages in the site.
|
||||
*/
|
||||
public function PaginatedPages() {
|
||||
$pages = DataList::create('Page');
|
||||
return new PaginatedList($pages, $this->request);
|
||||
return new PaginatedList(Page::get(), $this->request);
|
||||
}
|
||||
|
||||
## Setting Up The Template
|
||||
@ -72,3 +71,7 @@ list will already contain only the items that you wish to display on the current
|
||||
page. In this situation the automatic limiting done by `[api:PaginatedList]`
|
||||
will break the pagination. You can disable automatic limiting using the
|
||||
`[api:PaginatedList->setLimitItems()]` method when using custom lists.
|
||||
|
||||
## Related
|
||||
|
||||
* [Howto: "Grouping Lists"](/howto/grouping-dataobjectsets)
|
@ -403,7 +403,7 @@ Example:
|
||||
* This method returns something cool. {@link MyParentMethod} has other cool stuff in it.
|
||||
*
|
||||
* @param string $colour The colour of cool things that you want
|
||||
* @return DataObjectSet A list of everything cool
|
||||
* @return DataList A list of everything cool
|
||||
*/
|
||||
public function myMethod($foo) {}
|
||||
|
||||
@ -429,7 +429,7 @@ If you have to use raw SQL, make sure your code works across databases make sure
|
||||
with the column or table name escaped with double quotes and values with single quotes.
|
||||
|
||||
:::php
|
||||
DataObject::get("MyClass", "\"Title\" = 'my title'");
|
||||
MyClass::get()->where("\"Title\" = 'my title'");
|
||||
|
||||
Use [ANSI SQL](http://en.wikipedia.org/wiki/SQL#Standardization) format where possible.
|
||||
|
||||
|
@ -2,53 +2,67 @@
|
||||
|
||||
## Introduction
|
||||
|
||||
A single database record & abstract class for the data-access-model.
|
||||
The `[api:DataObject]` class represents a single row in a database table,
|
||||
following the ["Active Record"](http://en.wikipedia.org/wiki/Active_record_pattern) design pattern.
|
||||
|
||||
## Usage
|
||||
## Defining Properties
|
||||
|
||||
* [datamodel](/topics/datamodel): The basic pricinples
|
||||
* [data-types](/topics/data-types): Casting and special property-parsing
|
||||
* `[api:DataObject]`: A "container" for DataObjects
|
||||
Properties defined through `DataObject::$db` map to table columns,
|
||||
and can be declared as different [data-types](/topics/data-types).
|
||||
|
||||
## Basics
|
||||
## Loading and Saving Records
|
||||
|
||||
The call to `DataObject->getCMSFields()` is the centerpiece of every data administration interface in SilverStripe,
|
||||
which returns a `[api:FieldList]`''.
|
||||
The basic principles around data persistence and querying for objects
|
||||
is explained in the ["datamodel" topic](/topics/datamodel).
|
||||
|
||||
## Defining Form Fields
|
||||
|
||||
In addition to defining how data is persisted, the class can also
|
||||
help with editing it by providing form fields through `DataObject->getCMSFields()`.
|
||||
The resulting `[api:FieldList]` is the centrepiece of many data administration interfaces in SilverStripe.
|
||||
Many customizations of the SilverStripe CMS interface start here,
|
||||
by adding, removing or configuring fields.
|
||||
|
||||
Example getCMSFields implementation
|
||||
|
||||
:::php
|
||||
class MyPage extends Page {
|
||||
class MyDataObject extends DataObject {
|
||||
$db = array(
|
||||
'IsActive' => 'Boolean'
|
||||
);
|
||||
public function getCMSFields() {
|
||||
return new FieldSet(
|
||||
new CheckboxField('IsActive')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
There's various [form field types](/references/form-field-types), for editing text, dates,
|
||||
restricting input to numbers, and much more.
|
||||
|
||||
## Scaffolding Form Fields
|
||||
|
||||
The ORM already has a lot of information about the data represented by a `DataObject`
|
||||
through its `$db` property, so why not use it to create form fields as well?
|
||||
If you call the parent implementation, the class will use `[api:FormScaffolder]`
|
||||
to provide reasonable defaults based on the property type (e.g. a checkbox field for booleans).
|
||||
You can then further customize those fields as required.
|
||||
|
||||
:::php
|
||||
class MyDataObject extends DataObject {
|
||||
// ...
|
||||
public function getCMSFields() {
|
||||
$fields = parent::getCMSFields();
|
||||
$fields->addFieldToTab('Root.Content',new CheckboxField('CustomProperty'));
|
||||
$fields->fieldByName('IsActive')->setTitle('Is active?');
|
||||
return $fields;
|
||||
}
|
||||
}
|
||||
|
||||
The `[ModelAdmin](/reference/modeladmin)` class uses this approach to provide
|
||||
data management interfaces with very little custom coding.
|
||||
|
||||
## Scaffolding Formfields
|
||||
|
||||
These calls retrieve a `[api:FieldList]` for the area where you intend to work with the scaffolded form.
|
||||
|
||||
### For the CMS
|
||||
|
||||
:::php
|
||||
$fields = singleton('MyDataObject')->getCMSFields();
|
||||
|
||||
|
||||
### For the Frontend
|
||||
|
||||
Used for simple frontend forms without relation editing or `[api:TabSet] behaviour. Uses `scaffoldFormFields()` by
|
||||
default. To customize, either overload this method in your subclass, or extend it by `DataExtension->updateFormFields()`.
|
||||
|
||||
:::php
|
||||
$fields = singleton('MyDataObject')->getFrontEndFields();
|
||||
|
||||
|
||||
## Customizing Scaffolded Fields
|
||||
|
||||
This section covers how to enhance the default scaffolded form fields from above. It is particularly useful when used
|
||||
in conjunction with the `[api:ModelAdmin]` in the CMS to make relevant data administration interfaces.
|
||||
|
||||
You can also alter the fields of built-in and module `DataObject` classes through
|
||||
your own `[DataExtension](/reference/dataextension)`, and a call to `[api:DataExtension->updateCMSFields()]`.
|
||||
|
||||
### Searchable Fields
|
||||
|
||||
|
@ -1,98 +0,0 @@
|
||||
# DataObjectSet
|
||||
|
||||
## Introduction
|
||||
|
||||
This class represents a set of `[api:DataObject]`s, such as the results of a query. It is the base for all
|
||||
[datamodel](/topics/datamodel)-related querying. It implements the [Iterator
|
||||
interface](http://php.net/manual/en/language.oop5.iterations.php) introduced in PHP5.
|
||||
|
||||
Relations (`has_many`/`many_many`) are described in `[api:ComponentSet]`, a subclass of `[api:DataObjectSet]`.
|
||||
|
||||
## Usage
|
||||
|
||||
### Getting the size
|
||||
|
||||
:::php
|
||||
$mySet->Count();
|
||||
|
||||
### Getting an single element
|
||||
|
||||
:::php
|
||||
$myFirstDataObject = $mySet->First();
|
||||
$myLastDataObject = $mySet->Last();
|
||||
|
||||
|
||||
### Getting multiple elements
|
||||
|
||||
:::php
|
||||
$mySpecialDataObjects = $mySet->find('Status', 'special');
|
||||
$startingFromTen = $mySet->getOffset(10);
|
||||
$tenToTwenty = $mySet->getRange(10, 10);
|
||||
|
||||
|
||||
### Getting one property
|
||||
|
||||
:::php
|
||||
$myIDArray = $mySet->column('ID');
|
||||
|
||||
### Grouping
|
||||
|
||||
You can group a set by a specific column. Consider using `[api:SQLQuery]` with a *GROUP BY* statement for enhanced
|
||||
performance.
|
||||
|
||||
:::php
|
||||
$groupedSet = $mySet->groupBy('Lastname');
|
||||
|
||||
### Sorting
|
||||
|
||||
Sort a set by a specific column.
|
||||
|
||||
:::php
|
||||
$mySet->sort('Lastname'); //ascending
|
||||
$mySet->sort('Lastname', 'DESC'); //descending
|
||||
|
||||
This works on the object itself, so do NOT do something like this:
|
||||
|
||||
:::php
|
||||
$sortedSet = $mySet->sort('Lastname'); //ascending
|
||||
|
||||
## Merge with other `[api:DataObjectSet]`s
|
||||
|
||||
:::php
|
||||
$myFirstSet->merge($mySecondSet);
|
||||
// $myFirstSet now contains all combined values
|
||||
|
||||
|
||||
### Mapping for Dropdowns
|
||||
|
||||
When using `[api:DropdownField]` and its numerous subclasses to select a value from a set, you can easily map
|
||||
the records to a compatible array:
|
||||
|
||||
:::php
|
||||
$map = $mySet->toDropDownMap('ID', 'Title');
|
||||
$dropdownField = new DropdownField('myField', 'my label', $map);
|
||||
|
||||
|
||||
### Converting to array
|
||||
|
||||
:::php
|
||||
$myArray = $mySet->toArray();
|
||||
|
||||
### Checking for existence
|
||||
|
||||
It is good practice to check for empty sets before doing any iteration.
|
||||
|
||||
:::php
|
||||
$mySet = DataObject::get('Players');
|
||||
if($mySet->exists()) foreach($mySet as $player)
|
||||
|
||||
### Paging
|
||||
|
||||
`[api:DataObject]`s have native support for dealing with **pagination**.
|
||||
See *setPageLimits*, *setPageLength*, etc.
|
||||
|
||||
FIXME Complete pagination documentation
|
||||
|
||||
|
||||
## API Documentation
|
||||
`[api:DataObjectSet]`
|
@ -48,17 +48,14 @@ mod_rewrite works.
|
||||
|
||||
## main.php
|
||||
|
||||
All requests go through main.php, which sets up the environment and then hands control over to Director.
|
||||
All requests go through `main.`php, which sets up the environment and then hands control over to `Director`.
|
||||
|
||||
**See:** The API documentation of `[api:Main]` for information about how main.php processes requests.
|
||||
## Director and URL patterns
|
||||
|
||||
main.php relies on `[api:Director]` to work out which controller should handle this request. `[api:Director]` will instantiate that
|
||||
controller object and then call `[api:Controller::run()]`.
|
||||
|
||||
**See:** The API documentation of `[api:Director]` for information about how Director parses URLs and hands control over to a controller object.
|
||||
|
||||
In general, the URL is build up as follows: page/action/ID/otherID - e.g. http://www.mysite.com/mypage/addToCart/12.
|
||||
In general, the URL is build up as follows: `page/action/ID/otherID` - e.g. http://www.mysite.com/mypage/addToCart/12.
|
||||
This will add an object with ID 12 to the cart.
|
||||
|
||||
When you create a function, you can access the ID like this:
|
||||
@ -67,7 +64,7 @@ When you create a function, you can access the ID like this:
|
||||
public function addToCart ($request) {
|
||||
$param = $r->allParams();
|
||||
echo "my ID = ".$param["ID"];
|
||||
$obj = DataObject::get("myProduct", $param["ID"]);
|
||||
$obj = MyProduct::get()->byID($param["ID"]);
|
||||
$obj->addNow();
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,6 @@ Reference articles complement our auto-generated [API docs](http://api.silverstr
|
||||
* [Database Structure](database-structure): Conventions and best practices for database tables and fields
|
||||
* [DataObject](dataobject): Base class for database records
|
||||
* [DataExtension](dataextension): A "mixin" system allowing to extend core classes
|
||||
* [DataObjectSet](dataobjectset): The base collection of database records in the ORM
|
||||
* [Director](director): Routes URLs and handles HTTP requests
|
||||
* [Execution Pipeline](execution-pipeline): Detailed look on the way an HTTP request takes through the system
|
||||
* [Form Field Types](form-field-types): Highlevel overview of field classes
|
||||
@ -32,8 +31,4 @@ Reference articles complement our auto-generated [API docs](http://api.silverstr
|
||||
* [TableListField](tablelistfield): View and delete records in the CMS
|
||||
* [Typography](typography): CSS file to enable WYSIWYG previews in the CMS
|
||||
* [urlvariabletools](urlvariabletools): Debug and maintenance switches
|
||||
* [Versioned](versioned): Extension for SiteTree and other classes to store old versions and provide "staging"
|
||||
|
||||
## Feedback
|
||||
|
||||
If you have a topic you would like covered in these section please ask for it on our [Bug Tracker](http://open.silverstripe.org)
|
||||
* [Versioned](versioned): Extension for SiteTree and other classes to store old versions and provide "staging"
|
@ -57,7 +57,7 @@ something like this:
|
||||
|
||||
public function LatestUpdates() {
|
||||
// 10 is the number of pages
|
||||
return DataObject::get("Page", "", "LastEdited DESC", "", 10);
|
||||
return Page::get()->sort("LastEdited", "DESC")->limit(10);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,7 +64,7 @@ CustomSideReport.php
|
||||
|
||||
public function records() {
|
||||
// the data the report returns all the dataobjects of type Page and sorted by title. See datamodel for more info
|
||||
return DataObject::get("Page", "", "Title");
|
||||
return Page::get()->sort("Title");
|
||||
}
|
||||
|
||||
public function fieldsToShow() {
|
||||
|
@ -23,7 +23,7 @@ might consist of more than one *URLSegment*).
|
||||
|
||||
:::php
|
||||
// wrong
|
||||
$mypage = DataObject::get_one('SiteTree', '"URLSegment" = \'<mylink>\'');
|
||||
$mypage = SiteTree::get()->filter("URLSegment", '<mylink>')->First();
|
||||
// right
|
||||
$mypage = SiteTree::get_by_link('<mylink>');
|
||||
|
||||
@ -114,7 +114,8 @@ it is a good starting point, for choosing your customisation.
|
||||
|
||||
public function canCreate() {
|
||||
//here is a trick to only allow one (e.g. holder) of a page
|
||||
return !DataObject::get_one($this->class);
|
||||
$class = $this->class;
|
||||
return !$class::get()->Count();
|
||||
}
|
||||
|
||||
public function canDelete() {
|
||||
|
@ -32,7 +32,7 @@ publisher to generate folders and HTML-files.
|
||||
$urls = array();
|
||||
|
||||
// memory intensive depending on number of pages
|
||||
$pages = DataObject::get("SiteTree");
|
||||
$pages = SiteTree::get();
|
||||
|
||||
foreach($pages as $page) {
|
||||
$urls = array_merge($urls, (array)$page->subPagesToCache());
|
||||
@ -78,7 +78,7 @@ you can also add an exclusion
|
||||
:::php
|
||||
public function allPagesToCache() {
|
||||
$urls = array();
|
||||
$pages = DataObject::get("SiteTree");
|
||||
$pages = SiteTree::get();
|
||||
|
||||
// ignored page types
|
||||
$ignored = array('UserDefinedForm');
|
||||
@ -93,12 +93,12 @@ you can also add an exclusion
|
||||
return $urls;
|
||||
}
|
||||
|
||||
You can also pass the filtering to the original DataObject::get("SiteTree");
|
||||
You can also pass the filtering to the original `SiteTree::get()`;
|
||||
|
||||
:::php
|
||||
public function allPagesToCache() {
|
||||
$urls = array();
|
||||
$pages = DataObject::get("SiteTree", "ClassName != 'UserDefinedForm'");
|
||||
$pages = SiteTree::get()->where("ClassName != 'UserDefinedForm'");
|
||||
...
|
||||
|
||||
## Single server Caching
|
||||
|
@ -82,7 +82,7 @@ For more information on each of the features used in the example, you can read b
|
||||
);
|
||||
|
||||
// custom DataObjectSet
|
||||
$myProducts = DataObject::get('Product','Code = "MyCode"');
|
||||
$myProducts = Product::get()->filter('Code', "MyCode");
|
||||
$myTableListField->setCustomSourceItems($myProducts);
|
||||
|
||||
// custom SQL
|
||||
|
@ -54,7 +54,6 @@ incomplete - please add to it** *Try to keep it in alphabetical order too! :)*
|
||||
| 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::setDefaultAdmin('admin','password'); | | Set default admin email and password, helpful for recovering your password |
|
||||
| SSAkismet::setAPIKey(string $key) | | Enables use of the Akismet spam filter. The key must be a valid WordPress API key. |
|
||||
| SSViewer::set_theme(string $themename) | | Choose the default theme for your site |
|
||||
|
||||
## Constants
|
||||
|
@ -1,26 +1,87 @@
|
||||
# Data Types
|
||||
# Data Types and Casting
|
||||
|
||||
These are the data-types that you can use when defining your data objects. They are all subclasses of `[api:DBField]`
|
||||
for introducing their usage.
|
||||
|
||||
Properties on any SilverStripe object can be type casted automatically,
|
||||
by transforming its scalar value into an instance of the `[api:DBField]` class,
|
||||
providing additional helpers. For example, a string can be cast as
|
||||
a `[api:Text]` type, which has a `FirstSentence()` method to retrieve the first
|
||||
sentence in a longer piece of text.
|
||||
|
||||
## Types
|
||||
## Available Types
|
||||
|
||||
* `[api:Varchar]`: A variable-length string of up to 255 characters, designed to store raw text
|
||||
* `[api:Text]`: A variable-length string of up to 2 megabytes, designed to store raw text
|
||||
* `[api:HTMLVarchar]`: A variable-length string of up to 255 characters, designed to store HTML
|
||||
* `[api:HTMLText]`: A variable-length string of up to 2 megabytes, designed to store HTML
|
||||
* `[api:Enum]`: An enumeration of a set of strings
|
||||
* `[api:Boolean]`: A boolean field.
|
||||
* `[api:Int]`: An integer field.
|
||||
* `[api:Decimal]`: A decimal number.
|
||||
* `[api:Currency]`: A number with 2 decimal points of precision, designed to store currency values.
|
||||
* `[api:Percentage]`: A decimal number between 0 and 1 that represents a percentage.
|
||||
* `[api:Date]`: A date field
|
||||
* `[api:Decimal]`: A decimal number.
|
||||
* `[api:Enum]`: An enumeration of a set of strings
|
||||
* `[api:HTMLText]`: A variable-length string of up to 2 megabytes, designed to store HTML
|
||||
* `[api:HTMLVarchar]`: A variable-length string of up to 255 characters, designed to store HTML
|
||||
* `[api:Int]`: An integer field.
|
||||
* `[api:Percentage]`: A decimal number between 0 and 1 that represents a percentage.
|
||||
* `[api:SS_Datetime]`: A date / time field
|
||||
* `[api:Text]`: A variable-length string of up to 2 megabytes, designed to store raw text
|
||||
* `[api:Time]`: A time field
|
||||
* `[api:Varchar]`: A variable-length string of up to 255 characters, designed to store raw text
|
||||
|
||||
## HTMLText vs. Text, and HTMLVarchar vs. Varchar
|
||||
## Casting arbitrary values
|
||||
|
||||
On the most basic level, the class can be used as simple conversion class
|
||||
from one value to another, e.g. to round a number.
|
||||
|
||||
:::php
|
||||
DBField::create_field('Double', 1.23456)->Round(2); // results in 1.23
|
||||
|
||||
Of course that's much more verbose than the equivalent PHP call.
|
||||
The power of `[api:DBField]` comes with its more sophisticated helpers,
|
||||
like showing the time difference to the current date:
|
||||
|
||||
:::php
|
||||
DBField::create_field('Date', '1982-01-01')->TimeDiff(); // shows "30 years ago"
|
||||
|
||||
## Casting ViewableData
|
||||
|
||||
Most objects in SilverStripe extend from `[api:ViewableData]`,
|
||||
which means they know how to present themselves in a view context.
|
||||
Through a `$casting` array, arbitrary properties and getters can be casted:
|
||||
|
||||
:::php
|
||||
class MyObject extends ViewableData {
|
||||
static $casting = array(
|
||||
'MyDate' => 'Date'
|
||||
);
|
||||
function getMyDate() {
|
||||
return '1982-01-01';
|
||||
}
|
||||
}
|
||||
$obj = new MyObject;
|
||||
$obj->getMyDate(); // returns string
|
||||
$obj->MyDate; // returns string
|
||||
$obj->obj('MyDate'); // returns object
|
||||
$obj->obj('MyDate')->InPast(); // returns boolean
|
||||
|
||||
## Casting DataObject
|
||||
|
||||
The `[api:DataObject]` class uses `DBField` to describe the types of its
|
||||
properties which are persisted in database columns, through the `[$db](api:DataObject::$db)` property.
|
||||
In addition to type information, the `DBField` class also knows how to
|
||||
define itself as a database column. See the ["datamodel" topic](/topics/datamodel#casting) for more details.
|
||||
|
||||
<div class="warning" markdown="1">
|
||||
Since we're dealing with a loosely typed language (PHP)
|
||||
as well as varying type support by the different database drivers,
|
||||
type conversions between the two systems are not guaranteed to be lossless.
|
||||
Please take particular care when casting booleans, null values, and on float precisions.
|
||||
</div>
|
||||
|
||||
## Casting in templates
|
||||
|
||||
In templates, casting helpers are available without the need for an `obj()` call.
|
||||
|
||||
Example: Flagging an object of type `MyObject` (see above) if it's date is in the past.
|
||||
|
||||
:::ss
|
||||
<% if MyObjectInstance.MyDate.InPast %>Outdated!<% end_if %>
|
||||
|
||||
## Casting HTML Text
|
||||
|
||||
The database field types `[api:HTMLVarchar]` and `[api:Varchar]` are exactly the same in the database. However, the
|
||||
templating engine knows to escape the `[api:Varchar]` field and not the `[api:HTMLVarchar]` field. So, it's important you
|
||||
@ -29,6 +90,7 @@ use the right field if you don't want to be putting $FieldType.XML everywhere.
|
||||
If you're going to put HTML content into the field, please use the field type with the HTML prefix. Otherwise, you're
|
||||
going to risk double-escaping your data, forgetting to escape your data, and generally creating a confusing situation.
|
||||
|
||||
## Usage
|
||||
## Related
|
||||
|
||||
* See [datamodel](/topics/datamodel) for information about **database schemas** implementing these types
|
||||
* ["datamodel" topic](/topics/datamodel)
|
||||
* ["security" topic](/topics/security)
|
@ -3,21 +3,20 @@
|
||||
SilverStripe uses an [object-relational model](http://en.wikipedia.org/wiki/Object-relational_model) that assumes the
|
||||
following connections:
|
||||
|
||||
* Each database-table maps to a php-class
|
||||
* Each database-row maps to a php-object
|
||||
* Each database-column maps to a property on a php-object
|
||||
* Each database-table maps to a PHP class
|
||||
* Each database-row maps to a PHP object
|
||||
* Each database-column maps to a property on a PHP object
|
||||
|
||||
All data tables in SilverStripe are defined as subclasses of `[api:DataObject]`. Inheritance is supported in the data
|
||||
model: seperate tables will be linked together, the data spread across these tables. The mapping and saving/loading
|
||||
logic is handled by SilverStripe, you don't need to worry about writing SQL most of the time.
|
||||
|
||||
The advanced object-relational layer in SilverStripe is one of the main reasons for requiring PHP5. Most of its
|
||||
customizations are possible through [PHP5 Object
|
||||
Most of the ORM customizations are possible through [PHP5 Object
|
||||
Overloading](http://www.onlamp.com/pub/a/php/2005/06/16/overloading.html) handled in the `[api:Object]`-class.
|
||||
|
||||
See [database-structure](/reference/database-structure) for in-depth information on the database-schema.
|
||||
|
||||
## Generating the database-schema
|
||||
## Generating the Database Schema
|
||||
|
||||
The SilverStripe database-schema is generated automatically by visiting the URL.
|
||||
`http://<mysite>/dev/build`
|
||||
@ -28,14 +27,13 @@ Note: You need to be logged in as an administrator to perform this command.
|
||||
|
||||
## Querying Data
|
||||
|
||||
Every query to data starts with a `DataList::create($class)` or `$class::get()` call. For example, this query would return
|
||||
all of the Member objects:
|
||||
Every query to data starts with a `DataList::create(<class>)` or `<class>::get()` call. For example, this query would return all of the `Member` objects:
|
||||
|
||||
:::php
|
||||
$members = Member::get();
|
||||
|
||||
The ORM uses a "fluent" syntax, where you specify a query by chaining together different methods. Two common methods
|
||||
are filter() and sort():
|
||||
are `filter()` and `sort()`:
|
||||
|
||||
:::php
|
||||
$members = Member::get()->filter(array('FirstName' => 'Sam'))->sort('Surname');
|
||||
@ -83,19 +81,18 @@ If you have constructed a query that you know should return a single record, you
|
||||
|
||||
Quiet often you would like to sort a list. Doing this on a list could be done in a few ways.
|
||||
|
||||
If would like to sort the list by FirstName in a ascending way (from A to Z).
|
||||
If would like to sort the list by `FirstName` in a ascending way (from A to Z).
|
||||
|
||||
:::php
|
||||
$member = Member::get()->sort('FirstName');
|
||||
// Or the more expressive way
|
||||
$member = Member::get()->sort('FirstName', 'ASC');
|
||||
$member = Member::get()->sort('FirstName'); // Ascending is implied
|
||||
|
||||
To reverse the sort
|
||||
|
||||
:::php
|
||||
$member = Member::get()->sort('FirstName', 'DESC');
|
||||
|
||||
However you might have several entries with the same FirstName and would like to sort them by FirstName and LastName
|
||||
However you might have several entries with the same `FirstName` and would like to sort them by `FirstName` and `LastName`
|
||||
|
||||
:::php
|
||||
$member = Member::get()->sort(array(
|
||||
@ -395,7 +392,7 @@ Note: Alternatively you can set defaults directly in the database-schema (rather
|
||||
|
||||
Properties defined in *static $db* are automatically casted to their [data-types](data-types) when used in templates.
|
||||
You can also cast the return-values of your custom functions (e.g. your "virtual properties").
|
||||
Calling those functions directly will still return whatever type your php-code generates,
|
||||
Calling those functions directly will still return whatever type your PHP code generates,
|
||||
but using the *obj()*-method or accessing through a template will cast the value according to the $casting-definition.
|
||||
|
||||
:::php
|
||||
@ -594,6 +591,9 @@ This functionality is provided by the `SS_Map` class, which can be used to build
|
||||
$members = Member::get();
|
||||
$map = new SS_Map($members, 'ID', 'FirstName');
|
||||
|
||||
Note: You can also retrieve a single property from all contained records
|
||||
through `[api:SS_List->column()]`.
|
||||
|
||||
## Data Handling
|
||||
|
||||
When saving data through the object model, you don't have to manually escape strings to create SQL-safe commands.
|
||||
|
@ -166,7 +166,7 @@ Objects can be searched through an input field (partially matching one or more f
|
||||
Selecting from the results will add the object to the relation.
|
||||
|
||||
:::php
|
||||
$group = DataObject::get_one('Group');
|
||||
$group = Group::get()->First();
|
||||
$config = GridFieldConfig::create()->addComponent(new GridFieldAddExistingAutocompleter(array('FirstName', 'Surname', 'Email'));
|
||||
$gridField = new GridField('Members', 'Members', $group->Members(), $config);
|
||||
|
||||
|
@ -386,8 +386,7 @@ PHP:
|
||||
:::php
|
||||
class MyController {
|
||||
function autocomplete($request) {
|
||||
$SQL_title = Convert::raw2sql($request->getVar('title'));
|
||||
$results = DataObject::get("Page", "Title = '$SQL_title'");
|
||||
$results = Page::get()->filter("Title", $request->getVar('title'));
|
||||
if(!$results) return new HTTPResponse("Not found", 404);
|
||||
|
||||
// Use HTTPResponse to pass custom status messages
|
||||
|
@ -150,7 +150,7 @@ and [tutorial:3-forms](/tutorials/3-forms).
|
||||
## Updating a page:
|
||||
|
||||
:::php
|
||||
$page = DataObject::get_one("Page", "ParentID = 18");
|
||||
$page = Page::get()->filter("ParentID", 18)->First();
|
||||
$page->Title = "More Serious";
|
||||
$page->writeToStage('Stage');
|
||||
$page->Publish('Stage', 'Live');
|
||||
|
@ -24,6 +24,7 @@ For `[api:MySQLDatabase]`, this will be `[mysql_real_escape_string()](http://de3
|
||||
* DataObject::castedUpdate()
|
||||
* DataObject->Property = 'val', DataObject->setField('Property','val')
|
||||
* DataObject::write()
|
||||
* DataList->byID()
|
||||
* Form->saveInto()
|
||||
* FormField->saveInto()
|
||||
* DBField->saveInto()
|
||||
@ -65,7 +66,7 @@ Example:
|
||||
class MyForm extends Form {
|
||||
public function save($RAW_data, $form) {
|
||||
$SQL_data = Convert::raw2sql($RAW_data); // works recursively on an array
|
||||
$objs = DataObject::get('Player', "Name = '{$SQL_data[name]}'");
|
||||
$objs = Player::get()->where("Name = '{$SQL_data[name]}'");
|
||||
// ...
|
||||
}
|
||||
}
|
||||
@ -80,7 +81,7 @@ Example:
|
||||
class MyController extends Controller {
|
||||
public function myurlaction($RAW_urlParams) {
|
||||
$SQL_urlParams = Convert::raw2sql($RAW_urlParams); // works recursively on an array
|
||||
$objs = DataObject::get('Player', "Name = '{$SQL_data[OtherID]}'");
|
||||
$objs = Player::get()->where("Name = '{$SQL_data[OtherID]}'");
|
||||
// ...
|
||||
}
|
||||
}
|
||||
@ -314,8 +315,8 @@ Below is an example with different ways you would use this casting technique:
|
||||
// cast the 'category' GET variable as an integer
|
||||
$categoryID = (int)$_GET['category'];
|
||||
|
||||
// perform a get_by_id, ensure the ID is an integer before querying
|
||||
return DataObject::get_by_id('CaseStudy', $categoryID);
|
||||
// perform a byID(), which ensures the ID is an integer before querying
|
||||
return CaseStudy::get()->byID($categoryID);
|
||||
}
|
||||
|
||||
|
||||
|
@ -30,7 +30,7 @@ but rather just the returned collection,
|
||||
:::php
|
||||
$myPage = $this->objFromFixture('Page', 'mypage');
|
||||
$myOtherPage = $this->objFromFixture('Page', 'myotherpage');
|
||||
$pages = DataObject::get('Page');
|
||||
$pages = Page::get();
|
||||
// Bad: Assumptions about IDs and their order
|
||||
$this->assertEquals(array(1,2), $pages->column('ID'));
|
||||
// Good: Uses actually created IDs, independent of their order
|
||||
|
@ -406,8 +406,8 @@ control. We can get the data for the news articles by implementing our own funct
|
||||
:::php
|
||||
...
|
||||
public function LatestNews($num=5) {
|
||||
$holder = DataObject::get_one("ArticleHolder");
|
||||
return ($holder) ? DataList::create('ArticlePage')->where('"ParentID" = '.$holder->ID)->sort('Date DESC')->limit($num) : false;
|
||||
$holder = ArticleHolder::get()->First();
|
||||
return ($holder) ? ArticlePage::get()->filter('ParentID', $holder->ID)->sort('Date DESC')->limit($num) : false;
|
||||
}
|
||||
...
|
||||
|
||||
|
@ -321,7 +321,7 @@ then create our graph using a page control in the template. Create the function
|
||||
|
||||
:::php
|
||||
public function BrowserPollResults() {
|
||||
$submissions = DataObject::get('BrowserPollSubmission');
|
||||
$submissions = BrowserPollSubmission::get();
|
||||
$total = $submissions->Count();
|
||||
|
||||
$doSet = new DataObjectSet();
|
||||
@ -341,7 +341,7 @@ then create our graph using a page control in the template. Create the function
|
||||
This introduces a few new concepts, so let's step through it.
|
||||
|
||||
:::php
|
||||
$submissions = DataObject::get('BrowserPollSubmission');
|
||||
$submissions = BrowserPollSubmission::get();
|
||||
|
||||
|
||||
First we get all of the *BrowserPollSubmission*s from the database. This returns the submissions as a
|
||||
|
@ -703,7 +703,7 @@ it *MyProject* for instance.
|
||||
...
|
||||
|
||||
public function MyProject() {
|
||||
return DataObject::get( 'Project', "`MyStudentID` = '{$this->ID}'" );
|
||||
return Project::get()->filter("MyStudentID", $this->ID);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ class GroupedList extends SS_ListDecorator {
|
||||
|
||||
/**
|
||||
* @param string $index
|
||||
* @return ArrayList
|
||||
* @return array
|
||||
*/
|
||||
public function groupBy($index) {
|
||||
$result = array();
|
||||
@ -29,8 +29,11 @@ class GroupedList extends SS_ListDecorator {
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to {@link groupBy()}, but returns
|
||||
* the data in a format which is suitable for usage in templates.
|
||||
*
|
||||
* @param string $index
|
||||
* @param string $children
|
||||
* @param string $children Name of the control under which children can be iterated on
|
||||
* @return ArrayList
|
||||
*/
|
||||
public function GroupedBy($index, $children = 'Children') {
|
||||
|
Loading…
Reference in New Issue
Block a user