Yay, clean arrays

This commit is contained in:
Aaron Carlino 2017-08-03 15:35:09 +12:00
parent eb1695c03d
commit 2414eaeafd
97 changed files with 928 additions and 1341 deletions

View File

@ -103,7 +103,6 @@ Save it as `check.php` into your webroot, and run it as `php check.php` (or open
After using the script (and fixing errors afterwards), please remember to remove it again.
```php
<?php
// Check for whitespace around PHP brackets which show in output,
// and hence can break HTML rendering and HTTP operations.
$path = dirname(__FILE__);

View File

@ -350,8 +350,6 @@ types right now, we will go into much more detail in the [next tutorial](/tutori
Create a new file *HomePage.php* in *mysite/code*. Copy the following code into it:
```php
<?php
use Page;
use PageController;

View File

@ -68,8 +68,7 @@ We'll start with the *ArticlePage* page type. First we create the model, a class
**mysite/code/ArticlePage.php**
```php
<?php
use Page;
use Page;
class ArticlePage extends Page
{
@ -78,8 +77,7 @@ We'll start with the *ArticlePage* page type. First we create the model, a class
```
**mysite/code/ArticlePageController.php**
```php
<?php
use PageController;
use PageController;
class ArticlePageController extends PageController
{
@ -97,8 +95,7 @@ Let's create the *ArticleHolder* page type.
**mysite/code/ArticleHolder.php**
```php
<?php
use Page;
use Page;
class ArticleHolder extends Page
{
@ -107,8 +104,7 @@ Let's create the *ArticleHolder* page type.
```
**mysite/code/ArticleHolderController.php**
```php
<?php
use PageController;
use PageController;
class ArticleHolderController extends PageController
{
@ -136,8 +132,7 @@ the $db array to add extra fields to the database. It would be nice to know when
it. Add a *$db* property definition in the *ArticlePage* class:
```php
<?php
use Page;
use Page;
class ArticlePage extends Page
{
@ -162,8 +157,7 @@ When we rebuild the database, we will see that the *ArticlePage* table has been
To add our new fields to the CMS we have to override the *getCMSFields()* method, which is called by the CMS when it creates the form to edit a page. Add the method to the *ArticlePage* class.
```php
<?php
use Page;
use Page;
class ArticlePage extends Page
{
@ -233,8 +227,7 @@ To make the date field a bit more user friendly, you can add a dropdown calendar
the date field will have the date format defined by your locale.
```php
<?php
use Page;
use Page;
class ArticlePage extends Page
{
@ -488,8 +481,7 @@ Now that we have a complete news section, let's take a look at the staff section
**mysite/code/StaffHolder.php**
```php
<?php
use Page;
use Page;
class StaffHolder extends Page
{
@ -502,8 +494,7 @@ Now that we have a complete news section, let's take a look at the staff section
**mysite/code/StaffHolderController.php**
```php
<?php
use PageController;
use PageController;
class StaffHolderController extends PageController
{
@ -516,8 +507,7 @@ Nothing here should be new. The *StaffPage* page type is more interesting though
**mysite/code/StaffPage.php**
```php
<?php
use SilverStripe\AssetAdmin\Forms\UploadField;
use SilverStripe\AssetAdmin\Forms\UploadField;
use SilverStripe\Assets\Image;
class StaffPage extends Page
@ -542,8 +532,7 @@ Nothing here should be new. The *StaffPage* page type is more interesting though
**mysite/code/StaffPageController.php**
```php
<?php
use PageController;
use PageController;
class StaffPageController extends PageController
{

View File

@ -32,7 +32,7 @@ use SilverStripe\Forms\TextField;
class HomePageController extends PageController
{
private static $allowed_actions = array('BrowserPollForm');
private static $allowed_actions = ['BrowserPollForm'];
// ...
@ -41,14 +41,14 @@ class HomePageController extends PageController
// Create fields
$fields = new FieldList(
new TextField('Name'),
new OptionsetField('Browser', 'Your Favourite Browser', array(
new OptionsetField('Browser', 'Your Favourite Browser', [
'Firefox' => 'Firefox',
'Chrome' => 'Chrome',
'Internet Explorer' => 'Internet Explorer',
'Safari' => 'Safari',
'Opera' => 'Opera',
'Lynx' => 'Lynx'
))
])
);
// Create actions
@ -62,6 +62,7 @@ class HomePageController extends PageController
// ...
}
// ...
```
Let's step through this code.
@ -70,15 +71,16 @@ Let's step through this code.
// Create fields
$fields = new FieldList(
new TextField('Name'),
new OptionsetField('Browser', 'Your Favourite Browser', array(
new OptionsetField('Browser', 'Your Favourite Browser', [
'Firefox' => 'Firefox',
'Chrome' => 'Chrome',
'Internet Explorer' => 'Internet Explorer',
'Safari' => 'Safari',
'Opera' => 'Opera',
'Lynx' => 'Lynx'
))
])
);
```
First we create our form fields.
@ -192,17 +194,16 @@ If you recall, in the [second tutorial](/tutorials/extending_a_basic_site) we sa
**mysite/code/BrowserPollSubmission.php**
```php
<?php
use SilverStripe\ORM\DataObject;
class BrowserPollSubmission extends DataObject
{
private static $db = array(
private static $db = [
'Name' => 'Text',
'Browser' => 'Text'
);
];
}
```
If we then rebuild the database ([http://localhost/your_site_name/dev/build](http://localhost/your_site_name/dev/build)), we will see that the *BrowserPollSubmission* table is created. Now we just need to define 'doBrowserPoll' on *HomePageController*:
@ -324,13 +325,14 @@ public function BrowserPollResults()
$list = new ArrayList();
foreach($submissions->groupBy('Browser') as $browserName => $browserSubmissions) {
$percentage = (int) ($browserSubmissions->Count() / $total * 100);
$list->push(new ArrayData(array(
$list->push(new ArrayData([
'Browser' => $browserName,
'Percentage' => $percentage
)));
]));
}
return $list;
}
```
This code introduces a few new concepts, so let's step through it.
@ -349,11 +351,12 @@ We get the total number of submissions, which is needed to calculate the percent
$list = new ArrayList();
foreach ($submissions->groupBy('Browser') as $browserName => $browserSubmissions) {
$percentage = (int) ($browserSubmissions->Count() / $total * 100);
$list->push(new ArrayData(array(
$list->push(new ArrayData([
'Browser' => $browserName,
'Percentage' => $percentage
)));
]));
}
```
Now we create an empty [ArrayList](api:SilverStripe\ORM\ArrayList) to hold the data we'll pass to the template. Its similar to [DataList](api:SilverStripe\ORM\DataList), but can hold arbitrary objects rather than just DataObject` instances. Then we iterate over the 'Browser' submissions field.

View File

@ -64,14 +64,15 @@ is applied via `FulltextSearchable::enable()`
public function results($data, $form, $request)
{
$data = array(
$data = [
'Results' => $form->getResults(),
'Query' => $form->getSearchQuery(),
'Title' => _t('SearchForm.SearchResults', 'Search Results')
);
return $this->owner->customise($data)->renderWith(array('Page_results', 'Page'));
];
return $this->owner->customise($data)->renderWith(['Page_results', 'Page']);
}
}
```
The code populates an array with the data we wish to pass to the template - the search results, query and title of the page. The final line is a little more complicated.

View File

@ -39,41 +39,38 @@ Let's create the `Student` and `Project` objects.
**mysite/code/Student.php**
```php
<?php
use SilverStripe\ORM\DataObject;
class Student extends DataObject
{
private static $db = array(
private static $db = [
'Name' => 'Varchar',
'University' => 'Varchar',
);
private static $has_one = array(
];
private static $has_one = [
'Project' => 'Project'
);
];
}
```
**mysite/code/Project.php**
```php
<?php
use Page;
class Project extends Page
{
private static $has_many = array(
private static $has_many = [
'Students' => 'Student'
);
];
}
```
**mysite/code/ProjectController.php**
```php
<?php
use PageController;
class ProjectController extends PageController
@ -116,22 +113,19 @@ The restriction is enforced through the `$allowed_children` directive.
**mysite/code/ProjectsHolder.php**
```php
<?php
use Page;
class ProjectsHolder extends Page {
private static $allowed_children = array(
private static $allowed_children = [
'Project'
);
];
}
```
**mysite/code/ProjectsHolderController.php
```php
<?php
use PageController;
class ProjectsHolderController extends PageController
@ -164,8 +158,6 @@ All customization to fields for a page type are managed through a method called
**mysite/code/Project.php**
```php
<?php
use Page;
use SilverStripe\Forms\GridField;
use SilverStripe\Forms\GridField\GridFieldConfig_RelationEditor;
@ -182,10 +174,10 @@ class Project extends Page
// Set the names and data for our gridfield columns
$config
->getComponentByType('SilverStripe\\Forms\\GridField\\GridFieldDataColumns')
->setDisplayFields(array(
->setDisplayFields([
'Name' => 'Name',
'Project.Title'=> 'Project' // Retrieve from a has-one relationship
));
]);
// Create a gridfield to hold the student relationship
$studentsField = new GridField(
'Students', // Field name
@ -198,6 +190,7 @@ class Project extends Page
return $fields;
}
}
```
This creates a tabular field, which lists related student records, one row at a time.
@ -246,35 +239,33 @@ The first step is to create the `Mentor` object and set the relation with the `P
**mysite/code/Mentor.php**
```php
<?php
use SilverStripe\ORM\DataObject;
class Mentor extends DataObject
{
private static $db = array(
private static $db = [
'Name' => 'Varchar',
);
private static $belongs_many_many = array(
];
private static $belongs_many_many = [
'Projects' => 'Project'
);
];
}
```
**mysite/code/Project.php**
```php
<?php
use Page;
class Project extends Page
{
// ...
private static $many_many = array(
private static $many_many = [
'Mentors' => 'Mentor'
);
];
}
```
This code will create a relationship between the `Project` table and the `Mentor` table by storing the ids of the respective `Project` and `Mentor` in a another table named "Project_Mentors"
@ -288,8 +279,6 @@ to configure it a bit differently.
**mysite/code/Project.php**
```php
<?php
use Page;
use SilverStripe\Forms\GridField;
use SilverStripe\Forms\GridField\GridFieldConfig_RelationEditor;

View File

@ -20,18 +20,17 @@ Let's look at a simple example:
**mysite/code/Player.php**
```php
<?php
class Player extends DataObject {
private static $db = array(
private static $db = [
'PlayerNumber' => 'Int',
'FirstName' => 'Varchar(255)',
'LastName' => 'Text',
'Birthday' => 'Date'
);
];
}
```
This `Player` class definition will create a database table `Player` with columns for `PlayerNumber`, `FirstName` and
@ -78,18 +77,17 @@ system. Instead, it will generate a new `ID` by adding 1 to the current maximum
**mysite/code/Player.php**
```php
<?php
class Player extends DataObject {
private static $db = array(
private static $db = [
'PlayerNumber' => 'Int',
'FirstName' => 'Varchar(255)',
'LastName' => 'Text',
'Birthday' => 'Date'
);
];
}
```
Generates the following `SQL`.
@ -113,14 +111,12 @@ Generates the following `SQL`.
A new instance of a [DataObject](api:SilverStripe\ORM\DataObject) can be created using the `new` syntax.
```php
$player = new Player();
```
Or, a better way is to use the `create` method.
```php
$player = Player::create();
```
@ -133,7 +129,6 @@ Database columns and properties can be set as class properties on the object. Th
of the values through a custom `__set()` method.
```php
$player->FirstName = "Sam";
$player->PlayerNumber = 07;
```
@ -142,14 +137,12 @@ To save the `DataObject` to the database, use the `write()` method. The first ti
set.
```php
$player->write();
```
For convenience, the `write()` method returns the record's ID. This is particularly useful when creating new records.
```php
$player = Player::create();
$id = $player->write();
```
@ -160,7 +153,6 @@ With the `Player` class defined we can query our data using the `ORM` or Object-
shortcuts and methods for fetching, sorting and filtering data from our database.
```php
$players = Player::get();
// returns a `DataList` containing all the `Player` objects.
@ -178,12 +170,12 @@ The `ORM` uses a "fluent" syntax, where you specify a query by chaining together
are `filter()` and `sort()`:
```php
$members = Player::get()->filter(array(
$members = Player::get()->filter([
'FirstName' => 'Sam'
))->sort('Surname');
])->sort('Surname');
// returns a `DataList` containing all the `Player` records that have the `FirstName` of 'Sam'
```
<div class="info" markdown="1">
@ -198,28 +190,28 @@ It's smart enough to generate a single efficient query at the last moment in tim
result set in PHP. In `MySQL` the query generated by the ORM may look something like this
```php
$players = Player::get()->filter(array(
$players = Player::get()->filter([
'FirstName' => 'Sam'
));
]);
$players = $players->sort('Surname');
// executes the following single query
// SELECT * FROM Player WHERE FirstName = 'Sam' ORDER BY Surname
```
This also means that getting the count of a list of objects will be done with a single, efficient query.
```php
$players = Player::get()->filter(array(
$players = Player::get()->filter([
'FirstName' => 'Sam'
))->sort('Surname');
])->sort('Surname');
// This will create an single SELECT COUNT query
// SELECT COUNT(*) FROM Player WHERE FirstName = 'Sam'
echo $players->Count();
```
## Looping over a list of objects
@ -227,7 +219,6 @@ This also means that getting the count of a list of objects will be done with a
`get()` returns a `DataList` instance. You can loop over `DataList` instances in both PHP and templates.
```php
$players = Player::get();
foreach($players as $player) {
@ -238,7 +229,6 @@ This also means that getting the count of a list of objects will be done with a
Notice that we can step into the loop safely without having to check if `$players` exists. The `get()` call is robust, and will at worst return an empty `DataList` object. If you do want to check if the query returned any records, you can use the `exists()` method, e.g.
```php
$players = Player::get();
if($players->exists()) {
@ -254,14 +244,12 @@ There are a couple of ways of getting a single DataObject from the ORM. If you k
can use `byID($id)`:
```php
$player = Player::get()->byID(5);
```
`get()` returns a [DataList](api:SilverStripe\ORM\DataList) instance. You can use operations on that to get back a single record.
```php
$players = Player::get();
$first = $players->first();
@ -273,7 +261,6 @@ can use `byID($id)`:
If would like to sort the list by `FirstName` in a ascending way (from A to Z).
```php
// Sort can either be Ascending (ASC) or Descending (DESC)
$players = Player::get()->sort('FirstName', 'ASC');
@ -284,7 +271,6 @@ If would like to sort the list by `FirstName` in a ascending way (from A to Z).
To reverse the sort
```php
$players = Player::get()->sort('FirstName', 'DESC');
// or..
@ -295,17 +281,16 @@ However you might have several entries with the same `FirstName` and would like
`LastName`
```php
$players = Players::get()->sort(array(
$players = Players::get()->sort([
'FirstName' => 'ASC',
'LastName'=>'ASC'
));
]);
```
You can also sort randomly. Using the `DB` class, you can get the random sort method per database type.
```php
$random = DB::get_conn()->random();
$players = Player::get()->sort($random)
```
@ -315,10 +300,10 @@ You can also sort randomly. Using the `DB` class, you can get the random sort me
The `filter()` method filters the list of objects that gets returned.
```php
$players = Player::get()->filter(array(
$players = Player::get()->filter([
'FirstName' => 'Sam'
));
]);
```
Each element of the array specifies a filter. You can specify as many filters as you like, and they **all** must be
@ -330,42 +315,41 @@ value that you want to filter to.
So, this would return only those players called "Sam Minnée".
```php
$players = Player::get()->filter(array(
$players = Player::get()->filter([
'FirstName' => 'Sam',
'LastName' => 'Minnée',
));
]);
// SELECT * FROM Player WHERE FirstName = 'Sam' AND LastName = 'Minnée'
```
There is also a shorthand way of getting Players with the FirstName of Sam.
```php
$players = Player::get()->filter('FirstName', 'Sam');
```
Or if you want to find both Sam and Sig.
```php
$players = Player::get()->filter(
'FirstName', array('Sam', 'Sig')
'FirstName', ['Sam', 'Sig']
);
// SELECT * FROM Player WHERE FirstName IN ('Sam', 'Sig')
```
You can use [SearchFilters](searchfilters) to add additional behavior to your `filter` command rather than an
exact match.
```php
$players = Player::get()->filter(array(
$players = Player::get()->filter([
'FirstName:StartsWith' => 'S'
'PlayerNumber:GreaterThan' => '10'
));
]);
```
### filterAny
@ -373,38 +357,38 @@ exact match.
Use the `filterAny()` method to match multiple criteria non-exclusively (with an "OR" disjunctive),
```php
$players = Player::get()->filterAny(array(
$players = Player::get()->filterAny([
'FirstName' => 'Sam',
'Age' => 17,
));
]);
// SELECT * FROM Player WHERE ("FirstName" = 'Sam' OR "Age" = '17')
```
You can combine both conjunctive ("AND") and disjunctive ("OR") statements.
```php
$players = Player::get()
->filter(array(
->filter([
'LastName' => 'Minnée'
))
->filterAny(array(
])
->filterAny([
'FirstName' => 'Sam',
'Age' => 17,
));
]);
// SELECT * FROM Player WHERE ("LastName" = 'Minnée' AND ("FirstName" = 'Sam' OR "Age" = '17'))
```
You can use [SearchFilters](searchfilters) to add additional behavior to your `filterAny` command.
```php
$players = Player::get()->filterAny(array(
$players = Player::get()->filterAny([
'FirstName:StartsWith' => 'S'
'PlayerNumber:GreaterThan' => '10'
));
]);
```
### Filtering by null values
@ -418,7 +402,6 @@ For instance, the below code will select only values that do not match the given
```php
$players = Player::get()->filter('FirstName:not', 'Sam');
// ... WHERE "FirstName" != 'Sam' OR "FirstName" IS NULL
// Returns rows with any value (even null) other than Sam
@ -428,21 +411,21 @@ If null values should be excluded, include the null in your check.
```php
$players = Player::get()->filter('FirstName:not', array('Sam', null));
$players = Player::get()->filter('FirstName:not', ['Sam', null]);
// ... WHERE "FirstName" != 'Sam' AND "FirstName" IS NOT NULL
// Only returns non-null values for "FirstName" that aren't Sam.
// Strictly the IS NOT NULL isn't necessary, but is included for explicitness
```
It is also often useful to filter by all rows with either empty or null for a given field.
```php
$players = Player::get()->filter('FirstName', array(null, ''));
$players = Player::get()->filter('FirstName', [null, '']);
// ... WHERE "FirstName" == '' OR "FirstName" IS NULL
// Returns rows with FirstName which is either empty or null
```
### Filtering by aggregates
@ -480,7 +463,6 @@ for each record, if the callback returns true, this record will be added to the
The below example will get all `Players` aged over 10.
```php
$players = Player::get()->filterByCallback(function($item, $list) {
return ($item->Age() > 10);
});
@ -491,7 +473,6 @@ The below example will get all `Players` aged over 10.
The `exclude()` method is the opposite to the filter in that it removes entries from a list.
```php
$players = Player::get()->exclude('FirstName', 'Sam');
// SELECT * FROM Player WHERE FirstName != 'Sam'
@ -500,42 +481,42 @@ The `exclude()` method is the opposite to the filter in that it removes entries
Remove both Sam and Sig..
```php
$players = Player::get()->exclude(
'FirstName', array('Sam','Sig')
'FirstName', ['Sam','Sig']
);
```
`Exclude` follows the same pattern as filter, so for removing only Sam Minnée from the list:
```php
$players = Player::get()->exclude(array(
$players = Player::get()->exclude([
'FirstName' => 'Sam',
'Surname' => 'Minnée',
));
]);
```
And removing Sig and Sam with that are either age 17 or 43.
```php
$players = Player::get()->exclude(array(
'FirstName' => array('Sam', 'Sig'),
'Age' => array(17, 43)
));
$players = Player::get()->exclude([
'FirstName' => ['Sam', 'Sig'],
'Age' => [17, 43]
]);
// SELECT * FROM Player WHERE ("FirstName" NOT IN ('Sam','Sig) OR "Age" NOT IN ('17', '43'));
```
You can use [SearchFilters](searchfilters) to add additional behavior to your `exclude` command.
```php
$players = Player::get()->exclude(array(
$players = Player::get()->exclude([
'FirstName:EndsWith' => 'S'
'PlayerNumber:LessThanOrEqual' => '10'
));
]);
```
### Subtract
@ -543,7 +524,6 @@ You can use [SearchFilters](searchfilters) to add additional behavior to your `e
You can subtract entries from a [DataList](api:SilverStripe\ORM\DataList) by passing in another DataList to `subtract()`
```php
$sam = Player::get()->filter('FirstName', 'Sam');
$players = Player::get();
@ -554,7 +534,6 @@ Though for the above example it would probably be easier to use `filter()` and `
when you want to find all the members that does not exist in a Group.
```php
// ... Finding all members that does not belong to $group.
$otherMembers = Member::get()->subtract($group->Members());
```
@ -564,7 +543,6 @@ when you want to find all the members that does not exist in a Group.
You can limit the amount of records returned in a DataList by using the `limit()` method.
```php
$members = Member::get()->limit(5);
```
@ -573,7 +551,6 @@ parameter to specify the offset, which allows you to tell the system where to st
offset, if not provided as an argument, will default to 0.
```php
// Return 10 members with an offset of 4 (starting from the 5th result).
$members = Member::get()->sort('Surname')->limit(10, 4);
```
@ -592,7 +569,6 @@ For instance, the below model will be stored in the table name `BannerImage`
```php
namespace SilverStripe\BannerManager;
class BannerImage extends \DataObject {
private static $table_name = 'BannerImage';
@ -627,7 +603,6 @@ table and column.
```php
public function countDuplicates($model, $fieldToCheck) {
$table = DataObject::getSchema()->tableForField($model, $field);
$query = new SQLSelect();
@ -654,7 +629,6 @@ you need it to, you may also consider extending the ORM with new data types or f
You can specify a WHERE clause fragment (that will be combined with other filters using AND) with the `where()` method:
```php
$members = Member::get()->where("\"FirstName\" = 'Sam'")
```
@ -667,7 +641,6 @@ You can specify a join with the `innerJoin` and `leftJoin` methods. Both of the
* An optional alias.
```php
// Without an alias
$members = Member::get()
->leftJoin("Group_Members", "\"Group_Members\".\"MemberID\" = \"Member\".\"ID\"");
@ -687,15 +660,14 @@ Define the default values for all the `$db` fields. This example sets the "Statu
whenever a new object is created.
```php
<?php
class Player extends DataObject {
private static $defaults = array(
private static $defaults = [
"Status" => 'Active',
);
];
}
```
<div class="notice" markdown='1'>
@ -713,19 +685,18 @@ time.
For example, suppose we have the following set of classes:
```php
<?php
class Page extends SiteTree {
}
class NewsPage extends Page {
private static $db = array(
private static $db = [
'Summary' => 'Text'
);
];
}
```
The data for the following classes would be stored across the following tables:
@ -747,7 +718,6 @@ The data for the following classes would be stored across the following tables:
Accessing the data is transparent to the developer.
```php
$news = NewsPage::get();
foreach($news as $article) {

View File

@ -16,26 +16,25 @@ A 1-to-1 relation creates a database-column called "`<relationship-name>`ID", in
"TeamID" on the "Player"-table.
```php
<?php
class Team extends DataObject {
private static $db = array(
private static $db = [
'Title' => 'Varchar'
);
];
private static $has_many = array(
private static $has_many = [
'Players' => 'Player'
);
];
}
class Player extends DataObject {
private static $has_one = array(
private static $has_one = [
"Team" => "Team",
);
];
}
```
This defines a relationship called `Team` which links to a `Team` class. The `ORM` handles navigating the relationship
@ -44,7 +43,6 @@ and provides a short syntax for accessing the related object.
At the database level, the `has_one` creates a `TeamID` field on `Player`. A `has_many` field does not impose any database changes. It merely injects a new method into the class to access the related records (in this case, `Players()`)
```php
$player = Player::get()->byId(1);
$team = $player->Team();
@ -77,28 +75,27 @@ To specify that a has_one relation is polymorphic set the type to 'DataObject'.
Ideally, the associated has_many (or belongs_to) should be specified with dot notation.
```php
class Player extends DataObject {
private static $has_many = array(
private static $has_many = [
"Fans" => "Fan.FanOf"
);
];
}
class Team extends DataObject {
private static $has_many = array(
private static $has_many = [
"Fans" => "Fan.FanOf"
);
];
}
// Type of object returned by $fan->FanOf() will vary
class Fan extends DataObject {
// Generates columns FanOfID and FanOfClass
private static $has_one = array(
private static $has_one = [
"FanOf" => "DataObject"
);
];
}
```
<div class="warning" markdown='1'>
@ -119,33 +116,31 @@ available on both ends.
</div>
```php
<?php
class Team extends DataObject {
private static $db = array(
private static $db = [
'Title' => 'Varchar'
);
];
private static $has_many = array(
private static $has_many = [
'Players' => 'Player'
);
];
}
class Player extends DataObject {
private static $has_one = array(
private static $has_one = [
"Team" => "Team",
);
];
}
```
Much like the `has_one` relationship, `has_many` can be navigated through the `ORM` as well. The only difference being
you will get an instance of [HasManyList](api:SilverStripe\ORM\HasManyList) rather than the object.
```php
$team = Team::get()->first();
echo $team->Players();
@ -162,24 +157,23 @@ you will get an instance of [HasManyList](api:SilverStripe\ORM\HasManyList) rath
To specify multiple `$has_many` to the same object you can use dot notation to distinguish them like below:
```php
<?php
class Person extends DataObject {
private static $has_many = array(
private static $has_many = [
"Managing" => "Company.Manager",
"Cleaning" => "Company.Cleaner",
);
];
}
class Company extends DataObject {
private static $has_one = array(
private static $has_one = [
"Manager" => "Person",
"Cleaner" => "Person"
);
];
}
```
Multiple `$has_one` relationships are okay if they aren't linking to the same object type. Otherwise, they have to be
@ -207,22 +201,21 @@ Similarly with `$has_many`, dot notation can be used to explicitly specify the `
This is not mandatory unless the relationship would be otherwise ambiguous.
```php
<?php
class Team extends DataObject {
private static $has_one = array(
private static $has_one = [
'Coach' => 'Coach'
);
];
}
class Coach extends DataObject {
private static $belongs_to = array(
private static $belongs_to = [
'Team' => 'Team.Coach'
);
];
}
```
## many_many
@ -241,7 +234,6 @@ The only difference being you will get an instance of [ManyManyList](api:SilverS
[ManyManyThroughList](api:SilverStripe\ORM\ManyManyThroughList) rather than the object.
```php
$team = Team::get()->byId(1);
$supporters = $team->Supporters();
@ -259,9 +251,7 @@ config to add extra columns.
```php
<?php
class Team extends DataObject {
private static $many_many = [
"Supporters" => "Supporter",
@ -304,9 +294,7 @@ or child record.
The syntax for `belongs_many_many` is unchanged.
```php
<?php
class Team extends DataObject {
private static $many_many = [
"Supporters" => [
@ -340,7 +328,6 @@ for any sql conditions.
```php
$team = Team::get()->byId(1);
$supporters = $team->Supporters()->where(['"TeamSupporter"."Ranking"' => 1]);
```
@ -376,24 +363,23 @@ distinguish them like below:
```php
<?php
class Category extends DataObject {
private static $many_many = array(
private static $many_many = [
'Products' => 'Product',
'FeaturedProducts' => 'Product'
);
];
}
class Product extends DataObject {
private static $belongs_many_many = array(
private static $belongs_many_many = [
'Categories' => 'Category.Products',
'FeaturedInCategories' => 'Category.FeaturedProducts'
);
];
}
```
If you're unsure about whether an object should take on `many_many` or `belongs_many_many`,
@ -409,7 +395,6 @@ encapsulated by [HasManyList](api:SilverStripe\ORM\HasManyList) and [ManyManyLis
and `remove()` method.
```php
$team = Team::get()->byId(1);
// create a new supporter
@ -429,19 +414,18 @@ You can use the ORM to get a filtered result list without writing any SQL. For e
See [DataObject::$has_many](api:SilverStripe\ORM\DataObject::$has_many) for more info on the described relations.
```php
<?php
class Team extends DataObject {
private static $has_many = array(
private static $has_many = [
"Players" => "Player"
);
];
public function ActivePlayers() {
return $this->Players()->filter('Status', 'Active');
}
}
```
<div class="notice" markdown="1">

View File

@ -12,7 +12,6 @@ modify.
[SS_List](api:SilverStripe\ORM\SS_List) implements `IteratorAggregate`, allowing you to loop over the instance.
```php
$members = Member::get();
foreach($members as $member) {
@ -32,7 +31,6 @@ Or in the template engine:
## Finding an item by value.
```php
// $list->find($key, $value);
//
@ -47,7 +45,6 @@ Or in the template engine:
A map is an array where the array indexes contain data as well as the values. You can build a map from any list
```php
$members = Member::get()->map('ID', 'FirstName');
// $members = array(
@ -55,12 +52,12 @@ A map is an array where the array indexes contain data as well as the values. Yo
// 2 => 'Sig'
// 3 => 'Will'
// );
```
This functionality is provided by the [Map](api:SilverStripe\ORM\Map) class, which can be used to build a map around any `SS_List`.
```php
$members = Member::get();
$map = new Map($members, 'ID', 'FirstName');
```
@ -68,7 +65,6 @@ This functionality is provided by the [Map](api:SilverStripe\ORM\Map) class, whi
## Column
```php
$members = Member::get();
echo $members->column('Email');
@ -78,6 +74,7 @@ This functionality is provided by the [Map](api:SilverStripe\ORM\Map) class, whi
// 'sig@silverstripe.com',
// 'will@silverstripe.com'
// );
```
## ArrayList
@ -85,7 +82,6 @@ This functionality is provided by the [Map](api:SilverStripe\ORM\Map) class, whi
[ArrayList](api:SilverStripe\ORM\ArrayList) exists to wrap a standard PHP array in the same API as a database backed list.
```php
$sam = Member::get()->byId(5);
$sig = Member::get()->byId(6);
@ -95,6 +91,7 @@ This functionality is provided by the [Map](api:SilverStripe\ORM\Map) class, whi
echo $list->Count();
// returns '2'
```
## API Documentation

View File

@ -14,18 +14,17 @@ In the `Player` example, we have four database columns each with a different dat
**mysite/code/Player.php**
```php
<?php
class Player extends DataObject {
private static $db = array(
private static $db = [
'PlayerNumber' => 'Int',
'FirstName' => 'Varchar(255)',
'LastName' => 'Text',
'Birthday' => 'Date'
);
];
}
```
## Available Types
@ -54,21 +53,20 @@ For complex default values for newly instantiated objects see [Dynamic Default V
For simple values you can make use of the `$defaults` array. For example:
```php
<?php
class Car extends DataObject {
private static $db = array(
private static $db = [
'Wheels' => 'Int',
'Condition' => 'Enum(array("New","Fair","Junk"))'
);
];
private static $defaults = array(
private static $defaults = [
'Wheels' => 4,
'Condition' => 'New'
);
];
}
```
### Default values for new database columns
@ -86,17 +84,16 @@ For enum values, it's the second parameter.
For example:
```php
<?php
class Car extends DataObject {
private static $db = array(
private static $db = [
'Wheels' => 'Int(4)',
'Condition' => 'Enum(array("New","Fair","Junk"), "New")',
'Make' => 'Varchar(["default" => "Honda"]),
);
}
```
## Formatting Output
@ -110,9 +107,7 @@ object we can control the formatting and it allows us to call methods defined fr
**mysite/code/Player.php**
```php
<?php
class Player extends DataObject {
..
@ -126,7 +121,6 @@ object we can control the formatting and it allows us to call methods defined fr
Then we can refer to a new `Name` column on our `Player` instances. In templates we don't need to use the `get` prefix.
```php
$player = Player::get()->byId(1);
echo $player->Name;
@ -144,19 +138,18 @@ Then we can refer to a new `Name` column on our `Player` instances. In templates
Rather than manually returning objects from your custom functions. You can use the `$casting` property.
```php
<?php
class Player extends DataObject {
private static $casting = array(
private static $casting = [
"Name" => 'Varchar',
);
];
public function getName() {
return $this->FirstName . ' '. $this->LastName;
}
}
```
The properties on any SilverStripe object can be type casted automatically, by transforming its scalar value into an
@ -167,7 +160,6 @@ On the most basic level, the class can be used as simple conversion class from o
number.
```php
DBField::create_field('Double', 1.23456)->Round(2); // results in 1.23
```
@ -175,7 +167,6 @@ Of course that's much more verbose than the equivalent PHP call. The power of [D
sophisticated helpers, like showing the time difference to the current date:
```php
DBField::create_field('Date', '1982-01-01')->TimeDiff(); // shows "30 years ago"
```
@ -185,14 +176,12 @@ Most objects in SilverStripe extend from [ViewableData](api:SilverStripe\View\Vi
context. Through a `$casting` array, arbitrary properties and getters can be casted:
```php
<?php
class MyObject extends ViewableData {
private static $casting = array(
private static $casting = [
'MyDate' => 'Date'
);
];
public function getMyDate() {
return '1982-01-01';
@ -204,6 +193,7 @@ context. Through a `$casting` array, arbitrary properties and getters can be cas
$obj->MyDate; // returns string
$obj->obj('MyDate'); // returns object
$obj->obj('MyDate')->InPast(); // returns boolean
```
## Casting HTML Text
@ -225,18 +215,17 @@ The following example will use the result of `getStatus` instead of the 'Status'
database column using `dbObject`.
```php
<?php
class Player extends DataObject {
private static $db = array(
private static $db = [
"Status" => "Enum(array('Active', 'Injured', 'Retired'))"
);
];
public function getStatus() {
return (!$this->obj("Birthday")->InPast()) ? "Unborn" : $this->dbObject('Status')->Value();
}
```
## API Documentation

View File

@ -19,14 +19,12 @@ a `ModelAdmin` record.
Example: Disallow creation of new players if the currently logged-in player is not a team-manager.
```php
<?php
class Player extends DataObject {
private static $has_many = array(
private static $has_many = [
"Teams"=>"Team"
);
];
public function onBeforeWrite() {
// check on first write action, aka "database row creation" (ID-property is not set)
@ -50,6 +48,7 @@ Example: Disallow creation of new players if the currently logged-in player is n
parent::onBeforeWrite();
}
}
```
## onBeforeDelete
@ -60,14 +59,12 @@ Example: Checking for a specific [permission](permissions) to delete this type o
member is logged in who belongs to a group containing the permission "PLAYER_DELETE".
```php
<?php
class Player extends DataObject {
private static $has_many = array(
private static $has_many = [
"Teams" => "Team"
);
];
public function onBeforeDelete() {
if(!Permission::check('PLAYER_DELETE')) {
@ -78,6 +75,7 @@ member is logged in who belongs to a group containing the permission "PLAYER_DEL
parent::onBeforeDelete();
}
}
```
<div class="notice" markdown='1'>

View File

@ -17,18 +17,18 @@ you can put on field names to change this behavior. These are represented as `Se
An example of a `SearchFilter` in use:
```php
// fetch any player that starts with a S
$players = Player::get()->filter(array(
$players = Player::get()->filter([
'FirstName:StartsWith' => 'S',
'PlayerNumber:GreaterThan' => '10'
));
]);
// to fetch any player that's name contains the letter 'z'
$players = Player::get()->filterAny(array(
$players = Player::get()->filterAny([
'FirstName:PartialMatch' => 'z',
'LastName:PartialMatch' => 'z'
));
]);
```
Developers can define their own [SearchFilter](api:SilverStripe\ORM\Filters\SearchFilter) if needing to extend the ORM filter and exclude behaviors.
@ -53,15 +53,15 @@ config:
The following is a query which will return everyone whose first name starts with "S", either lowercase or uppercase:
```php
$players = Player::get()->filter(array(
$players = Player::get()->filter([
'FirstName:StartsWith:nocase' => 'S'
));
]);
// use :not to perform a converse operation to filter anything but a 'W'
$players = Player::get()->filter(array(
$players = Player::get()->filter([
'FirstName:StartsWith:not' => 'W'
));
]);
```
## API Documentation

View File

@ -17,9 +17,7 @@ code.
</div>
```php
<?php
class MyDataObject extends DataObject {
public function canView($member = null) {

View File

@ -19,7 +19,6 @@ For example, if you want to run a simple `COUNT` SQL statement,
the following three statements are functionally equivalent:
```php
// Through raw SQL.
$count = DB::query('SELECT COUNT(*) FROM "Member"')->value();
@ -59,15 +58,13 @@ conditional filters, grouping, limiting, and sorting.
E.g.
```php
<?php
$sqlQuery = new SQLSelect();
$sqlQuery->setFrom('Player');
$sqlQuery->selectField('FieldName', 'Name');
$sqlQuery->selectField('YEAR("Birthday")', 'Birthyear');
$sqlQuery->addLeftJoin('Team','"Player"."TeamID" = "Team"."ID"');
$sqlQuery->addWhere(array('YEAR("Birthday") = ?' => 1982));
$sqlQuery->addWhere(['YEAR("Birthday") = ?' => 1982]);
// $sqlQuery->setOrderBy(...);
// $sqlQuery->setGroupBy(...);
// $sqlQuery->setHaving(...);
@ -84,6 +81,7 @@ E.g.
foreach($result as $row) {
echo $row['BirthYear'];
}
```
The result of `SQLSelect::execute()` is an array lightly wrapped in a database-specific subclass of [Query](api:SilverStripe\ORM\Connect\Query).
@ -98,35 +96,32 @@ object instead.
For example, creating a `SQLDelete` object
```php
<?php
$query = SQLDelete::create()
->setFrom('"SiteTree"')
->setWhere(array('"SiteTree"."ShowInMenus"' => 0));
->setWhere(['"SiteTree"."ShowInMenus"' => 0]);
$query->execute();
```
Alternatively, turning an existing `SQLQuery` into a delete
```php
<?php
$query = SQLQuery::create()
->setFrom('"SiteTree"')
->setWhere(array('"SiteTree"."ShowInMenus"' => 0))
->setWhere(['"SiteTree"."ShowInMenus"' => 0])
->toDelete();
$query->execute();
```
Directly querying the database
```php
DB::prepared_query('DELETE FROM "SiteTree" WHERE "SiteTree"."ShowInMenus" = ?', [0]);
<?php
DB::prepared_query('DELETE FROM "SiteTree" WHERE "SiteTree"."ShowInMenus" = ?', array(0));
```
### INSERT/UPDATE
@ -174,31 +169,30 @@ SQLInsert also includes the following api methods:
E.g.
```php
<?php
$update = SQLUpdate::create('"SiteTree"')->addWhere(array('ID' => 3));
$update = SQLUpdate::create('"SiteTree"')->addWhere(['ID' => 3]);
// assigning a list of items
$update->addAssignments(array(
$update->addAssignments([
'"Title"' => 'Our Products',
'"MenuTitle"' => 'Products'
));
]);
// Assigning a single value
$update->assign('"MenuTitle"', 'Products');
// Assigning a value using parameterised expression
$title = 'Products';
$update->assign('"MenuTitle"', array(
$update->assign('"MenuTitle"', [
'CASE WHEN LENGTH("MenuTitle") > LENGTH(?) THEN "MenuTitle" ELSE ? END' =>
array($title, $title)
));
[$title, $title]
]);
// Assigning a value using a pure SQL expression
$update->assignSQL('"Date"', 'NOW()');
// Perform the update
$update->execute();
```
In addition to assigning values, the SQLInsert object also supports multi-row
@ -208,27 +202,26 @@ these are translated internally as multiple single row inserts.
For example,
```php
<?php
$insert = SQLInsert::create('"SiteTree"');
$insert = SQLInsert::create('"SiteTree"');
// Add multiple rows in a single call. Note that column names do not need
// to be symmetric
$insert->addRows(array(
array('"Title"' => 'Home', '"Content"' => '<p>This is our home page</p>'),
array('"Title"' => 'About Us', '"ClassName"' => 'AboutPage')
));
$insert->addRows([
['"Title"' => 'Home', '"Content"' => '<p>This is our home page</p>'],
['"Title"' => 'About Us', '"ClassName"' => 'AboutPage']
]);
// Adjust an assignment on the last row
$insert->assign('"Content"', '<p>This is about us</p>');
// Add another row
$insert->addRow(array('"Title"' => 'Contact Us'));
$insert->addRow(['"Title"' => 'Contact Us']);
$columns = $insert->getColumns();
// $columns will be array('"Title"', '"Content"', '"ClassName"');
$insert->execute();
```
### Value Checks
@ -239,19 +232,18 @@ e.g. when you want a single column rather than a full-blown object representatio
Example: Get the count from a relationship.
```php
$sqlQuery = new SQLSelect();
$sqlQuery->setFrom('Player');
$sqlQuery->addSelect('COUNT("Player"."ID")');
$sqlQuery->addWhere(array('"Team"."ID"' => 99));
$sqlQuery->addWhere(['"Team"."ID"' => 99]);
$sqlQuery->addLeftJoin('Team', '"Team"."ID" = "Player"."TeamID"');
$count = $sqlQuery->execute()->value();
```
Note that in the ORM, this call would be executed in an efficient manner as well:
```php
$count = $myTeam->Players()->count();
```
@ -263,7 +255,6 @@ This can be useful for creating dropdowns.
Example: Show player names with their birth year, but set their birth dates as values.
```php
$sqlQuery = new SQLSelect();
$sqlQuery->setFrom('Player');
$sqlQuery->setSelect('Birthdate');
@ -277,18 +268,18 @@ because of the custom SQL value transformation (`YEAR()`).
An alternative approach would be a custom getter in the object definition.
```php
class Player extends DataObject {
private static $db = array(
private static $db = [
'Name' => 'Varchar',
'Birthdate' => 'Date'
);
];
function getNameWithBirthyear() {
return date('y', $this->Birthdate);
}
}
$players = Player::get();
$map = $players->map('Name', 'NameWithBirthyear');
```
## Related

View File

@ -22,15 +22,13 @@ write, and respond appropriately if it isn't.
The return value of `validate()` is a [ValidationResult](api:SilverStripe\ORM\ValidationResult) object.
```php
<?php
class MyObject extends DataObject {
private static $db = array(
private static $db = [
'Country' => 'Varchar',
'Postcode' => 'Varchar'
);
];
public function validate() {
$result = parent::validate();
@ -42,6 +40,7 @@ The return value of `validate()` is a [ValidationResult](api:SilverStripe\ORM\Va
return $result;
}
}
```
## API Documentation

View File

@ -21,7 +21,6 @@ also track versioned history.
```php
class MyStagedModel extends DataObject {
private static $extensions = [
Versioned::class
@ -34,7 +33,6 @@ can be specified by setting the constructor argument to "Versioned"
```php
class VersionedModel extends DataObject {
private static $extensions = [
"SilverStripe\\ORM\\Versioning\\Versioned('Versioned')"
@ -82,7 +80,6 @@ By default, all records are retrieved from the "Draft" stage (so the `MyRecord`
explicitly request a certain stage through various getters on the `Versioned` class.
```php
// Fetching multiple records
$stageRecords = Versioned::get_by_stage('MyRecord', Versioned::DRAFT);
$liveRecords = Versioned::get_by_stage('MyRecord', Versioned::LIVE);
@ -98,7 +95,6 @@ The above commands will just retrieve the latest version of its respective stage
in the `<class>_versions` tables.
```php
$historicalRecord = Versioned::get_version('MyRecord', <record-id>, <version-id>);
```
@ -112,7 +108,6 @@ objects, which expose the same database information as a `DataObject`, but also
a record was published.
```php
$record = MyRecord::get()->byID(99); // stage doesn't matter here
$versions = $record->allVersions();
echo $versions->First()->Version; // instance of Versioned_Version
@ -139,7 +134,6 @@ done via one of several ways:
See "DataObject ownership" for reference on dependant objects.
```php
$record = Versioned::get_by_stage('MyRecord', Versioned::DRAFT)->byID(99);
$record->MyField = 'changed';
// will update `MyRecord` table (assuming Versioned::current_stage() == 'Stage'),
@ -152,7 +146,6 @@ done via one of several ways:
Similarly, an "unpublish" operation does the reverse, and removes a record from a specific stage.
```php
$record = MyRecord::get()->byID(99); // stage doesn't matter here
// will remove the row from the `MyRecord_Live` table
$record->deleteFromStage(Versioned::LIVE);
@ -164,7 +157,6 @@ The current stage is stored as global state on the object. It is usually modifie
is initialized. But it can also be set and reset temporarily to force a specific operation to run on a certain stage.
```php
$origMode = Versioned::get_reading_mode(); // save current mode
$obj = MyRecord::getComplexObjectRetrieval(); // returns 'Live' records
Versioned::set_reading_mode(Versioned::DRAFT); // temporarily overwrite mode
@ -192,28 +184,28 @@ without requiring any custom code.
```php
class MyPage extends Page {
private static $has_many = array(
private static $has_many = [
'Banners' => Banner::class
);
private static $owns = array(
];
private static $owns = [
'Banners'
);
];
}
class Banner extends Page {
private static $extensions = array(
private static $extensions = [
Versioned::class
);
private static $has_one = array(
];
private static $has_one = [
'Parent' => MyPage::class,
'Image' => Image::class,
);
private static $owns = array(
];
private static $owns = [
'Image'
);
];
}
```
Note that ownership cannot be used with polymorphic relations. E.g. has_one to non-type specific `DataObject`.
@ -232,29 +224,29 @@ that can be used to traverse between each, and then by ensuring you configure bo
E.g.
```php
class MyParent extends DataObject {
private static $extensions = array(
private static $extensions = [
Versioned::class
);
private static $owns = array(
];
private static $owns = [
'ChildObjects'
);
];
public function ChildObjects() {
return MyChild::get();
}
}
class MyChild extends DataObject {
private static $extensions = array(
private static $extensions = [
Versioned::class
);
private static $owned_by = array(
];
private static $owned_by = [
'Parent'
);
];
public function Parent() {
return MyParent::get()->first();
}
}
```
#### DataObject Ownership in HTML Content
@ -275,7 +267,6 @@ smaller modifications of the generated `DataList` objects.
Example: Get the first 10 live records, filtered by creation date:
```php
$records = Versioned::get_by_stage('MyRecord', Versioned::LIVE)->limit(10)->sort('Created', 'ASC');
```
@ -300,11 +291,10 @@ Versioned object visibility can be customised in one of the following ways by ed
E.g.
```php
class MyObject extends DataObject {
private static $extensions = array(
private static $extensions = [
Versioned::class,
);
];
public function canViewVersioned($member = null) {
// Check if site is live
@ -318,6 +308,7 @@ E.g.
return Permission::checkMember($member, 'ADMIN');
}
}
```
If you want to control permissions of an object in an extension, you can also use
@ -332,7 +323,6 @@ only be invoked if the object is in a non-published state.
E.g.
```php
class MyObjectExtension extends DataExtension {
public function canViewNonLive($member = null) {
return Permission::check($member, 'DRAFT_STATUS');
@ -346,13 +336,13 @@ permissions in the `TargetObject.non_live_permissions` config.
E.g.
```php
class MyObject extends DataObject {
private static $extensions = array(
private static $extensions = [
Versioned::class,
);
private static $non_live_permissions = array('ADMIN');
];
private static $non_live_permissions = ['ADMIN'];
}
```
Versioned applies no additional permissions to `canEdit` or `canCreate`, and such
@ -371,7 +361,6 @@ to force a specific stage, we recommend the `Controller->init()` method for this
**mysite/code/MyController.php**
```php
public function init() {
parent::init();
Versioned::set_stage(Versioned::DRAFT);

View File

@ -13,16 +13,14 @@ customise those fields as required.
An example is `DataObject`, SilverStripe will automatically create your CMS interface so you can modify what you need.
```php
<?php
class MyDataObject extends DataObject {
private static $db = array(
private static $db = [
'IsActive' => 'Boolean',
'Title' => 'Varchar',
'Content' => 'Text'
);
];
public function getCMSFields() {
// parent::getCMSFields() does all the hard work and creates the fields for Title, IsActive and Content.
@ -32,14 +30,13 @@ An example is `DataObject`, SilverStripe will automatically create your CMS inte
return $fields;
}
}
```
To fully customise your form fields, start with an empty FieldList.
```php
<?php
public function getCMSFields() {
$fields = FieldList::create(
TabSet::create("Root.Main",
@ -63,16 +60,15 @@ The `$searchable_fields` property uses a mixed array format that can be used to
system. The default is a set of array values listing the fields.
```php
<?php
class MyDataObject extends DataObject {
private static $searchable_fields = array(
private static $searchable_fields = [
'Name',
'ProductCode'
);
];
}
```
Searchable fields will be appear in the search interface with a default form field (usually a [TextField](api:SilverStripe\Forms\TextField)) and a
@ -80,74 +76,71 @@ default search filter assigned (usually an [ExactMatchFilter](api:SilverStripe\O
additional information on `$searchable_fields`:
```php
<?php
class MyDataObject extends DataObject {
private static $searchable_fields = array(
private static $searchable_fields = [
'Name' => 'PartialMatchFilter',
'ProductCode' => 'NumericField'
);
];
}
```
If you assign a single string value, you can set it to be either a [FormField](api:SilverStripe\Forms\FormField) or [SearchFilter](api:SilverStripe\ORM\Filters\SearchFilter). To specify
both, you can assign an array:
```php
<?php
class MyDataObject extends DataObject {
private static $searchable_fields = array(
'Name' => array(
private static $searchable_fields = [
'Name' => [
'field' => 'TextField',
'filter' => 'PartialMatchFilter',
),
'ProductCode' => array(
],
'ProductCode' => [
'title' => 'Product code #',
'field' => 'NumericField',
'filter' => 'PartialMatchFilter',
),
);
],
];
}
```
To include relations (`$has_one`, `$has_many` and `$many_many`) in your search, you can use a dot-notation.
```php
<?php
class Team extends DataObject {
private static $db = array(
private static $db = [
'Title' => 'Varchar'
);
];
private static $many_many = array(
private static $many_many = [
'Players' => 'Player'
);
];
private static $searchable_fields = array(
private static $searchable_fields = [
'Title',
'Players.Name',
);
];
}
class Player extends DataObject {
private static $db = array(
private static $db = [
'Name' => 'Varchar',
'Birthday' => 'Date'
);
];
private static $belongs_many_many = array(
private static $belongs_many_many = [
'Teams' => 'Team'
);
];
}
```
### Summary Fields
@ -156,77 +149,74 @@ Summary fields can be used to show a quick overview of the data for a specific [
is their display as table columns, e.g. in the search results of a [ModelAdmin](api:SilverStripe\Admin\ModelAdmin) CMS interface.
```php
<?php
class MyDataObject extends DataObject {
private static $db = array(
private static $db = [
'Name' => 'Text',
'OtherProperty' => 'Text',
'ProductCode' => 'Int',
);
];
private static $summary_fields = array(
private static $summary_fields = [
'Name',
'ProductCode'
);
];
}
```
To include relations or field manipulations in your summaries, you can use a dot-notation.
```php
<?php
class OtherObject extends DataObject {
private static $db = array(
private static $db = [
'Title' => 'Varchar'
);
];
}
class MyDataObject extends DataObject {
private static $db = array(
private static $db = [
'Name' => 'Text',
'Description' => 'HTMLText'
);
];
private static $has_one = array(
private static $has_one = [
'OtherObject' => 'OtherObject'
);
];
private static $summary_fields = array(
private static $summary_fields = [
'Name' => 'Name',
'Description.Summary' => 'Description (summary)',
'OtherObject.Title' => 'Other Object Title'
);
];
}
```
Non-textual elements (such as images and their manipulations) can also be used in summaries.
```php
<?php
class MyDataObject extends DataObject {
private static $db = array(
private static $db = [
'Name' => 'Text'
);
];
private static $has_one = array(
private static $has_one = [
'HeroImage' => 'Image'
);
];
private static $summary_fields = array(
private static $summary_fields = [
'Name' => 'Name',
'HeroImage.CMSThumbnail' => 'Hero Image'
);
];
}
```
## Related Documentation

View File

@ -25,9 +25,7 @@ Indexes are represented on a `DataObject` through the `DataObject::$indexes` arr
descriptor. There are several supported notations:
```php
<?php
class MyObject extends DataObject {
private static $indexes = [
@ -55,9 +53,7 @@ support the following:
**mysite/code/MyTestObject.php**
```php
<?php
class MyTestObject extends DataObject {
private static $db = [

View File

@ -39,9 +39,9 @@ will be used both for grouping and for the title in the template.
class Module extends DataObject
{
private static $db = array(
private static $db = [
'Title' => 'Text'
);
];
/**
* Returns the first letter of the module title, used for grouping.
@ -52,6 +52,7 @@ will be used both for grouping and for the title in the template.
return $this->Title[0];
}
}
```
The next step is to create a method or variable that will contain/return all the objects,

View File

@ -104,7 +104,6 @@ Variables can come from your database fields, or custom methods you define on yo
**mysite/code/Page.php**
```php
public function UsersIpAddress()
{
return $this->getRequest()->getIP();

View File

@ -32,8 +32,6 @@ It is common practice to include most Requirements either in the *init()*-method
as close to rendering as possible (e.g. in [FormField](api:SilverStripe\Forms\FormField)).
```php
<?php
use SilverStripe\Control\Director;
use SilverStripe\View\Requirements;

View File

@ -22,14 +22,15 @@ instance with a template name or an array of templates to render.
**mysite/code/Page.php**
```php
$arrayData = new SilverStripe/View/ArrayData(array(
$arrayData = new SilverStripe/View/ArrayData([
'Name' => 'John',
'Role' => 'Head Coach'
));
]);
echo $arrayData->renderWith('Coach_Message');
// returns "<strong>John</strong> is the Head Coach on our team."
```
<div class="info" markdown="1">
@ -38,22 +39,21 @@ includes [Controller](api:SilverStripe\Control\Controller), [FormField](api:Silv
</div>
```php
$controller->renderWith(array('MyController', 'MyBaseController'));
$controller->renderWith(['MyController', 'MyBaseController']);
SilverStripe\Security\Security::getCurrentUser()->renderWith('Member_Profile');
```
`renderWith` can be used to override the default template process. For instance, to provide an ajax version of a
template.
```php
<?php
use SilverStripe\CMS\Controllers\ContentController;
class PageController extends ContentController
{
private static $allowed_actions = array('iwantmyajax');
private static $allowed_actions = ['iwantmyajax'];
public function iwantmyajax()
{
@ -64,13 +64,13 @@ class PageController extends ContentController
}
}
}
```
Any data you want to render into the template that does not extend `ViewableData` should be wrapped in an object that
does, such as `ArrayData` or `ArrayList`.
```php
<?php
use SilverStripe\View\ArrayData;
use SilverStripe\ORM\ArrayList;
use SilverStripe\Control\Director;
@ -83,18 +83,19 @@ class PageController extends ContentController
{
if (Director::is_ajax()) {
$experience = new ArrayList();
$experience->push(new ArrayData(array(
$experience->push(new ArrayData([
'Title' => 'First Job'
)));
]));
return $this->customise(new ArrayData(array(
return $this->customise(new ArrayData([
'Name' => 'John',
'Role' => 'Head Coach',
'Experience' => $experience
)))->renderWith('AjaxTemplate');
]))->renderWith('AjaxTemplate');
} else {
return $this->httpError(404);
}
}
}
```

View File

@ -9,7 +9,6 @@ All functions that provide data to templates must have no side effects, as the v
example, this controller method will not behave as you might imagine.
```php
private $counter = 0;
public function Counter() {

View File

@ -48,9 +48,7 @@ provide default template for an object.
**mysite/code/Page.php**
```php
<?php
class Page extends SiteTree {
public function forTemplate() {
@ -73,19 +71,18 @@ content that method sends back, or, provide a type in the `$casting` array for t
to a template, SilverStripe will ensure that the object is wrapped in the correct type and values are safely escaped.
```php
<?php
class Page extends SiteTree {
private static $casting = array(
private static $casting = [
'MyCustomMethod' => 'HTMLText'
);
];
public function MyCustomMethod() {
return "<h1>This is my header</h1>";
}
}
```
When calling `$MyCustomMethod` SilverStripe now has the context that this method will contain HTML and escape the data

View File

@ -9,15 +9,13 @@ subclass the base `Controller` class.
**mysite/code/controllers/TeamController.php**
```php
<?php
class TeamController extends Controller {
private static $allowed_actions = array(
private static $allowed_actions = [
'players',
'index'
);
];
public function index(HTTPRequest $request) {
// ..
@ -27,6 +25,7 @@ subclass the base `Controller` class.
print_r($request->allParams());
}
}
```
## Routing
@ -78,15 +77,14 @@ Action methods can return one of four main things:
**mysite/code/controllers/TeamController.php**
```php
/**
* Return some additional data to the current response that is waiting to go out, this makes $Title set to
* 'MyTeamName' and continues on with generating the response.
*/
public function index(HTTPRequest $request) {
return array(
return [
'Title' => 'My Team Name'
);
];
}
/**
@ -113,23 +111,24 @@ Action methods can return one of four main things:
* We can render HTML and leave SilverStripe to set the response code and body.
*/
public function htmlaction() {
return $this->customise(new ArrayData(array(
return $this->customise(new ArrayData([
'Title' => 'HTML Action'
)))->renderWith('MyCustomTemplate');
]))->renderWith('MyCustomTemplate');
}
/**
* We can send stuff to the browser which isn't HTML
*/
public function ajaxaction() {
$this->getResponse()->setBody(json_encode(array(
$this->getResponse()->setBody(json_encode([
'json' => true
)));
]));
$this->getResponse()->addHeader("Content-type", "application/json");
return $this->getResponse().
}
```
For more information on how a URL gets mapped to an action see the [Routing](routing) documentation.
@ -159,7 +158,6 @@ Each controller should define a `Link()` method. This should be used to avoid ha
**mysite/code/controllers/TeamController.php**
```php
public function Link($action = null) {
return Controller::join_links('teams', $action);
}

View File

@ -84,6 +84,7 @@ print_r($this->getRequest()->params());
// [ID] => 1
// [Name] => null
// )
```
You can also fetch one parameter at a time.
@ -158,20 +159,19 @@ This is useful when you want to provide custom actions for the mapping of `teams
**mysite/code/controllers/TeamController.php**
```php
<?php
use SilverStripe\Control\Controller;
class TeamController extends Controller
{
private static $allowed_actions = array(
private static $allowed_actions = [
'payroll'
);
];
private static $url_handlers = array(
private static $url_handlers = [
'staff/$ID/$Name' => 'payroll',
'coach/$ID/$Name' => 'payroll'
);
];
```
The syntax for the `$url_handlers` array users the same pattern matches as the `YAML` configuration rules.
@ -188,10 +188,10 @@ use SilverStripe\CMS\Controllers\ContentController;
class FeedController extends ContentController
{
private static $allowed_actions = array('go');
private static $url_handlers = array(
private static $allowed_actions = ['go'];
private static $url_handlers = [
'go/$UserName/$AuthToken/$Timestamp/$OutputType/$DeleteMode' => 'go'
);
];
public function go()
{
@ -206,6 +206,7 @@ class FeedController extends ContentController
The YAML rule, in contrast, is simple. It needs to provide only enough
information for the framework to choose the desired controller.
```yml
Director:
rules:

View File

@ -12,12 +12,10 @@ Any action you define on a controller must be defined in a `$allowed_actions` st
directly calling methods that they shouldn't.
```php
<?php
class MyController extends Controller {
private static $allowed_actions = array(
private static $allowed_actions = [
// someaction can be accessed by anyone, any time
'someaction',
@ -35,8 +33,9 @@ directly calling methods that they shouldn't.
// complexactioncheck can only be accessed if $this->canComplexAction("MyRestrictedAction", false, 42) is true.
'complexactioncheck' => '->canComplexAction("MyRestrictedAction", false, 42)',
);
];
}
```
<div class="info">
@ -47,7 +46,6 @@ An action named "index" is white listed by default, unless `allowed_actions` is
is specifically restricted.
```php
<?php
class MyController extends Controller {
@ -61,29 +59,26 @@ is specifically restricted.
`$allowed_actions` can be defined on `Extension` classes applying to the controller.
```php
<?php
class MyExtension extends Extension {
private static $allowed_actions = array(
private static $allowed_actions = [
'mycustomaction'
);
];
}
```
Only public methods can be made accessible.
```php
<?php
class MyController extends Controller {
private static $allowed_actions = array(
private static $allowed_actions = [
'secure',
// secureaction won't work as it's private.
);
];
public function secure() {
// ..
@ -93,18 +88,17 @@ Only public methods can be made accessible.
// ..
}
}
```
If a method on a parent class is overwritten, access control for it has to be redefined as well.
```php
<?php
class MyController extends Controller {
private static $allowed_actions = array(
private static $allowed_actions = [
'action',
);
];
public function action() {
// ..
@ -113,14 +107,15 @@ If a method on a parent class is overwritten, access control for it has to be re
class MyChildController extends MyController {
private static $allowed_actions = array(
private static $allowed_actions = [
'action', // required as we are redefining action
);
];
public function action() {
}
}
```
<div class="notice" markdown="1">
@ -132,14 +127,12 @@ Access checks on parent classes need to be overwritten via the [Configuration AP
Form action methods should **not** be included in `$allowed_actions`. However, the form method **should** be included
as an `allowed_action`.
```php
<?php
class MyController extends Controller {
private static $allowed_actions = array(
private static $allowed_actions = [
'ContactForm' // use the Form method, not the action
);
];
public function ContactForm() {
return new Form(..);
@ -149,6 +142,7 @@ as an `allowed_action`.
// ..
}
}
```
## Action Level Checks
@ -157,14 +151,12 @@ Each method responding to a URL can also implement custom permission checks, e.g
the passed request data.
```php
<?php
class MyController extends Controller {
private static $allowed_actions = array(
private static $allowed_actions = [
'myaction'
);
];
public function myaction($request) {
if(!$request->getVar('apikey')) {
@ -174,6 +166,7 @@ the passed request data.
return 'valid';
}
}
```
<div class="notice" markdown="1">
@ -191,12 +184,10 @@ execution. This behavior can be used to implement permission checks.
`init` is called for any possible action on the controller and before any specific method such as `index`.
</div>
```php
<?php
class MyController extends Controller {
private static $allowed_actions = array();
private static $allowed_actions = [];
public function init() {
parent::init();
@ -206,6 +197,7 @@ execution. This behavior can be used to implement permission checks.
}
}
}
```
## Related Documentation

View File

@ -10,7 +10,6 @@ HTTP header.
```php
$this->redirect('goherenow');
// redirect to Page::goherenow(), i.e on the contact-us page this will redirect to /contact-us/goherenow/
@ -29,7 +28,6 @@ HTTP header.
The `redirect()` method takes an optional HTTP status code, either `301` for permanent redirects, or `302` for
temporary redirects (default).
```php
$this->redirect('/', 302);
// go back to the homepage, don't cache that this page has moved
```
@ -41,10 +39,10 @@ operator.
```php
private static $url_handlers = array(
private static $url_handlers = [
'players/john' => '~>coach'
);
];
```
For more information on `$url_handlers` see the [Routing](routing) documenation.

View File

@ -19,8 +19,6 @@ will deliberately return a different response, e.g. an error response or a redir
**mysite/code/CustomMiddleware.php**
```php
<?php
use SilverStripe\Control\Middleware\HTTPMiddleware
use SilverStripe\Control\HTTPRequest;

View File

@ -16,7 +16,6 @@ Creating a [Form](api:SilverStripe\Forms\Form) has the following signature.
```php
$form = new Form(
$controller, // the Controller to render this form on
$name, // name of the method that returns this form on the controller
@ -31,8 +30,6 @@ In practice, this looks like:
**mysite/code/Page.php**
```php
<?php
use SilverStripe\CMS\Controllers\ContentController;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\Form;
@ -42,9 +39,9 @@ use SilverStripe\Forms\TextField;
class PageController extends ContentController
{
private static $allowed_actions = array(
private static $allowed_actions = [
'HelloForm'
);
];
public function HelloForm()
{
@ -70,6 +67,7 @@ class PageController extends ContentController
return $this->redirectBack();
}
}
```
**mysite/templates/Page.ss**
@ -94,9 +92,10 @@ Because the `HelloForm()` method will be the location the user is taken to, it n
controller action. To grant it access through URLs, we add it to the `$allowed_actions` array.
```php
private static $allowed_actions = array(
private static $allowed_actions = [
'HelloForm'
);
];
```
<div class="notice" markdown="1">
@ -279,8 +278,6 @@ The `$action` method takes two arguments:
* `$form` the submitted [Form](api:SilverStripe\Forms\Form) instance.
```php
<?php
use SilverStripe\CMS\Controllers\ContentController;
use SilverStripe\Forms\EmailField;
use SilverStripe\Forms\FieldList;
@ -290,9 +287,9 @@ use SilverStripe\Forms\TextField;
class PageController extends ContentController
{
private static $allowed_actions = array(
private static $allowed_actions = [
'MyForm'
);
];
public function MyForm()
{
@ -326,6 +323,7 @@ class PageController extends ContentController
return $this->redirectBack();
}
}
```
## Validation
@ -337,12 +335,13 @@ validating its' own data value.
For more information, see the [Form Validation](validation) documentation.
```php
$validator = new SilverStripe\Forms\RequiredFields(array(
$validator = new SilverStripe\Forms\RequiredFields([
'Name',
'Email'
));
]);
$form = new Form($this, 'MyForm', $fields, $actions, $validator);
```
## API Documentation

View File

@ -8,8 +8,6 @@ SilverStripe provides server-side form validation out of the box through the [Va
the [Form](api:SilverStripe\Forms\Form) constructor or through the function `setValidator`.
```php
<?php
use SilverStripe\CMS\Controllers\ContentController;
use SilverStripe\Forms\EmailField;
use SilverStripe\Forms\Form;
@ -19,9 +17,9 @@ use SilverStripe\Forms\RequiredFields;
class PageController extends ContentController
{
private static $allowed_actions = array(
private static $allowed_actions = [
'MyForm'
);
];
public function MyForm()
{
@ -35,9 +33,9 @@ class PageController extends ContentController
);
// the fields 'Name' and 'Email' are required.
$required = new RequiredFields(array(
$required = new RequiredFields([
'Name', 'Email'
));
]);
// $required can be set as an argument
$form = new Form($controller, 'MyForm', $fields, $actions, $required);
@ -53,6 +51,7 @@ class PageController extends ContentController
//..
}
}
```
In this example we will be required to input a value for `Name` and a valid email address for `Email` before the
@ -96,8 +95,6 @@ the same validation logic applied to it throughout.
**mysite/code/CustomNumberField.php**
```php
<?php
use SilverStripe\Forms\TextField;
class CustomNumberField extends TextField
@ -128,8 +125,6 @@ reusable and would not be possible within the `CMS` or other automated `UI` but
`FormField` classes.
```php
<?php
use SilverStripe\CMS\Controllers\ContentController;
use SilverStripe\Forms\EmailField;
use SilverStripe\Forms\FieldList;
@ -140,9 +135,9 @@ use SilverStripe\Security\Member;
class Page_Controller extends ContentController
{
private static $allowed_actions = array(
private static $allowed_actions = [
'MyForm'
);
];
public function MyForm()
{
@ -179,6 +174,7 @@ class Page_Controller extends ContentController
return $this->redirectBack();
}
}
```
## Exempt validation actions
@ -283,17 +279,15 @@ Again, custom error messages can be provided through the `FormField`
</div>
```php
<?php
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Forms\TextField;
use SilverStripe\Forms\RequiredFields;
class Page extends SiteTree
{
private static $db = array(
private static $db = [
'MyRequiredField' => 'Text'
);
];
public function getCMSFields()
{
@ -306,11 +300,12 @@ class Page extends SiteTree
public function getCMSValidator()
{
return new RequiredFields(array(
return new RequiredFields([
'MyRequiredField'
));
]);
}
}
```
## API Documentation

View File

@ -8,8 +8,6 @@ can be rendered out using custom templates using `setTemplate`.
```php
$form = new Form(..);
$form->setTemplate('MyCustomFormTemplate');
@ -39,7 +37,6 @@ For [FormField](api:SilverStripe\Forms\FormField) instances, there are several o
```php
$field = new TextField();
$field->setTemplate('CustomTextField');

View File

@ -22,7 +22,6 @@ The `SecurityToken` automatically added looks something like:
```php
$form = new Form(..);
echo $form->getSecurityToken()->getValue();
@ -42,7 +41,6 @@ normally require a security token).
```php
$form = new Form(..);
$form->disableSecurityToken();
```
@ -60,7 +58,6 @@ application errors or edge cases. If you need to disable this setting follow the
```php
$form = new Form(..);
$form->setFormMethod('POST');

View File

@ -11,7 +11,6 @@ To make an entire [Form](api:SilverStripe\Forms\Form) read-only.
```php
$form = new Form(..);
$form->makeReadonly();
```
@ -20,7 +19,6 @@ To make all the fields within a [FieldList](api:SilverStripe\Forms\FieldList) re
```php
$fields = new FieldList(..);
$fields = $fields->makeReadonly();
```
@ -29,7 +27,6 @@ To make a [FormField](api:SilverStripe\Forms\FormField) read-only you need to kn
```php
$field = new TextField(..);
$field = $field->performReadonlyTransformation();

View File

@ -23,7 +23,6 @@ display up to two levels of tabs in the interface. If you want to group data fur
```php
$fields->addFieldToTab('Root.Main', new TextField(..));
```
@ -31,7 +30,6 @@ display up to two levels of tabs in the interface. If you want to group data fur
```php
$fields->removeFieldFromTab('Root.Main', 'Content');
```
@ -39,7 +37,6 @@ display up to two levels of tabs in the interface. If you want to group data fur
```php
$fields->addFieldToTab('Root.MyNewTab', new TextField(..));
```
@ -47,7 +44,6 @@ display up to two levels of tabs in the interface. If you want to group data fur
```php
$content = $fields->dataFieldByName('Content');
$fields->removeFieldFromTab('Root.Main', 'Content');
@ -58,11 +54,11 @@ display up to two levels of tabs in the interface. If you want to group data fur
```php
$fields->addFieldsToTab('Root.Content', array(
$fields->addFieldsToTab('Root.Content', [
TextField::create('Name'),
TextField::create('Email')
));
]);
```
## API Documentation

View File

@ -16,14 +16,12 @@ The following example will add a simple DateField to your Page, allowing you to
```php
<?php
class Page extends SiteTree {
private static $db = array(
private static $db = [
'MyDate' => 'Date',
);
];
public function getCMSFields() {
$fields = parent::getCMSFields();
@ -36,6 +34,7 @@ The following example will add a simple DateField to your Page, allowing you to
return $fields;
}
}
```
## Custom Date Format
@ -45,7 +44,6 @@ This is only necessary if you want to opt-out of the built-in browser localisati
```php
// will display a date in the following format: 31/06/2012
DateField::create('MyDate')
->setHTML5(false)
@ -64,7 +62,6 @@ Sets the minimum and maximum allowed date values using the `min` and `max` confi
```php
DateField::create('MyDate')
->setMinDate('-7 days')
->setMaxDate('2012-12-31')
@ -78,7 +75,6 @@ field description as an example.
```php
$dateField = DateField::create('MyDate');
// Show long format as text below the field

View File

@ -17,14 +17,12 @@ functionality. It is usually added through the [DataObject::getCMSFields()](api:
```php
<?php
class MyObject extends DataObject {
private static $db = array(
private static $db = [
'Content' => 'HTMLText'
);
];
public function getCMSFields() {
return new FieldList(
@ -32,6 +30,7 @@ functionality. It is usually added through the [DataObject::getCMSFields()](api:
);
}
}
```
### Specify which configuration to use
@ -47,20 +46,20 @@ This is particularly useful if you need different configurations for multiple [H
```php
class MyObject extends DataObject {
private static $db = array(
private static $db = [
'Content' => 'HTMLText',
'OtherContent' => 'HTMLText'
);
];
public function getCMSFields() {
return new FieldList(array(
return new FieldList([
new HTMLEditorField('Content'),
new HTMLEditorField('OtherContent', 'Other content', $this->OtherContent, 'myConfig')
));
]);
}
}
```
In the above example, the 'Content' field will use the default 'cms' config while 'OtherContent' will be using 'myConfig'.
@ -93,7 +92,6 @@ transparently generate the relevant underlying TinyMCE code.
**mysite/_config.php**
```php
HtmlEditorConfig::get('cms')->enablePlugins('media');
```
@ -109,7 +107,6 @@ configuration. Here is an example of adding a `ssmacron` button after the `charm
**mysite/_config.php**
```php
HtmlEditorConfig::get('cms')->insertButtonsAfter('charmap', 'ssmacron');
```
@ -118,7 +115,6 @@ Buttons can also be removed:
**mysite/_config.php**
```php
HtmlEditorConfig::get('cms')->removeButtons('tablecontrols', 'blockquote', 'hr');
```
@ -140,7 +136,6 @@ from the HTML source by the editor.
**mysite/_config.php**
```php
// Add start and type attributes for <ol>, add <object> and <embed> with all attributes.
HtmlEditorConfig::get('cms')->setOption(
'extended_valid_elements',
@ -168,8 +163,8 @@ You can enable them through [HtmlEditorConfig::enablePlugins()](api:SilverStripe
**mysite/_config.php**
```php
HtmlEditorConfig::get('cms')->enablePlugins(['myplugin' => '../../../mysite/javascript/myplugin/editor_plugin.js']);
HtmlEditorConfig::get('cms')->enablePlugins(array('myplugin' => '../../../mysite/javascript/myplugin/editor_plugin.js'));
```
You can learn how to [create a plugin](http://www.tinymce.com/wiki.php/Creating_a_plugin) from the TinyMCE documentation.
@ -223,7 +218,6 @@ In case you want to adhere to HTML4 instead, use the following configuration:
```php
HtmlEditorConfig::get('cms')->setOption('element_format', 'html');
```
@ -249,7 +243,6 @@ Example: Remove field for "image captions"
```php
// File: mysite/code/MyToolbarExtension.php
class MyToolbarExtension extends Extension {
public function updateFieldsForImage(&$fields, $url, $file) {
@ -261,7 +254,6 @@ Example: Remove field for "image captions"
```php
// File: mysite/_config.php
ModalController::add_extension('MyToolbarExtension');
```
@ -291,7 +283,6 @@ of the CMS you have to take care of instantiate yourself:
```php
// File: mysite/code/MyController.php
class MyObjectController extends Controller {
public function Modals() {
@ -305,7 +296,6 @@ so this is considered advanced usage of the field.
```php
// File: mysite/_config.php
HtmlEditorConfig::get('cms')->disablePlugins('ssbuttons');
HtmlEditorConfig::get('cms')->removeButtons('sslink', 'ssmedia');
@ -332,7 +322,6 @@ Assuming you have the module installed, here's how you enable its use in `mysite
```php
HtmlEditorConfig::get('cms')->enablePlugins('spellchecker', 'contextmenu');
HtmlEditorConfig::get('cms')->addButtonsToLine(2, 'spellchecker');
HtmlEditorConfig::get('cms')->setOption(
@ -346,7 +335,6 @@ Now change the default spellchecker in `framework/thirdparty/tinymce-spellchecke
```php
// ...
$config['general.engine'] = 'PSpell';

View File

@ -8,7 +8,6 @@ tabular data in a format that is easy to view and modify. It can be thought of a
```php
$field = new GridField($name, $title, $list);
```
@ -30,9 +29,7 @@ actions such as deleting records.
```php
<?php
class Page extends SiteTree {
public function getCMSFields() {
@ -64,9 +61,7 @@ the `getConfig()` method on `GridField`.
```php
<?php
class Page extends SiteTree {
public function getCMSFields() {
@ -86,20 +81,20 @@ the `getConfig()` method on `GridField`.
//
$dataColumns = $config->getComponentByType('GridFieldDataColumns');
$dataColumns->setDisplayFields(array(
$dataColumns->setDisplayFields([
'Title' => 'Title',
'Link'=> 'URL',
'LastEdited' => 'Changed'
));
]);
return $fields;
}
}
```
With the `GridFieldConfig` instance, we can modify the behavior of the `GridField`.
```php
// `GridFieldConfig::create()` will create an empty configuration (no components).
$config = GridFieldConfig::create();
@ -113,7 +108,6 @@ With the `GridFieldConfig` instance, we can modify the behavior of the `GridFiel
`GridFieldConfig` provides a number of methods to make setting the configuration easier. We can insert a component
before another component by passing the second parameter.
```php
$config->addComponent(new GridFieldFilterHeader(), 'GridFieldDataColumns');
```
@ -121,7 +115,6 @@ We can add multiple components in one call.
```php
$config->addComponents(
new GridFieldDataColumns(),
new GridFieldToolbarHeader()
@ -132,7 +125,6 @@ Or, remove a component.
```php
$config->removeComponentsByType('GridFieldDeleteAction');
```
@ -140,7 +132,6 @@ Fetch a component to modify it later on.
```php
$component = $config->getComponentByType('GridFieldFilterHeader')
```
@ -170,7 +161,6 @@ A simple read-only and paginated view of records with sortable and searchable he
```php
$config = GridFieldConfig_Base::create();
$gridField->setConfig($config);
@ -201,7 +191,6 @@ this record.
```php
$config = GridFieldConfig_RecordViewer::create();
$gridField->setConfig($config);
@ -227,7 +216,6 @@ Permission control for editing and deleting the record uses the `canEdit()` and
```php
$config = GridFieldConfig_RecordEditor::create();
$gridField->setConfig($config);
@ -243,7 +231,6 @@ Permission control for editing and deleting the record uses the `canEdit()` and
Similar to `GridFieldConfig_RecordEditor`, but adds features to work on a record's has-many or many-many relationships.
As such, it expects the list used with the `GridField` to be a instance of `RelationList`.
```php
$config = GridFieldConfig_RelationEditor::create();
$gridField->setConfig($config);
@ -263,7 +250,6 @@ The `GridFieldDetailForm` component drives the record viewing and editing form.
```php
$form = $gridField->getConfig()->getComponentByType('GridFieldDetailForm');
$form->setFields(new FieldList(
new TextField('Title')
@ -283,35 +269,33 @@ The namespace notation is `ManyMany[<extradata-field-name>]`, so for example `Ma
```php
<?php
class Team extends DataObject {
private static $db = array(
private static $db = [
'Name' => 'Text'
);
];
public static $many_many = array(
public static $many_many = [
'Players' => 'Player'
);
];
}
class Player extends DataObject {
private static $db = array(
private static $db = [
'Name' => 'Text'
);
];
public static $many_many = array(
public static $many_many = [
'Teams' => 'Team'
);
];
public static $many_many_extraFields = array(
'Teams' => array(
public static $many_many_extraFields = [
'Teams' => [
'Position' => 'Text'
)
);
]
];
public function getCMSFields() {
$fields = parent::getCMSFields();
@ -334,6 +318,7 @@ The namespace notation is `ManyMany[<extradata-field-name>]`, so for example `Ma
return $fields;
}
}
```
## Flexible Area Assignment through Fragments
@ -355,7 +340,6 @@ bottom right of the table.
```php
$config->addComponent(new GridFieldButtonRow('after'));
$config->addComponent(new GridFieldPrintButton('buttons-after-right'));
```
@ -368,17 +352,16 @@ create an area rendered before the table wrapped in a simple `<div>`.
```php
<?php
class MyAreaComponent implements GridField_HTMLProvider {
public function getHTMLFragments( $gridField) {
return array(
return [
'before' => '<div class="my-area">$DefineFragment(my-area)</div>'
);
];
}
}
```
<div class="notice" markdown="1">
@ -391,24 +374,22 @@ Now you can add other components into this area by returning them as an array fr
```php
<?php
class MyShareLinkComponent implements GridField_HTMLProvider {
public function getHTMLFragments( $gridField) {
return array(
return [
'my-area' => '<a href>...</a>'
);
];
}
}
```
Your new area can also be used by existing components, e.g. the [GridFieldPrintButton](api:SilverStripe\Forms\GridField\GridFieldPrintButton)
```php
new GridFieldPrintButton('my-component-area');
```

View File

@ -11,30 +11,28 @@ code for a `Form` is to create it as a subclass to `Form`. Let's look at a examp
```php
<?php
class PageController extends ContentController {
public function SearchForm() {
$fields = new FieldList(
HeaderField::create('Header', 'Step 1. Basics'),
OptionsetField::create('Type', '', array(
OptionsetField::create('Type', '', [
'foo' => 'Search Foo',
'bar' => 'Search Bar',
'baz' => 'Search Baz'
)),
]),
CompositeField::create(
HeaderField::create('Header2', 'Step 2. Advanced '),
CheckboxSetField::create('Foo', 'Select Option', array(
CheckboxSetField::create('Foo', 'Select Option', [
'qux' => 'Search Qux'
)),
]),
CheckboxSetField::create('Category', 'Category', array(
CheckboxSetField::create('Category', 'Category', [
'Foo' => 'Foo',
'Bar' => 'Bar'
)),
]),
NumericField::create('Minimum', 'Minimum'),
NumericField::create('Maximum', 'Maximum')
@ -45,9 +43,9 @@ code for a `Form` is to create it as a subclass to `Form`. Let's look at a examp
FormAction::create('doSearchForm', 'Search')
);
$required = new RequiredFields(array(
$required = new RequiredFields([
'Type'
));
]);
$form = new Form($this, 'SearchForm', $fields, $actions, $required);
$form->setFormMethod('GET');
@ -61,6 +59,7 @@ code for a `Form` is to create it as a subclass to `Form`. Let's look at a examp
..
}
```
Now that is a bit of code to include on our controller and generally makes the file look much more complex than it
@ -70,9 +69,7 @@ should be. Good practice would be to move this to a subclass and create a new in
```php
<?php
class SearchForm extends Form {
/**
@ -83,22 +80,22 @@ should be. Good practice would be to move this to a subclass and create a new in
public function __construct($controller, $name) {
$fields = new FieldList(
HeaderField::create('Header', 'Step 1. Basics'),
OptionsetField::create('Type', '', array(
OptionsetField::create('Type', '', [
'foo' => 'Search Foo',
'bar' => 'Search Bar',
'baz' => 'Search Baz'
)),
]),
CompositeField::create(
HeaderField::create('Header2', 'Step 2. Advanced '),
CheckboxSetField::create('Foo', 'Select Option', array(
CheckboxSetField::create('Foo', 'Select Option', [
'qux' => 'Search Qux'
)),
]),
CheckboxSetField::create('Category', 'Category', array(
CheckboxSetField::create('Category', 'Category', [
'Foo' => 'Foo',
'Bar' => 'Bar'
)),
]),
NumericField::create('Minimum', 'Minimum'),
NumericField::create('Maximum', 'Maximum')
@ -109,9 +106,9 @@ should be. Good practice would be to move this to a subclass and create a new in
FormAction::create('doSearchForm', 'Search')
);
$required = new RequiredFields(array(
$required = new RequiredFields([
'Type'
));
]);
// now we create the actual form with our fields and actions defined
// within this class
@ -125,6 +122,7 @@ should be. Good practice would be to move this to a subclass and create a new in
$this->loadDataFrom($_REQUEST);
}
}
```
Our controller will now just have to create a new instance of this form object. Keeping the file light and easy to read.
@ -133,19 +131,18 @@ Our controller will now just have to create a new instance of this form object.
```php
<?php
class PageController extends ContentController {
private static $allowed_actions = array(
private static $allowed_actions = [
'SearchForm',
);
];
public function SearchForm() {
return new SearchForm($this, 'SearchForm');
}
}
```
Form actions can also be defined within your `Form` subclass to keep the entire form logic encapsulated.

View File

@ -13,9 +13,7 @@ totally custom template to meet our needs. To do this, we'll provide the class w
```php
<?php
public function SearchForm() {
$fields = new FieldList(
TextField::create('q')

View File

@ -19,9 +19,7 @@ below:
```php
<?php
class GridFieldCustomAction implements GridField_ColumnProvider, GridField_ActionProvider {
public function augmentColumns($gridField, &$columns) {
@ -31,17 +29,17 @@ below:
}
public function getColumnAttributes($gridField, $record, $columnName) {
return array('class' => 'grid-field__col-compact');
return ['class' => 'grid-field__col-compact'];
}
public function getColumnMetadata($gridField, $columnName) {
if($columnName == 'Actions') {
return array('title' => '');
return ['title' => ''];
}
}
public function getColumnsHandled($gridField) {
return array('Actions');
return ['Actions'];
}
public function getColumnContent($gridField, $record, $columnName) {
@ -52,14 +50,14 @@ below:
'CustomAction'.$record->ID,
'Do Action',
"docustomaction",
array('RecordID' => $record->ID)
['RecordID' => $record->ID]
);
return $field->Field();
}
public function getActions($gridField) {
return array('docustomaction');
return ['docustomaction'];
}
public function handleAction(GridField $gridField, $actionName, $arguments, $data) {
@ -74,6 +72,7 @@ below:
}
}
}
```
## Add the GridFieldCustomAction to the current `GridFieldConfig`
@ -85,7 +84,6 @@ manipulating the `GridFieldConfig` instance if required.
```php
// option 1: creating a new GridField with the CustomAction
$config = GridFieldConfig::create();
$config->addComponent(new GridFieldCustomAction());

View File

@ -6,12 +6,10 @@ Let's start by defining a new `ContactPage` page type:
```php
<?php
class ContactPage extends Page {
class ContactPage extends Page {
}
class ContactPageController extends PageController {
private static $allowed_actions = array('Form');
private static $allowed_actions = ['Form'];
public function Form() {
$fields = new FieldList(
new TextField('Name'),
@ -24,6 +22,7 @@ Let's start by defining a new `ContactPage` page type:
return new Form($this, 'Form', $fields, $actions);
}
}
```
To create a form, we instanciate a `Form` object on a function on our page controller. We'll call this function `Form()`. You're free to choose this name, but it's standard practice to name the function `Form()` if there's only a single form on the page.
@ -32,7 +31,6 @@ There's quite a bit in this function, so we'll step through one piece at a time.
```php
$fields = new FieldList(
new TextField('Name'),
new EmailField('Email'),
@ -44,7 +42,6 @@ First we create all the fields we want in the contact form, and put them inside
```php
$actions = FieldList(
new FormAction('submit', 'Submit')
);
@ -54,7 +51,6 @@ We then create a [FieldList](api:SilverStripe\Forms\FieldList) of the form actio
```php
return new Form($this, 'Form', $fields, $actions);
```
@ -74,9 +70,8 @@ Now that we have a contact form, we need some way of collecting the data submitt
```php
class ContactPageController extends PageController {
private static $allowed_actions = array('Form');
private static $allowed_actions = ['Form'];
public function Form() {
// ...
}
@ -93,12 +88,13 @@ Now that we have a contact form, we need some way of collecting the data submitt
";
$email->setBody($messageBody);
$email->send();
return array(
return [
'Content' => '<p>Thank you for your feedback.</p>',
'Form' => ''
);
];
}
}
```
<div class="hint" markdown="1">
@ -123,7 +119,6 @@ The framework comes with a predefined validator called [RequiredFields](api:Silv
```php
public function Form() {
// ...
$validator = new RequiredFields('Name', 'Message');

View File

@ -29,9 +29,7 @@ be marked `private static` and follow the `lower_case_with_underscores` structur
```php
<?php
class MyClass extends Page {
/**
@ -42,10 +40,11 @@ be marked `private static` and follow the `lower_case_with_underscores` structur
/**
* @config
*/
private static $option_two = array();
private static $option_two = [];
// ..
}
```
## Accessing and Setting Configuration Properties
@ -54,7 +53,6 @@ This can be done by calling the static method [Config::inst()](api:SilverStripe\
```php
$config = Config::inst()->get('MyClass', 'property');
```
@ -99,7 +97,6 @@ To use those variables in your application code:
```php
$me = new MyClass();
echo $me->config()->option_one;
@ -120,12 +117,13 @@ To use those variables in your application code:
// returns true
// You can also use the static version
MyClass::config()->option_two = array(
MyClass::config()->option_two = [
'Qux'
);
];
echo implode(', ', MyClass::config()->option_one);
// returns 'Qux'
```
<div class="notice" markdown="1">

View File

@ -25,7 +25,6 @@ To access variables in the PHP:
```php
$config = SiteConfig::current_site_config();
echo $config->Title;
@ -41,14 +40,12 @@ To extend the options available in the panel, define your own fields via a [Data
```php
<?php
class CustomSiteConfig extends DataExtension {
private static $db = array(
private static $db = [
'FooterContent' => 'HTMLText'
);
];
public function updateCMSFields(FieldList $fields) {
$fields->addFieldToTab("Root.Main",
@ -56,6 +53,7 @@ To extend the options available in the panel, define your own fields via a [Data
);
}
}
```
Then activate the extension.

View File

@ -19,20 +19,19 @@ and `RequestHandler`. You can still apply extensions to descendants of these cla
```php
<?php
class MyMemberExtension extends DataExtension {
private static $db = array(
private static $db = [
'DateOfBirth' => 'SS_Datetime'
);
];
public function SayHi() {
// $this->owner refers to the original instance. In this case a `Member`.
return "Hi " . $this->owner->Name;
}
}
```
<div class="info" markdown="1">
@ -56,7 +55,6 @@ Alternatively, we can add extensions through PHP code (in the `_config.php` file
```php
Member::add_extension('MyMemberExtension');
```
@ -81,24 +79,23 @@ $has_one etc.
```php
<?php
class MyMemberExtension extends DataExtension {
private static $db = array(
private static $db = [
'Position' => 'Varchar',
);
];
private static $has_one = array(
private static $has_one = [
'Image' => 'Image',
);
];
public function SayHi() {
// $this->owner refers to the original instance. In this case a `Member`.
return "Hi " . $this->owner->Name;
}
}
```
**mysite/templates/Page.ss**
@ -127,7 +124,6 @@ we added a `SayHi` method which is unique to our extension.
**mysite/code/Page.php**
```php
$member = Security::getCurrentUser();
echo $member->SayHi;
@ -144,7 +140,6 @@ through the [Object::extend()](api:Object::extend()) method.
```php
public function getValidator() {
// ..
@ -163,9 +158,7 @@ validator by defining the `updateValidator` method.
```php
<?php
class MyMemberExtension extends DataExtension {
// ..
@ -186,18 +179,16 @@ extension. The `CMS` provides a `updateCMSFields` Extension Hook to tie into.
```php
<?php
class MyMemberExtension extends DataExtension {
private static $db = array(
private static $db = [
'Position' => 'Varchar',
);
];
private static $has_one = array(
private static $has_one = [
'Image' => 'Image',
);
];
public function updateCMSFields(FieldList $fields) {
$fields->push(new TextField('Position'));
@ -205,6 +196,7 @@ extension. The `CMS` provides a `updateCMSFields` Extension Hook to tie into.
$upload->setAllowedFileCategories('image/supported');
}
}
```
<div class="notice" markdown="1">
@ -214,7 +206,6 @@ which allows an Extension to modify the results.
```php
public function Foo() {
$foo = // ..
@ -234,9 +225,7 @@ In your [Extension](api:SilverStripe\Core\Extension) class you can only refer to
```php
<?php
class MyMemberExtension extends DataExtension {
public function updateFoo($foo) {
@ -251,7 +240,6 @@ In your [Extension](api:SilverStripe\Core\Extension) class you can only refer to
To see what extensions are currently enabled on an object, use [Object::getExtensionInstances()](api:Object::getExtensionInstances()) and
[Object::hasExtension()](api:Object::hasExtension())
```php
$member = Security::getCurrentUser();
print_r($member->getExtensionInstances());
@ -279,7 +267,6 @@ if not specified in `self::$defaults`, but before extensions have been called:
```php
function __construct() {
$self = $this;
@ -301,7 +288,6 @@ This method is preferred to disabling, enabling, and calling field extensions ma
```php
public function getCMSFields() {
$this->beforeUpdateCMSFields(function($fields) {

View File

@ -12,7 +12,6 @@ in their WYSIWYG editor. Shortcodes are a semi-technical solution for this. A go
viewer or a Google Map at a certain location.
```php
$text = "<h1>My Map</h1>[map]"
// Will output
@ -22,7 +21,6 @@ viewer or a Google Map at a certain location.
Here's some syntax variations:
```php
[my_shortcode]
#
[my_shortcode /]
@ -40,7 +38,6 @@ Other fields can be manually parsed with shortcodes through the `parse` method.
```php
$text = "My awesome [my_shortcode] is here.";
ShortcodeParser::get_active()->parse($text);
```
@ -53,19 +50,18 @@ First we need to define a callback for the shortcode.
```php
<?php
class Page extends SiteTree {
private static $casting = array(
private static $casting = [
'MyShortCodeMethod' => 'HTMLText'
);
];
public static function MyShortCodeMethod($arguments, $content = null, $parser = null, $tagName) {
return "<em>" . $tagName . "</em> " . $content . "; " . count($arguments) . " arguments.";
}
}
```
These parameters are passed to the `MyShortCodeMethod` callback:
@ -86,10 +82,10 @@ To register a shortcode you call the following.
```php
// ShortcodeParser::get('default')->register($shortcode, $callback);
ShortcodeParser::get('default')->register('my_shortcode', array('Page', 'MyShortCodeMethod'));
ShortcodeParser::get('default')->register('my_shortcode', ['Page', 'MyShortCodeMethod']);
```
## Built-in Shortcodes
@ -104,7 +100,6 @@ shortcode, which takes an `id` parameter.
```php
<a href="[sitetree_link,id=99]">
```
@ -112,7 +107,6 @@ Links to internal `File` database records work exactly the same, but with the `[
```php
<a href="[file_link,id=99]">
```
@ -203,30 +197,30 @@ When the location attribute is "leftAlone" or "center" then the DOM is split aro
Here is a summary of the callback parameter values based on some example shortcodes.
```php
public function MyCustomShortCode($arguments, $content = null, $parser = null, $tagName) {
// ..
}
[my_shortcode]
$attributes => array();
$attributes => [];
$content => null;
$parser => ShortcodeParser instance,
$tagName => 'my_shortcode')
[my_shortcode,attribute="foo",other="bar"]
$attributes => array ('attribute' => 'foo', 'other' => 'bar')
$attributes => ['attribute' => 'foo', 'other' => 'bar']
$enclosedContent => null
$parser => ShortcodeParser instance
$tagName => 'my_shortcode'
[my_shortcode,attribute="foo"]content[/my_shortcode]
$attributes => array('attribute' => 'foo')
$attributes => ['attribute' => 'foo']
$enclosedContent => 'content'
$parser => ShortcodeParser instance
$tagName => 'my_shortcode'
```
## Limitations

View File

@ -20,7 +20,6 @@ The following sums up the simplest usage of the `Injector` it creates a new obje
```php
$object = Injector::inst()->create('MyClassName');
```
@ -40,7 +39,6 @@ Repeated calls to `create()` create a new object each time.
```php
$object = Injector::inst()->create('MyClassName');
$object2 = Injector::inst()->create('MyClassName');
@ -56,7 +54,6 @@ object instance as the first call.
```php
// sets up MyClassName as a singleton
$object = Injector::inst()->get('MyClassName');
$object2 = Injector::inst()->get('MyClassName');
@ -73,8 +70,7 @@ The `Injector` API can be used to define the types of `$dependencies` that an ob
```php
<?php
class MyController extends Controller {
// both of these properties will be automatically
@ -84,18 +80,18 @@ The `Injector` API can be used to define the types of `$dependencies` that an ob
// we declare the types for each of the properties on the object. Anything we pass in via the Injector API must
// match these data types.
static $dependencies = array(
static $dependencies = [
'textProperty' => 'a string value',
'permissions' => '%$PermissionService',
);
];
}
```
When creating a new instance of `MyController` the dependencies on that class will be met.
```php
$object = Injector::inst()->get('MyController');
echo ($object->permissions instanceof PermissionService);
@ -123,7 +119,6 @@ Now the dependencies will be replaced with our configuration.
```php
$object = Injector::inst()->get('MyController');
echo ($object->permissions instanceof MyCustomPermissionService);
@ -182,18 +177,17 @@ An example using the `MyFactory` service to create instances of the `MyService`
```php
<?php
class MyFactory implements SilverStripe\Core\Injector\Factory {
public function create($service, array $params = array()) {
public function create($service, array $params = []) {
return new MyServiceImplementation();
}
}
// Will use MyFactoryImplementation::create() to create the service instance.
$instance = Injector::inst()->get('MyService');
```
## Dependency overrides
@ -219,9 +213,7 @@ Assuming a class structure such as
```php
<?php
class RestrictivePermissionService {
private $database;
@ -266,7 +258,6 @@ Calling..
```php
// sets up ClassName as a singleton
$controller = Injector::inst()->get('MyController');
```
@ -324,7 +315,6 @@ This is useful when writing test cases, as certain services may be necessary to
```php
// Setup default service
Injector::inst()->registerService(new LiveService(), 'ServiceName');

View File

@ -47,9 +47,7 @@ used.
```php
<?php
class MySQLWriteDbAspect implements BeforeCallAspect {
/**
@ -57,9 +55,9 @@ used.
*/
public $writeDb;
public $writeQueries = array(
public $writeQueries = [
'insert','update','delete','replace'
);
];
public function beforeCall($proxied, $method, $args, &$alternateReturn) {
if (isset($args[0])) {
@ -73,6 +71,7 @@ used.
}
}
}
```
To actually make use of this class, a few different objects need to be configured. First up, define the `writeDb`
@ -184,7 +183,6 @@ One major feature of an `Aspect` is the ability to modify what is returned from
As seen in the above example, the `beforeCall` method modifies the `&$alternateReturn` variable, and returns `false`
after doing so.
```php
$alternateReturn = $this->writeDb->query($sql, $code);
return false;

View File

@ -7,7 +7,6 @@ address. We want our CMS authors to be able to embed the map using the following
```php
[googlemap,width=500,height=300]97-99 Courtenay Place, Wellington, New Zealand[/googlemap]
```

View File

@ -11,13 +11,11 @@ explicitly logging in or by invoking the "remember me" functionality.
```php
<?php
class MyMemberExtension extends DataExtension {
private static $db = array(
class MyMemberExtension extends DataExtension {
private static $db = [
'LastVisited' => 'Datetime',
'NumVisit' => 'Int',
);
];
public function memberLoggedIn() {
$this->logVisit();
@ -28,10 +26,10 @@ explicitly logging in or by invoking the "remember me" functionality.
}
public function updateCMSFields(FieldList $fields) {
$fields->addFieldsToTab('Root.Main', array(
$fields->addFieldsToTab('Root.Main', [
ReadonlyField::create('LastVisited', 'Last visited'),
ReadonlyField::create('NumVisit', 'Number of visits')
));
]);
}
protected function logVisit() {
@ -44,6 +42,7 @@ explicitly logging in or by invoking the "remember me" functionality.
));
}
}
```
Now you just need to apply this extension through your config:

View File

@ -10,9 +10,7 @@ to ensure that it works as it should. A simple example would be to test the resu
```php
<?php
use SilverStripe\CMS\Model\SiteTree;
class Page extends SiteTree
@ -28,9 +26,7 @@ to ensure that it works as it should. A simple example would be to test the resu
```php
<?php
use Page;
use SilverStripe\Dev\SapphireTest;
@ -120,9 +116,7 @@ end of each test.
```php
<?php
use SilverStripe\Core\Config\Config;
use SilverStripe\Dev\SapphireTest;
@ -134,7 +128,7 @@ end of each test.
// create 100 pages
for ($i = 0; $i < 100; $i++) {
$page = new Page(array('Title' => "Page $i"));
$page = new Page(['Title' => "Page $i"]);
$page->write();
$page->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
}
@ -153,6 +147,7 @@ end of each test.
// ..
}
}
```
`tearDownAfterClass` and `setUpBeforeClass` can be used to run code just once for the file rather than before and after
@ -161,9 +156,7 @@ takes place.
```php
<?php
use SilverStripe\Dev\SapphireTest;
class PageTest extends SapphireTest
@ -196,7 +189,6 @@ It's important to remember that the `parent::setUp();` functions will need to be
```php
public static function setUpBeforeClass()
{
parent::setUpBeforeClass();

View File

@ -9,7 +9,6 @@ creating [HTTPRequest](api:SilverStripe\Control\HTTPRequest), receiving [HTTPRes
## Get
```php
$page = $this->get($url);
```
@ -18,7 +17,6 @@ of the response.
## Post
```php
$page = $this->post($url);
```
@ -29,8 +27,8 @@ of the response.
```php
$submit = $this->submitForm($formID, $button = null, $data = []);
$submit = $this->submitForm($formID, $button = null, $data = array());
```
Submits the given form (`#ContactForm`) on the current page and returns the [HTTPResponse](api:SilverStripe\Control\HTTPResponse).
@ -39,7 +37,6 @@ Submits the given form (`#ContactForm`) on the current page and returns the [HTT
```php
$this->logInAs($member);
```
@ -47,7 +44,6 @@ Logs a given user in, sets the current session. To log all users out pass `null`
```php
$this->logInAs(null);
```
@ -59,10 +55,10 @@ The `FunctionalTest` class also provides additional asserts to validate your tes
```php
$this->assertPartialMatchBySelector('p.good',array(
$this->assertPartialMatchBySelector('p.good',[
'Test save was successful'
));
]);
```
Asserts that the most recently queried page contains a number of content tags specified by a CSS selector. The given CSS
@ -74,10 +70,10 @@ assertion fails if one of the expectedMatches fails to appear.
```php
$this->assertExactMatchBySelector("#MyForm_ID p.error", array(
$this->assertExactMatchBySelector("#MyForm_ID p.error", [
"That email address is invalid."
));
]);
```
Asserts that the most recently queried page contains a number of content tags specified by a CSS selector. The given CSS
@ -86,10 +82,10 @@ assertion fails if one of the expectedMatches fails to appear.
### assertPartialHTMLMatchBySelector
```php
$this->assertPartialHTMLMatchBySelector("#MyForm_ID p.error", array(
$this->assertPartialHTMLMatchBySelector("#MyForm_ID p.error", [
"That email address is invalid."
));
]);
```
Assert that the most recently queried page contains a number of content tags specified by a CSS selector. The given CSS
@ -102,10 +98,10 @@ assertion fails if one of the expectedMatches fails to appear.
### assertExactHTMLMatchBySelector
```php
$this->assertExactHTMLMatchBySelector("#MyForm_ID p.error", array(
$this->assertExactHTMLMatchBySelector("#MyForm_ID p.error", [
"That email address is invalid."
));
]);
```
Assert that the most recently queried page contains a number of content tags specified by a CSS selector. The given CSS

View File

@ -16,9 +16,7 @@ To include your fixture file in your tests, you should define it as your `$fixtu
```php
<?php
class MyNewTest extends SapphireTest {
protected static $fixture_file = 'fixtures.yml';
@ -33,17 +31,16 @@ You can also use an array of fixture files, if you want to use parts of multiple
```php
<?php
class MyNewTest extends SapphireTest {
protected static $fixture_file = array(
protected static $fixture_file = [
'fixtures.yml',
'otherfixtures.yml'
);
];
}
```
Typically, you'd have a separate fixture file for each class you are testing - although overlap between tests is common.
@ -53,33 +50,32 @@ ideal for fixture generation. Say we have the following two DataObjects:
```php
<?php
use SilverStripe\ORM\DataObject;
class Player extends DataObject
{
private static $db = array (
private static $db = [
'Name' => 'Varchar(255)'
);
];
private static $has_one = array(
private static $has_one = [
'Team' => 'Team'
);
];
}
class Team extends DataObject
{
private static $db = array (
private static $db = [
'Name' => 'Varchar(255)',
'Origin' => 'Varchar(255)'
);
];
private static $has_many = array(
private static $has_many = [
'Players' => 'Player'
);
];
}
```
We can represent multiple instances of them in `YAML` as follows:
@ -116,7 +112,6 @@ represents a new object and can be referenced in the PHP using `objFromFixture`
```php
$player = $this->objFromFixture('Player', 'jack');
```
@ -173,15 +168,15 @@ writing:
```php
$team = new Team(array(
$team = new Team([
'Name' => 'Hurricanes',
'Origin' => 'Wellington'
));
]);
$team->write();
$team->Players()->add($john);
```
<div class="notice" markdown="1">
@ -218,36 +213,36 @@ declare the role each player has in the team.
```php
use SilverStripe\ORM\DataObject;
class Player extends DataObject
{
private static $db = array (
private static $db = [
'Name' => 'Varchar(255)'
);
];
private static $belongs_many_many = array(
private static $belongs_many_many = [
'Teams' => 'Team'
);
];
}
class Team extends DataObject
{
private static $db = array (
private static $db = [
'Name' => 'Varchar(255)'
);
];
private static $many_many = array(
private static $many_many = [
'Players' => 'Player'
);
];
private static $many_many_extraFields = array(
'Players' => array(
private static $many_many_extraFields = [
'Players' => [
'Role' => "Varchar"
)
);
]
];
}
```
To provide the value for the `many_many_extraField` use the YAML list syntax.
@ -298,7 +293,6 @@ using them.
```php
$factory = Injector::inst()->create('FixtureFactory');
$obj = $factory->createObject('Team', 'hurricanes');
@ -308,10 +302,10 @@ In order to create an object with certain properties, just add a third argument:
```php
$obj = $factory->createObject('Team', 'hurricanes', array(
$obj = $factory->createObject('Team', 'hurricanes', [
'Name' => 'My Value'
));
]);
```
<div class="warning" markdown="1">
@ -323,7 +317,6 @@ After we've created this object in the factory, `getId` is used to retrieve it b
```php
$databaseId = $factory->getId('Team', 'hurricanes');
```
@ -334,10 +327,10 @@ name, we can set the default to be `Unknown Team`.
```php
$factory->define('Team', array(
$factory->define('Team', [
'Name' => 'Unknown Team'
));
]);
```
### Dependent Properties
@ -347,8 +340,7 @@ values based on other fixture data.
```php
$factory->define('Member', array(
$factory->define('Member', [
'Email' => function($obj, $data, $fixtures) {
if(isset($data['FirstName']) {
$obj->Email = strtolower($data['FirstName']) . '@example.org';
@ -357,7 +349,8 @@ values based on other fixture data.
'Score' => function($obj, $data, $fixtures) {
$obj->Score = rand(0,10);
}
));
)];
```
### Relations
@ -367,10 +360,10 @@ Model relations can be expressed through the same notation as in the YAML fixtur
```php
$obj = $factory->createObject('Team', 'hurricanes', array(
$obj = $factory->createObject('Team', 'hurricanes', [
'MyHasManyRelation' => '=>Player.john,=>Player.joe'
));
]);
```
#### Callbacks
@ -380,7 +373,6 @@ publish a page, which requires a method call.
```php
$blueprint = Injector::inst()->create('FixtureBlueprint', 'Member');
$blueprint->addCallback('afterCreate', function($obj, $identifier, $data, $fixtures) {
@ -403,7 +395,6 @@ equal the class names they manage.
```php
$memberBlueprint = Injector::inst()->create('FixtureBlueprint', 'Member', 'Member');
$adminBlueprint = Injector::inst()->create('FixtureBlueprint', 'AdminMember', 'Member');

View File

@ -9,9 +9,7 @@ how you can load default records into the test database.
```php
<?php
use SilverStripe\Dev\SapphireTest;
class PageTest extends SapphireTest
@ -32,12 +30,12 @@ how you can load default records into the test database.
*/
public function testURLGeneration()
{
$expectedURLs = array(
$expectedURLs = [
'home' => 'home',
'staff' => 'my-staff',
'about' => 'about-us',
'staffduplicate' => 'my-staff-2'
);
];
foreach($expectedURLs as $fixture => $urlSegment) {
$obj = $this->objFromFixture('Page', $fixture);
@ -46,6 +44,7 @@ how you can load default records into the test database.
}
}
}
```
Firstly we define a static `$fixture_file`, this should point to a file that represents the data we want to test,

View File

@ -11,9 +11,7 @@ response and modify the session within a test.
```php
<?php
class HomePageTest extends FunctionalTest {
/**
@ -26,15 +24,15 @@ response and modify the session within a test.
$this->assertEquals(200, $page->getStatusCode());
// We should see a login form
$login = $this->submitForm("LoginFormID", null, array(
$login = $this->submitForm("LoginFormID", null, [
'Email' => 'test@test.com',
'Password' => 'wrongpassword'
));
]);
// wrong details, should now see an error message
$this->assertExactHTMLMatchBySelector("#LoginForm p.error", array(
$this->assertExactHTMLMatchBySelector("#LoginForm p.error", [
"That email address is invalid."
));
]);
// If we login as a user we should see a welcome message
$me = Member::get()->first();
@ -42,11 +40,12 @@ response and modify the session within a test.
$this->logInAs($me);
$page = $this->get('home/');
$this->assertExactHTMLMatchBySelector("#Welcome", array(
$this->assertExactHTMLMatchBySelector("#Welcome", [
'Welcome Back'
));
]);
}
}
```
## Related Documentation

View File

@ -10,7 +10,6 @@ with information that we need.
```php
class MyObjectTest extends SapphireTest {
protected $factory;
@ -21,9 +20,9 @@ with information that we need.
$factory = Injector::inst()->create('FixtureFactory');
// Defines a "blueprint" for new objects
$factory->define('MyObject', array(
$factory->define('MyObject', [
'MyProperty' => 'My Default Value'
));
]);
$this->factory = $factory;
}
@ -31,7 +30,7 @@ with information that we need.
function testSomething() {
$MyObjectObj = $this->factory->createObject(
'MyObject',
array('MyOtherProperty' => 'My Custom Value')
['MyOtherProperty' => 'My Custom Value']
);
echo $MyObjectObj->MyProperty;
@ -41,6 +40,7 @@ with information that we need.
// returns "My Custom Value"
}
}
```
## Related Documentation

View File

@ -8,7 +8,6 @@ email was sent using this method.
```php
public function MyMethod() {
$e = new Email();
$e->To = "someone@example.com";
@ -22,7 +21,6 @@ To test that `MyMethod` sends the correct email, use the [SapphireTest::assertEm
```php
$this->assertEmailSent($to, $from, $subject, $body);
// to assert that the email is sent to the correct person

View File

@ -83,7 +83,6 @@ You can check for the current environment type in [config files](../configuratio
Checking for what environment you're running in can also be done in PHP. Your application code may disable or enable
certain functionality depending on the environment type.
```php
if (Director::isLive()) {
// is in live
} elseif (Director::isTest()) {

View File

@ -98,18 +98,17 @@ For example, a block that shows a collection of rotating slides needs to update
```php
public function SliderCacheKey() {
$fragments = array(
$fragments = [
'Page-Slides',
$this->ID,
// identify which objects are in the list and their sort order
implode('-', $this->Slides()->Column('ID')),
$this->Slides()->max('LastEdited')
);
];
return implode('-_-', $fragments);
}
```
Then reference that function in the cache key:
@ -147,7 +146,6 @@ configurable only on a site-wide basis), you could add a special function to you
```php
public function BlogStatisticsCounter() {
return (int)(time() / 60 / 5); // Returns a new number every five minutes
}
@ -308,7 +306,6 @@ logic is sound, you could increase the expiry dramatically.
```php
// Set partial cache expiry to 7 days
SS_Cache::set_cache_lifetime('cacheblock', 60 * 60 * 24 * 7);
```

View File

@ -47,7 +47,6 @@ This factory allows us you to globally define an adapter for all cache instances
```php
use Psr\SimpleCache\CacheInterface
$cache = Injector::inst()->get(CacheInterface::class . '.myCache');
```
@ -67,7 +66,6 @@ Cache objects follow the [PSR-16](http://www.php-fig.org/psr/psr-16/) class inte
```php
use Psr\SimpleCache\CacheInterface
$cache = Injector::inst()->get(CacheInterface::class . '.myCache');
@ -92,7 +90,6 @@ this will only affect a subset of cache keys ("myCache" in this example):
```php
use Psr\SimpleCache\CacheInterface
$cache = Injector::inst()->get(CacheInterface::class . '.myCache');
@ -105,7 +102,6 @@ You can also delete a single item based on it's cache key:
```php
use Psr\SimpleCache\CacheInterface
$cache = Injector::inst()->get(CacheInterface::class . '.myCache');
@ -117,7 +113,6 @@ Individual cache items can define a lifetime, after which the cached value is ma
```php
use Psr\SimpleCache\CacheInterface
$cache = Injector::inst()->get(CacheInterface::class . '.myCache');
@ -150,7 +145,6 @@ old cache keys will be garbage collected as the cache fills up.
```php
use Psr\SimpleCache\CacheInterface
$cache = Injector::inst()->get(CacheInterface::class . '.myCache');

View File

@ -18,7 +18,6 @@ headers:
### HTTP::set_cache_age
```php
HTTP::set_cache_age(0);
```
@ -29,7 +28,6 @@ clause in `Cache-Control` and `Pragma` will be included.
```php
HTTP::register_modification_date('2014-10-10');
```

View File

@ -17,7 +17,6 @@ next method for testing if you just need to test.
```php
// Is a member logged in?
if( Member::currentUserID() ) {
// Yes!
@ -32,7 +31,6 @@ Returns the full *Member* Object for the current user, returns *null* if user is
```php
if( $member = Security::getCurrentUser() ) {
// Work with $member
} else {
@ -51,13 +49,13 @@ You can define subclasses of [Member](api:SilverStripe\Security\Member) to add e
```php
class MyMember extends Member {
private static $db = array(
private static $db = [
"Age" => "Int",
"Address" => "Text",
);
];
}
```
To ensure that all new members are created using this class, put a call to [Object::useCustomClass()](api:Object::useCustomClass()) in
@ -65,7 +63,6 @@ To ensure that all new members are created using this class, put a call to [Obje
```php
Object::useCustomClass("Member", "MyMember");
```
@ -79,7 +76,6 @@ parent::getCMSFields() and manipulate the [FieldList](api:SilverStripe\Forms\Fie
```php
public function getCMSFields() {
$fields = parent::getCMSFields();
$fields->insertBefore("HTMLEmail", new TextField("Age"));
@ -118,7 +114,6 @@ things, you should add appropriate [Permission::checkMember()](api:SilverStripe\
```php
class MyMemberExtension extends DataExtension {
/**
@ -132,16 +127,17 @@ things, you should add appropriate [Permission::checkMember()](api:SilverStripe\
}
// define additional properties
private static $db = array();
private static $has_one = array();
private static $has_many = array();
private static $many_many = array();
private static $belongs_many_many = array();
private static $db = [];
private static $has_one = [];
private static $has_many = [];
private static $many_many = [];
private static $belongs_many_many = [];
public function somethingElse() {
// You can add any other methods you like, which you can call directly on the member object.
}
}
```
## Saved User Logins ##
@ -172,7 +168,6 @@ E.g.
```php
class CleanRecordsTask extends BuildTask
{
public function run($request)

View File

@ -38,11 +38,12 @@ class PageController implements PermissionProvider
public function providePermissions()
{
return array(
return [
'VIEW_SITE' => 'Access the site'
);
];
}
}
```

View File

@ -26,35 +26,35 @@ come from user input.
Example:
```php
$records = DB::prepared_query('SELECT * FROM "MyClass" WHERE "ID" = ?', array(3));
$records = MyClass::get()->where(array('"ID" = ?' => 3));
$records = MyClass::get()->where(array('"ID"' => 3));
$records = DB::prepared_query('SELECT * FROM "MyClass" WHERE "ID" = ?', [3]);
$records = MyClass::get()->where(['"ID" = ?' => 3]);
$records = MyClass::get()->where(['"ID"' => 3]);
$records = DataObject::get_by_id('MyClass', 3);
$records = DataObject::get_one('MyClass', array('"ID" = ?' => 3));
$records = DataObject::get_one('MyClass', ['"ID" = ?' => 3]);
$records = MyClass::get()->byID(3);
$records = SQLSelect::create()->addWhere(array('"ID"' => 3))->execute();
$records = SQLSelect::create()->addWhere(['"ID"' => 3])->execute();
```
Parameterised updates and inserts are also supported, but the syntax is a little different
```php
SQLInsert::create('"MyClass"')
->assign('"Name"', 'Daniel')
->addAssignments(array(
->addAssignments([
'"Position"' => 'Accountant',
'"Age"' => array(
'GREATEST(0,?,?)' => array(24, 28)
)
))
'"Age"' => [
'GREATEST(0,?,?)' => [24, 28]
]
])
->assignSQL('"Created"', 'NOW()')
->execute();
DB::prepared_query(
'INSERT INTO "MyClass" ("Name", "Position", "Age", "Created") VALUES(?, ?, GREATEST(0,?,?), NOW())'
array('Daniel', 'Accountant', 24, 28)
['Daniel', 'Accountant', 24, 28]
);
```
### Automatic escaping
@ -80,15 +80,15 @@ handled via prepared statements.
Example:
```php
// automatically escaped/quoted
$members = Member::get()->filter('Name', $_GET['name']);
// automatically escaped/quoted
$members = Member::get()->filter(array('Name' => $_GET['name']));
$members = Member::get()->filter(['Name' => $_GET['name']]);
// parameterised condition
$members = Member::get()->where(array('"Name" = ?' => $_GET['name']));
$members = Member::get()->where(['"Name" = ?' => $_GET['name']]);
// needs to be escaped and quoted manually (note raw2sql called with the $quote parameter set to true)
$members = Member::get()->where(sprintf('"Name" = %s', Convert::raw2sql($_GET['name'], true)));
```
<div class="warning" markdown='1'>
@ -114,7 +114,6 @@ Example:
```php
class MyForm extends Form {
public function save($RAW_data, $form) {
// Pass true as the second parameter of raw2sql to quote the value safely
@ -123,6 +122,7 @@ Example:
// ...
}
}
```
* `FormField->Value()`
@ -132,9 +132,8 @@ Example:
```php
class MyController extends Controller {
private static $allowed_actions = array('myurlaction');
private static $allowed_actions = ['myurlaction'];
public function myurlaction($RAW_urlParams) {
// Pass true as the second parameter of raw2sql to quote the value safely
$SQL_urlParams = Convert::raw2sql($RAW_urlParams, true); // works recursively on an array
@ -142,6 +141,7 @@ Example:
// ...
}
}
```
As a rule of thumb, you should escape your data **as close to querying as possible**
@ -150,7 +150,6 @@ passing data through, escaping should happen at the end of the chain.
```php
class MyController extends Controller {
/**
* @param array $RAW_data All names in an indexed array (not SQL-safe)
@ -165,6 +164,7 @@ passing data through, escaping should happen at the end of the chain.
DB::query("UPDATE Player SET Name = {$SQL_name}");
}
}
```
This might not be applicable in all cases - especially if you are building an API thats likely to be customised. If
@ -231,20 +231,19 @@ PHP:
```php
class MyObject extends DataObject {
private static $db = array(
private static $db = [
'MyEscapedValue' => 'Text', // Example value: <b>not bold</b>
'MyUnescapedValue' => 'HTMLText' // Example value: <b>bold</b>
);
];
}
```
Template:
```php
<ul>
<li>$MyEscapedValue</li> // output: &lt;b&gt;not bold&lt;b&gt;
<li>$MyUnescapedValue</li> // output: <b>bold</b>
@ -263,7 +262,6 @@ Template (see above):
```php
<ul>
// output: <a href="#" title="foo &amp; &#quot;bar&quot;">foo &amp; "bar"</a>
<li><a href="#" title="$Title.ATT">$Title</a></li>
@ -282,27 +280,26 @@ PHP:
```php
class MyObject extends DataObject {
public $Title = '<b>not bold</b>'; // will be escaped due to Text casting
$casting = array(
$casting = [
"Title" => "Text", // forcing a casting
'TitleWithHTMLSuffix' => 'HTMLText' // optional, as HTMLText is the default casting
);
];
public function TitleWithHTMLSuffix($suffix) {
// $this->Title is not casted in PHP
return $this->Title . '<small>(' . $suffix. ')</small>';
}
}
```
Template:
```php
<ul>
<li>$Title</li> // output: &lt;b&gt;not bold&lt;b&gt;
<li>$Title.RAW</li> // output: <b>not bold</b>
@ -325,24 +322,23 @@ PHP:
```php
class MyController extends Controller {
private static $allowed_actions = array('search');
private static $allowed_actions = ['search'];
public function search($request) {
$htmlTitle = '<p>Your results for:' . Convert::raw2xml($request->getVar('Query')) . '</p>';
return $this->customise(array(
return $this->customise([
'Query' => Text::create($request->getVar('Query')),
'HTMLTitle' => HTMLText::create($htmlTitle)
));
]);
}
}
```
Template:
```php
<h2 title="Searching for $Query.ATT">$HTMLTitle</h2>
```
@ -359,24 +355,23 @@ PHP:
```php
class MyController extends Controller {
private static $allowed_actions = array('search');
private static $allowed_actions = ['search'];
public function search($request) {
$rssRelativeLink = "/rss?Query=" . urlencode($_REQUEST['query']) . "&sortOrder=asc";
$rssLink = Controller::join_links($this->Link(), $rssRelativeLink);
return $this->customise(array(
return $this->customise([
"RSSLink" => Text::create($rssLink),
));
]);
}
}
```
Template:
```php
<a href="$RSSLink.ATT">RSS feed</a>
```
@ -426,7 +421,6 @@ Below is an example with different ways you would use this casting technique:
```php
public function CaseStudies() {
// cast an ID from URL parameters e.g. (mysite.com/home/action/ID)
@ -524,12 +518,12 @@ a [PasswordValidator](api:SilverStripe\Security\PasswordValidator):
```php
$validator = new PasswordValidator();
$validator->minLength(7);
$validator->checkHistoricalPasswords(6);
$validator->characterStrength(3, array("lowercase", "uppercase", "digits", "punctuation"));
$validator->characterStrength(3, ["lowercase", "uppercase", "digits", "punctuation"]);
Member::set_password_validator($validator);
```
In addition, you can tighten password security with the following configuration settings:
@ -554,7 +548,6 @@ controller's `init()` method:
```php
class MyController extends Controller {
public function init() {
parent::init();
@ -638,8 +631,6 @@ variable will be no longer necessary, thus it will be necessary to always set
SilverStripe recommends the use of TLS(HTTPS) for your application, and you can easily force the use through the
director function `forceSSL()`
```php
if (!Director::isDev()) {
Director::forceSSL();
}
@ -668,7 +659,6 @@ clear text and can be intercepted and stolen by an attacker who is listening on
code. It is best practice to set this flag unless the application is known to use JavaScript to access these cookies
as this prevents an attacker who achieves cross-site scripting from accessing these cookies.
```php
Cookie::set('cookie-name', 'chocolate-chip', $expiry = 30, $path = null, $domain = null, $secure = true,
$httpOnly = false
@ -697,8 +687,6 @@ and `Date: <current date>` will ensure that sensitive content is not stored loca
unauthorised local persons. SilverStripe adds the current date for every request, and we can add the other cache
headers to the request for our secure controllers:
```php
class MySecureController extends Controller {
public function init() {

View File

@ -24,7 +24,6 @@ SilverStripe\Core\Injector\Injector:
```php
$email = new Email($from, $to, $subject, $body);
$email->sendPlain();
```
@ -37,7 +36,6 @@ to `*text*`).
```php
$email = new Email($from, $to, $subject, $body);
$email->send();
```
@ -68,10 +66,10 @@ The PHP Logic..
```php
$email = SilverStripe\Control\Email\Email::create()
->setHTMLTemplate('Email\\MyCustomEmail')
->setData(array(
->setData([
'Member' => Security::getCurrentUser(),
'Link'=> $link,
))
])
->setFrom($from)
->setTo($to)
->setSubject($subject);
@ -81,6 +79,7 @@ if ($email->send()) {
} else {
// there may have been 1 or more failures
}
```
<div class="alert" markdown="1">
@ -136,7 +135,6 @@ Configuration of those properties looks like the following:
```php
if(Director::isLive()) {
Config::inst()->update('Email', 'bcc_all_emails_to', "client@example.com");
} else {
@ -151,7 +149,6 @@ email, do the following. This is encouraged especially when the domain responsib
necessarily the same which should be used for return correspondence and should help prevent your message from being
marked as spam.
```php
$email = new Email(..);
$email->setReplyTo('me@address.com');
```
@ -163,7 +160,6 @@ For email headers which do not have getters or setters (like setTo(), setFrom())
```php
$email = new Email(...);
$email->getSwiftMessage()->getHeaders()->addTextHeader('HeaderName', 'HeaderValue');
..

View File

@ -36,7 +36,6 @@ The loader would be triggered through the `load()` method:
```php
$loader = new CsvBulkLoader('Member');
$result = $loader->load('<my-file-path>');
```
@ -50,18 +49,17 @@ The simplest way to use [CsvBulkLoader](api:SilverStripe\Dev\CsvBulkLoader) is t
```php
<?php
class PlayerAdmin extends ModelAdmin {
private static $managed_models = array(
class PlayerAdmin extends ModelAdmin {
private static $managed_models = [
'Player'
);
private static $model_importers = array(
];
private static $model_importers = [
'Player' => 'CsvBulkLoader',
);
];
private static $url_segment = 'players';
}
?>
```
The new admin interface will be available under `http://localhost/admin/players`, the import form is located
@ -76,11 +74,9 @@ You'll need to add a route to your controller to make it accessible via URL
```php
class MyController extends Controller {
<?php
class MyController extends Controller {
private static $allowed_actions = array('Form');
private static $allowed_actions = ['Form'];
protected $template = "BlankPage";
@ -106,7 +102,7 @@ You'll need to add a route to your controller to make it accessible via URL
public function doUpload($data, $form) {
$loader = new CsvBulkLoader('MyDataObject');
$results = $loader->load($_FILES['CsvFile']['tmp_name']);
$messages = array();
$messages = [];
if($results->CreatedCount()) $messages[] = sprintf('Imported %d items', $results->CreatedCount());
if($results->UpdatedCount()) $messages[] = sprintf('Updated %d items', $results->UpdatedCount());
if($results->DeletedCount()) $messages[] = sprintf('Deleted %d items', $results->DeletedCount());
@ -116,6 +112,7 @@ You'll need to add a route to your controller to make it accessible via URL
return $this->redirectBack();
}
}
```
Note: This interface is not secured, consider using [Permission::check()](api:SilverStripe\Security\Permission::check()) to limit the controller to users
@ -137,37 +134,35 @@ Datamodel for Player
```php
<?php
class Player extends DataObject {
private static $db = array(
class Player extends DataObject {
private static $db = [
'PlayerNumber' => 'Int',
'FirstName' => 'Text',
'LastName' => 'Text',
'Birthday' => 'Date',
);
private static $has_one = array(
];
private static $has_one = [
'Team' => 'FootballTeam'
);
];
}
?>
```
Datamodel for FootballTeam:
```php
<?php
class FootballTeam extends DataObject {
private static $db = array(
class FootballTeam extends DataObject {
private static $db = [
'Title' => 'Text',
);
private static $has_many = array(
];
private static $has_many = [
'Players' => 'Player'
);
];
}
?>
```
Sample implementation of a custom loader. Assumes a CSV-file in a certain format (see below).
@ -177,24 +172,22 @@ Sample implementation of a custom loader. Assumes a CSV-file in a certain format
* Avoids duplicate imports by a custom `$duplicateChecks` definition
* Creates `Team` relations automatically based on the `Gruppe` column in the CSV data
```php
<?php
class PlayerCsvBulkLoader extends CsvBulkLoader {
public $columnMap = array(
class PlayerCsvBulkLoader extends CsvBulkLoader {
public $columnMap = [
'Number' => 'PlayerNumber',
'Name' => '->importFirstAndLastName',
'Birthday' => 'Birthday',
'Team' => 'Team.Title',
);
public $duplicateChecks = array(
];
public $duplicateChecks = [
'Number' => 'PlayerNumber'
);
public $relationCallbacks = array(
'Team.Title' => array(
];
public $relationCallbacks = [
'Team.Title' => [
'relationname' => 'Team',
'callback' => 'getTeamByTitle'
)
);
]
];
public static function importFirstAndLastName(&$obj, $val, $record) {
$parts = explode(' ', $val);
if(count($parts) != 2) return false;
@ -206,24 +199,24 @@ Sample implementation of a custom loader. Assumes a CSV-file in a certain format
}
}
?>
```
Building off of the ModelAdmin example up top, use a custom loader instead of the default loader by adding it to `$model_importers`. In this example, `CsvBulkLoader` is replaced with `PlayerCsvBulkLoader`.
```php
<?php
class PlayerAdmin extends ModelAdmin {
private static $managed_models = array(
class PlayerAdmin extends ModelAdmin {
private static $managed_models = [
'Player'
);
private static $model_importers = array(
];
private static $model_importers = [
'Player' => 'PlayerCsvBulkLoader',
);
];
private static $url_segment = 'players';
}
?>
```
## Related

View File

@ -21,15 +21,14 @@ in the template.
```php
public function getWellingtonWeather() {
$fetch = new RestfulService(
'https://query.yahooapis.com/v1/public/yql'
);
$fetch->setQueryString(array(
$fetch->setQueryString([
'q' => 'select * from weather.forecast where woeid in (select woeid from geo.places(1) where text="Wellington, NZ")'
));
]);
// perform the query
$conn = $fetch->request();
@ -42,14 +41,15 @@ in the template.
if($msgs) {
foreach($msgs as $msg) {
$output->push(new ArrayData(array(
$output->push(new ArrayData([
'Description' => Convert::xml2raw($msg->channel_item_description)
)));
]));
}
}
return $output;
}
```
## Features
@ -58,7 +58,6 @@ in the template.
```php
$service = new RestfulService("http://example.harvestapp.com");
$service->basicAuth('username', 'password');
```
@ -67,7 +66,6 @@ in the template.
```php
$service = new RestfulService("http://example.harvestapp.com");
$peopleXML = $service->request('/people');
@ -85,7 +83,6 @@ To set the cache interval you can pass it as the 2nd argument to constructor.
```php
$expiry = 60 * 60; // 1 hour;
$request = new RestfulService("http://example.harvestapp.com", $expiry );
@ -111,20 +108,20 @@ To extract the id attributes of the entries use:
```php
$this->getAttributes($xml, "entries", "entry");
// array(array('id' => 12), array('id' => '15'), ..)
```
To extract the values (the names) of the entries use:
```php
$this->getValues($xml, "entries", "entry");
// array('Sally', 'Ted', 'Matt', 'John')
```
### Searching for Values & Attributes
@ -147,10 +144,10 @@ To get the value of entry node with the namespace media, use:
```php
$this->searchValue($response, "//media:guide/media:entry");
// array('video');
```
## Best Practices
@ -163,9 +160,7 @@ If the web service returned an error (for example, API key not available or inad
```php
<?php
class MyRestfulService extends RestfulService {
public function errorCatch($response) {
@ -184,9 +179,7 @@ If you want to bypass error handling, define `checkErrors` in the constructor fo
```php
<?php
class MyRestfulService extends RestfulService {
public function __construct($expiry = NULL) {
@ -216,10 +209,11 @@ To set global cURL settings you can update the `RestfulService` config via the C
Here is an example to increase the HTTP Timeout globally. Insert this in your `_config.php` file:
```php
SilverStripe\Core\Config\Config::inst()->update('RestfulService', 'default_curl_options', array(
SilverStripe\Core\Config\Config::inst()->update('RestfulService', 'default_curl_options', [
CURLOPT_DNS_CACHE_TIMEOUT => 3600,
CURLOPT_CONNECTTIMEOUT => 10,
));
]);
```
@ -231,15 +225,15 @@ parameter in `RestfulService::request()`.
For example:
```php
//cURL options
$curlOptions = array(
$curlOptions = [
CURLOPT_UNRESTRICTED_AUTH => true,
);
];
$service = new RestfulService('http://example.com/');
$service->request('service.json', 'GET', null, null, $curlOptions);
```

View File

@ -24,7 +24,6 @@ An outline of step one looks like:
```php
$feed = new RSSFeed(
$list,
$link,
@ -43,7 +42,6 @@ An outline of step one looks like:
To achieve step two include the following code where ever you want to include the `<link>` tag to the RSS Feed. This
will normally go in your `Controllers` `init` method.
```php
RSSFeed::linkToFeed($link, $title);
```
@ -58,16 +56,14 @@ You can use [RSSFeed](api:SilverStripe\Control\RSS\RSSFeed) to easily create a f
```php
<?php
..
class PageController extends ContentController {
private static $allowed_actions = array(
private static $allowed_actions = [
'rss'
);
];
public function init() {
parent::init();
@ -90,6 +86,7 @@ You can use [RSSFeed](api:SilverStripe\Control\RSS\RSSFeed) to easily create a f
return Page::get()->sort("LastEdited", "DESC")->limit(10);
}
}
```
### Rendering DataObjects in a RSSFeed
@ -106,9 +103,7 @@ method is defined and returns a string to the full website URL.
```php
<?php
class Player extends DataObject {
public function AbsoluteLink() {
@ -127,14 +122,12 @@ Then in our controller, we add a new action which returns a the XML list of `Pla
```php
<?php
class PageController extends ContentController {
private static $allowed_actions = array(
private static $allowed_actions = [
'players'
);
];
public function init() {
parent::init();
@ -152,6 +145,7 @@ Then in our controller, we add a new action which returns a the XML list of `Pla
return $rss->outputToBrowser();
}
}
```
### Customizing the RSS Feed template
@ -190,8 +184,6 @@ Say from that last example we want to include the Players Team in the XML feed w
```php
public function players() {
$rss = new RSSFeed(
Player::get(),

View File

@ -8,14 +8,12 @@ form (which is used for `MyDataObject` instances). You can access it through
```php
<?php
class MyController extends Controller {
private static $allowed_actions = array(
private static $allowed_actions = [
'Form'
);
];
protected $template = "BlankPage";
@ -41,7 +39,7 @@ form (which is used for `MyDataObject` instances). You can access it through
public function doUpload($data, $form) {
$loader = new CsvBulkLoader('MyDataObject');
$results = $loader->load($_FILES['CsvFile']['tmp_name']);
$messages = array();
$messages = [];
if($results->CreatedCount()) {
$messages[] = sprintf('Imported %d items', $results->CreatedCount());
@ -64,6 +62,7 @@ form (which is used for `MyDataObject` instances). You can access it through
return $this->redirectBack();
}
}
```
<div class="alert" markdown="1">

View File

@ -17,41 +17,39 @@ information about the individual player and a relation set up for managing the `
```php
<?php
class Player extends DataObject {
private static $db = array(
private static $db = [
'PlayerNumber' => 'Int',
'FirstName' => 'Text',
'LastName' => 'Text',
'Birthday' => 'Date'
);
];
private static $has_one = array(
private static $has_one = [
'Team' => 'FootballTeam'
);
];
}
```
**mysite/code/FootballTeam.php**
```php
<?php
class FootballTeam extends DataObject {
private static $db = array(
private static $db = [
'Title' => 'Text'
);
];
private static $has_many = array(
private static $has_many = [
'Players' => 'Player'
);
];
}
```
Now going back to look at the CSV, we can see that what we're provided with does not match what our data model looks
@ -70,28 +68,26 @@ Our final import looks like this.
```php
<?php
class PlayerCsvBulkLoader extends CsvBulkLoader {
public $columnMap = array(
public $columnMap = [
'Number' => 'PlayerNumber',
'Name' => '->importFirstAndLastName',
'Geburtsdatum' => 'Birthday',
'Gruppe' => 'Team.Title',
);
];
public $duplicateChecks = array(
public $duplicateChecks = [
'SpielerNummer' => 'PlayerNumber'
);
];
public $relationCallbacks = array(
'Team.Title' => array(
public $relationCallbacks = [
'Team.Title' => [
'relationname' => 'Team',
'callback' => 'getTeamByTitle'
)
);
]
];
public static function importFirstAndLastName(&$obj, $val, $record) {
$parts = explode(' ', $val);
@ -104,6 +100,7 @@ Our final import looks like this.
return FootballTeam::get()->filter('Title', $val)->First();
}
}
```
## Related

View File

@ -11,15 +11,14 @@ First, we write the code to query the API feed.
```php
public function getWellingtonWeather() {
$fetch = new RestfulService(
'https://query.yahooapis.com/v1/public/yql'
);
$fetch->setQueryString(array(
$fetch->setQueryString([
'q' => 'select * from weather.forecast where woeid in (select woeid from geo.places(1) where text="Wellington, NZ")'
));
]);
// perform the query
$conn = $fetch->request();
@ -32,14 +31,15 @@ First, we write the code to query the API feed.
if($msgs) {
foreach($msgs as $msg) {
$output->push(new ArrayData(array(
$output->push(new ArrayData([
'Description' => Convert::xml2raw($msg->channel_item_description)
)));
]));
}
}
return $output;
}
```
This will provide our `Page` template with a new `WellingtonWeather` variable (an [ArrayList](api:SilverStripe\ORM\ArrayList)). Each item has a

View File

@ -20,16 +20,15 @@ Defining search-able fields on your DataObject.
```php
<?php
class MyDataObject extends DataObject {
private static $searchable_fields = array(
private static $searchable_fields = [
'Name',
'ProductCode'
);
];
}
```
## Customizing fields and filters
@ -40,26 +39,24 @@ and `MyDate`. The attribute `HiddenProperty` should not be searchable, and `MyDa
```php
<?php
class MyDataObject extends DataObject {
private static $db = array(
private static $db = [
'PublicProperty' => 'Text'
'HiddenProperty' => 'Text',
'MyDate' => 'Date'
);
];
public function getDefaultSearchContext() {
$fields = $this->scaffoldSearchFields(array(
'restrictFields' => array('PublicProperty','MyDate')
));
$fields = $this->scaffoldSearchFields([
'restrictFields' => ['PublicProperty','MyDate']
]);
$filters = array(
$filters = [
'PublicProperty' => new PartialMatchFilter('PublicProperty'),
'MyDate' => new GreaterThanFilter('MyDate')
);
];
return new SearchContext(
$this->class,
@ -68,6 +65,7 @@ and `MyDate`. The attribute `HiddenProperty` should not be searchable, and `MyDa
);
}
}
```
<div class="notice" markdown="1">
@ -84,9 +82,7 @@ the `$fields` constructor parameter.
```php
<?php
// ..
class PageController extends ContentController {
@ -109,11 +105,12 @@ the `$fields` constructor parameter.
$context = singleton('MyDataObject')->getCustomSearchContext();
$results = $context->getResults($data);
return $this->customise(array(
return $this->customise([
'Results' => $results
))->renderWith('Page_results');
])->renderWith('Page_results');
}
}
```
### Pagination
@ -125,14 +122,13 @@ in order to read page limit information. It is also passed the current
```php
public function getResults($searchCriteria = array()) {
public function getResults($searchCriteria = []) {
$start = ($this->getRequest()->getVar('start')) ? (int)$this->getRequest()->getVar('start') : 0;
$limit = 10;
$context = singleton('MyDataObject')->getCustomSearchContext();
$query = $context->getQuery($searchCriteria, null, array('start'=>$start,'limit'=>$limit));
$records = $context->getResults($searchCriteria, null, array('start'=>$start,'limit'=>$limit));
$query = $context->getQuery($searchCriteria, null, ['start'=>$start,'limit'=>$limit]);
$records = $context->getResults($searchCriteria, null, ['start'=>$start,'limit'=>$limit]);
if($records) {
$records = new PaginatedList($records, $this->getRequest());
@ -143,20 +139,21 @@ in order to read page limit information. It is also passed the current
return $records;
}
```
notice that if you want to use this getResults function, you need to change the function doSearch for this one:
```php
public function doSearch($data, $form) {
$context = singleton('MyDataObject')->getCustomSearchContext();
$results = $this->getResults($data);
return $this->customise(array(
return $this->customise([
'Results' => $results
))->renderWith(array('Catalogo_results', 'Page'));
])->renderWith(['Catalogo_results', 'Page']);
}
```
The change is in **$results = $this->getResults($data);**, because you are using a custom getResults function.

View File

@ -23,15 +23,14 @@ You can do so by adding this static variable to your class definition:
```php
<?php
class MyDataObject extends DataObject {
private static $create_table_options = array(
private static $create_table_options = [
'MySQLDatabase' => 'ENGINE=MyISAM'
);
];
}
```
The [FulltextSearchable](api:SilverStripe\ORM\Search\FulltextSearchable) extension will add the correct `Fulltext` indexes to the data model.
@ -51,33 +50,32 @@ Example DataObject:
```php
class SearchableDataObject extends DataObject {
private static $db = array(
private static $db = [
"Title" => "Varchar(255)",
"Content" => "HTMLText",
);
];
private static $indexes = array(
'SearchFields' => array(
private static $indexes = [
'SearchFields' => [
'type' => 'fulltext',
'columns' => ['Title', 'Content'],
)
);
]
];
private static $create_table_options = array(
private static $create_table_options = [
'MySQLDatabase' => 'ENGINE=MyISAM'
);
];
}
```
Performing the search:
```php
SearchableDataObject::get()->filter('SearchFields:Fulltext', 'search term');
```

View File

@ -29,7 +29,6 @@ you want to set.
```php
// mysite/_config.php
i18n::set_locale('de_DE'); // Setting the locale to German (Germany)
i18n::set_locale('ca_AD'); // Setting to Catalan (Andorra)
@ -83,7 +82,6 @@ You can use these settings for your own view logic.
```php
Config::inst()->update('i18n', 'date_format', 'dd.MM.yyyy');
Config::inst()->update('i18n', 'time_format', 'HH:mm');
```
@ -157,7 +155,6 @@ followed by `setLocale()` or `setDateFormat()`/`setTimeFormat()`.
```php
$field = new DateField();
$field->setLocale('de_AT'); // set Austrian/German locale, defaulting format to dd.MM.y
$field->setDateFormat('d.M.y'); // set a more specific date format (single digit day/month)
@ -170,7 +167,6 @@ language-dependent and use a translator function call instead.
```php
// without i18n
echo "This is a string";
// with i18n
@ -215,7 +211,6 @@ For instance, this is an example of how to correctly declare pluralisations for
```php
class MyObject extends DataObject, implements i18nEntityProvider
{
public function provideI18nEntities()
@ -255,19 +250,18 @@ Please ensure that any required plurals are exposed via provideI18nEntities.
```php
// Simple string translation
_t('LeftAndMain.FILESIMAGES','Files & Images');
// Using injection to add variables into the translated strings.
_t('CMSMain.RESTORED',
"Restored {value} successfully",
array('value' => $itemRestored)
['value' => $itemRestored]
);
// Plurals are invoked via a `|` pipe-delimeter with a {count} argument
_t('MyObject.PLURALS', 'An object|{count} objects', [ 'count' => '$count ]);
```
#### Usage in Template Files
@ -404,7 +398,6 @@ Just point it to a directory instead of a file, and the class will figure out th
```php
Requirements::add_i18n_javascript('<my-module-dir>/javascript/lang');
```

View File

@ -52,17 +52,17 @@ within the assets folder).
For example, to load a temporary file into a DataObject you could use the below:
```php
<?
class Banner extends DataObject {
private static $db = array(
private static $db = [
'Image' => 'DBFile'
);
];
}
// Image could be assigned in other parts of the code using the below
$banner = new Banner();
$banner->Image->setFromLocalFile($tempfile['path'], 'uploads/banner-file.jpg');
```
When uploading a file it's normally necessary to give the file a useful name and directory, otherwise the

View File

@ -88,7 +88,6 @@ png images.
```php
$Image.Pad(80, 80, FFFFFF, 50) // white padding with 50% transparency
$Image.Pad(80, 80, FFFFFF, 100) // white padding with 100% transparency
$Image.Pad(80, 80, FFFFFF) // white padding with no transparency
@ -108,7 +107,6 @@ You can also create your own functions by decorating the `Image` class.
```php
class ImageExtension extends \SilverStripe\Core\Extension
{

View File

@ -20,11 +20,11 @@ config option:
```php
$store = singleton(AssetStore::class);
$store->setFromString('My protected content', 'Documents/Mydocument.txt', null, null, array(
$store->setFromString('My protected content', 'Documents/Mydocument.txt', null, null, [
'visibility' => AssetStore::VISIBILITY_PROTECTED
));
]);
```
## User access control
@ -65,7 +65,6 @@ authorised users, the following should be considered:
```php
class PageController extends ContentController {
public function init() {
parent::init();
@ -97,7 +96,6 @@ authorised users, the following should be considered:
```php
class PageController extends ContentController {
public function init() {
parent::init();
@ -130,10 +128,10 @@ E.g.
```php
$object->MyFile->setFromLocalFile($tmpFile['Path'], $filename, null, null, array(
$object->MyFile->setFromLocalFile($tmpFile['Path'], $filename, null, null, [
'visibility' => AssetStore::VISIBILITY_PROTECTED
));
]);
```
You can also adjust the visibility of any existing file to either public or protected.
@ -141,7 +139,6 @@ You can also adjust the visibility of any existing file to either public or prot
```php
// This will make the file available only when a user calls `->grant()`
$object->SecretFile->protectFile();
@ -197,7 +194,6 @@ the web server, bypassing the need for additional PHP requests.
```php
$store = singleton(AssetStore::class);
$store->publish('NewCompanyLogo.gif', 'a870de278b475cb75f5d9f451439b2d378e13af1');
```
@ -313,13 +309,13 @@ the `Versioned` extension.
```php
class MyVersiondObject extends DataObject {
/** Ensure assets are archived along with the DataObject */
private static $keep_archived_assets = true;
/** Versioned */
private static $extensions = array('Versioned');
private static $extensions = ['Versioned'];
}
```
The extension can also be globally disabled by removing it at the root level:

View File

@ -21,40 +21,38 @@ a category.
```php
<?php
class Product extends DataObject {
private static $db = array(
private static $db = [
'Name' => 'Varchar',
'ProductCode' => 'Varchar',
'Price' => 'Currency'
);
];
private static $has_one = array(
private static $has_one = [
'Category' => 'Category'
);
];
}
```
**mysite/code/Category.php**
```php
<?php
class Category extends DataObject {
private static $db = array(
private static $db = [
'Title' => 'Text'
);
];
private static $has_many = array(
private static $has_many = [
'Products' => 'Product'
);
];
}
```
To create your own `ModelAdmin`, simply extend the base class, and edit the `$managed_models` property with the list of
@ -66,20 +64,19 @@ We'll name it `MyAdmin`, but the class name can be anything you want.
```php
<?php
class MyAdmin extends ModelAdmin {
private static $managed_models = array(
private static $managed_models = [
'Product',
'Category'
);
];
private static $url_segment = 'products';
private static $menu_title = 'My Product Admin';
}
```
This will automatically add a new menu entry to the SilverStripe Admin UI entitled `My Product Admin` and logged in
@ -107,9 +104,7 @@ permissions by default. For most cases, less restrictive checks make sense, e.g.
```php
<?php
class Category extends DataObject {
// ...
public function canView($member = null) {
@ -143,16 +138,15 @@ class (see [SearchContext](../search/searchcontext) docs for details).
```php
<?php
class Product extends DataObject {
private static $searchable_fields = array(
private static $searchable_fields = [
'Name',
'ProductCode'
);
];
}
```
<div class="hint" markdown="1">
@ -169,20 +163,19 @@ model class, where you can add or remove columns. To change the title, use [Data
```php
<?php
class Product extends DataObject {
private static $field_labels = array(
private static $field_labels = [
'Price' => 'Cost' // renames the column to "Cost"
);
];
private static $summary_fields = array(
private static $summary_fields = [
'Name',
'Price'
);
];
}
```
The results list are retrieved from [SearchContext::getResults()](api:SilverStripe\ORM\Search\SearchContext::getResults()), based on the parameters passed through the search
@ -195,9 +188,7 @@ For example, we might want to exclude all products without prices in our sample
```php
<?php
class MyAdmin extends ModelAdmin {
public function getList() {
@ -220,9 +211,7 @@ checkbox which limits search results to expensive products (over $100).
```php
<?php
class MyAdmin extends ModelAdmin {
public function getSearchContext() {
@ -256,15 +245,13 @@ example, to add a new component.
```php
<?php
class MyAdmin extends ModelAdmin {
private static $managed_models = array(
private static $managed_models = [
'Product',
'Category'
);
];
// ...
public function getEditForm($id = null, $fields = null) {
@ -282,6 +269,7 @@ example, to add a new component.
return $form;
}
}
```
The above example will add the component to all `GridField`s (of all managed models). Alternatively we can also add it
@ -291,15 +279,13 @@ to only one specific `GridField`:
```php
<?php
class MyAdmin extends ModelAdmin {
private static $managed_models = array(
private static $managed_models = [
'Product',
'Category'
);
];
public function getEditForm($id = null, $fields = null) {
$form = parent::getEditForm($id, $fields);
@ -314,6 +300,7 @@ to only one specific `GridField`:
return $form;
}
}
```
## Data Import
@ -334,20 +321,19 @@ To customize the exported columns, create a new method called `getExportFields`
```php
<?php
class MyAdmin extends ModelAdmin {
// ...
public function getExportFields() {
return array(
return [
'Name' => 'Name',
'ProductCode' => 'Product Code',
'Category.Title' => 'Category'
);
];
}
}
```
## Related Documentation

View File

@ -75,7 +75,6 @@ In PHP you should use:
```php
AdminRootController::admin_url()
```
@ -163,7 +162,6 @@ Basic example form in a CMS controller subclass:
```php
class MyAdmin extends LeftAndMain {
function getEditForm() {
return CMSForm::create(
@ -296,12 +294,12 @@ Firstly, `reactRouter` must be passed as a boolean flag to indicate that this se
controlled by the react section, and thus should suppress registration of a page.js route
for this section.
```php
public function getClientConfig() {
return array_merge(parent::getClientConfig(), [
'reactRouter' => true
]);
}
```
Secondly, you should ensure that your react CMS section triggers route registration on the client side
@ -363,7 +361,6 @@ in a single Ajax request.
```php
// mysite/code/MyAdmin.php
class MyAdmin extends LeftAndMain {
private static $url_segment = 'myadmin';
@ -489,7 +486,6 @@ without affecting the response body.
```php
class MyController extends LeftAndMain {
class myaction() {
// ...
@ -550,7 +546,6 @@ which is picked up by the menu:
```php
public function mycontrollermethod() {
// .. logic here
$this->getResponse()->addHeader('X-Controller', 'AssetAdmin');

View File

@ -8,7 +8,6 @@ SilverStripe lets you customise the style of content in the CMS. This is done by
```php
HtmlEditorConfig::get('cms')->setOption('content_css', project() . '/css/editor.css');
```
@ -18,7 +17,6 @@ If using this config option in `mysite/_config.php`, you will have to instead ca
```php
HtmlEditorConfig::get('cms')->setOption('content_css', project() . '/css/editor.css');
```

View File

@ -421,7 +421,6 @@ PHP:
```php
class MyController {
public function autocomplete($request) {
$results = Page::get()->filter("Title", $request->getVar('title'));
@ -432,11 +431,12 @@ PHP:
// render all results with a custom template
$vd = new ViewableData();
return $vd->customise(array(
return $vd->customise([
"Results" => $results
))->renderWith('AutoComplete');
])->renderWith('AutoComplete');
}
}
```
HTML

View File

@ -28,7 +28,6 @@ Here is the configuration code for the button:
```php
public function getCMSActions() {
$fields = parent::getCMSActions();
@ -55,7 +54,6 @@ Here we initialise the button based on the backend check, and assume that the bu
```php
public function getCMSActions() {
// ...
if ($this->needsCleaning()) {

View File

@ -11,7 +11,6 @@ at the last position within the field, and expects unescaped HTML content.
```php
TextField::create('MyText', 'My Text Label')
->setDescription('More <strong>detailed</strong> help');
```
@ -21,7 +20,6 @@ add a `.cms-description-tooltip` class.
```php
TextField::create('MyText', 'My Text Label')
->setDescription('More <strong>detailed</strong> help')
->addExtraClass('cms-description-tooltip');
@ -42,7 +40,6 @@ by clicking the 'info' icon displayed alongside the field.
```php
TextField::create('MyText', 'My Text Label')
->setDescription('More <strong>detailed</strong> help')
->addExtraClass('cms-description-toggle');
@ -53,7 +50,6 @@ by setting an additional `RightTitle`.
```php
TextField::create('MyText', 'My Text Label')
->setDescription('More <strong>detailed</strong> help')
->addExtraClass('cms-description-toggle')

View File

@ -22,7 +22,6 @@ black-and-transparent PNG graphics. In this case we'll place the icon in
```php
class ProductAdmin extends ModelAdmin {
// ...
private static $menu_icon = 'mysite/images/product-icon.png';
@ -37,7 +36,6 @@ controller, removing the "Admin" bit at the end.
```php
class ProductAdmin extends ModelAdmin {
// ...
private static $menu_title = 'My Custom Admin';
@ -62,9 +60,7 @@ button configuration.
```php
<?php
class CustomLeftAndMain extends LeftAndMainExtension {
public function init() {
@ -83,13 +79,14 @@ button configuration.
// Add your own attributes onto the link. In our case, we want to
// open the link in a new window (not the original)
$attributes = array(
$attributes = [
'target' => '_blank'
);
];
CMSMenu::add_link($id, $title, $link, $priority, $attributes);
}
}
```
To have the link appear, make sure you add the extension to the `LeftAndMain`
@ -98,7 +95,6 @@ class. For more information about configuring extensions see the
```php
LeftAndMain::add_extension('CustomLeftAndMain')
```

View File

@ -19,18 +19,18 @@ hypothetical `NewsPageHolder` type, which contains `NewsPage` children.
```php
// mysite/code/NewsPageHolder.php
class NewsPageHolder extends Page {
private static $allowed_children = array('NewsPage');
private static $allowed_children = ['NewsPage'];
}
// mysite/code/NewsPage.php
class NewsPage extends Page {
private static $has_one = array(
private static $has_one = [
'Author' => 'Member',
);
];
}
```
We'll now add an `Extension` subclass to `LeftAndMain`, which is the main CMS controller.
@ -41,7 +41,6 @@ or across page types with common characteristics.
```php
// mysite/code/NewsPageHolderCMSMainExtension.php
class NewsPageHolderCMSMainExtension extends Extension {
function updateListView($listView) {

View File

@ -66,7 +66,6 @@ __Example: using a subclass__
```php
class Page extends SiteTree {
public function getScheduledToPublish(){
// return either true or false

View File

@ -34,7 +34,6 @@ The following example will create a report to list every page on the current sit
###CustomSideReport.php
```php
class CustomSideReport_NameOfReport extends SS_Report {
// the name of the report
@ -49,13 +48,14 @@ The following example will create a report to list every page on the current sit
// which fields on that object we want to show
public function columns() {
$fields = array(
$fields = [
'Title' => 'Title'
);
];
return $fields;
}
}
```
More useful reports can be created by changing the `DataList` returned in the `sourceRecords` function.

View File

@ -80,14 +80,12 @@ and insert the following code.
```php
<?php
class BookmarkedPageExtension extends DataExtension {
private static $db = array(
private static $db = [
'IsBookmarked' => 'Boolean'
);
];
public function updateCMSFields(FieldList $fields) {
$fields->addFieldToTab('Root.Main',
@ -95,6 +93,7 @@ and insert the following code.
);
}
}
```
Enable the extension in your [configuration file](../../configuration)
@ -121,9 +120,7 @@ Add the following code to a new file `mysite/code/BookmarkedLeftAndMainExtension
```php
<?php
class BookmarkedPagesLeftAndMainExtension extends LeftAndMainExtension {
public function BookmarkedPages() {
@ -191,7 +188,6 @@ button group (`CompositeField`) in a similar fashion.
```php
$fields->unshift(FormAction::create('normal', 'Normal button'));
```
@ -200,7 +196,6 @@ already present in the `FieldList`.
```php
$fields->fieldByName('MajorActions')->push(FormAction::create('grouped', 'New group button'));
```
@ -209,7 +204,6 @@ infrequently used minor actions.
```php
$fields->addFieldToTab('ActionMenus.MoreOptions', FormAction::create('minor', 'Minor action'));
```
@ -218,7 +212,6 @@ We can also easily create new drop-up menus by defining new tabs within the
```php
$fields->addFieldToTab('ActionMenus.MyDropUp', FormAction::create('minor', 'Minor action in a new drop-up'));
```
@ -243,12 +236,11 @@ applicable controller actions to it:
```php
class CustomActionsExtension extends LeftAndMainExtension {
private static $allowed_actions = array(
private static $allowed_actions = [
'sampleAction'
);
];
public function sampleAction()
{
@ -256,6 +248,7 @@ applicable controller actions to it:
}
}
```
The extension then needs to be registered:
@ -272,7 +265,6 @@ You can now use these handlers with your buttons:
```php
$fields->push(FormAction::create('sampleAction', 'Perform Sample Action'));
```

View File

@ -5,7 +5,6 @@ also another tool at your disposal: The [Extension](api:SilverStripe\Core\Extens
```php
class MyAdminExtension extends Extension {
// ...
public function updateEditForm(&$form) {

View File

@ -20,9 +20,7 @@ This example uses [Cache](api:Cache) in some custom code, and the same cache is
```php
<?php
class MyClass extends DataObject implements Flushable {
class MyClass extends DataObject implements Flushable {
public static function flush() {
Cache::factory('mycache')->clean(Zend_Cache::CLEANING_MODE_ALL);
@ -48,8 +46,7 @@ useful in an example like `GD` or `Imagick` generating resampled images, but we
flush so they are re-created on demand.
```php
<?php
class MyClass extends DataObject implements Flushable {
class MyClass extends DataObject implements Flushable {
public static function flush() {
foreach(glob(ASSETS_PATH . '/_tempfiles/*.jpg') as $file) {

View File

@ -10,7 +10,6 @@ This can be accessed in user code via Injector
```php
$kernel = Injector::inst()->get(Kernel::class);
echo "Current environment: " . $kernel->getEnvironment();
```
@ -40,7 +39,6 @@ you should call `->activate()` on the kernel instance you would like to unnest t
```php
$oldKernel = Injector::inst()->get(Kernel::class);
try {
// Injector::inst() / Config::inst() are automatically updated to the new kernel
@ -71,9 +69,7 @@ This class provides basic support for HTTP Middleware, such as [ErrorControlChai
```php
<?php
use SilverStripe\Control\HTTPApplication;
use SilverStripe\Control\HTTPRequestBuilder;
use SilverStripe\Core\CoreKernel;
@ -136,7 +132,6 @@ routing.
```php
$request = CLIRequestBuilder::createFromEnvironment();
$kernel = new TestKernel(BASE_PATH);
$app = new HTTPApplication($kernel);

View File

@ -93,14 +93,12 @@ This code provides a good template:
```php
<?php
class MyProcess extends Controller {
private static $allowed_actions = array(
private static $allowed_actions = [
'index'
);
];
function index() {
set_time_limit(0);
@ -115,6 +113,7 @@ This code provides a good template:
}
}
}
```
Then the process can be managed through `sake`

View File

@ -15,7 +15,6 @@ Sets the value of cookie with configuration.
```php
Cookie::set($name, $value, $expiry = 90, $path = null, $domain = null, $secure = false, $httpOnly = false);
// Cookie::set('MyApplicationPreference', 'Yes');
@ -27,7 +26,6 @@ Returns the value of cookie.
```php
Cookie::get($name);
// Cookie::get('MyApplicationPreference');
@ -40,7 +38,6 @@ Clears a given cookie.
```php
Cookie::force_expiry($name, $path = null, $domain = null);
// Cookie::force_expiry('MyApplicationPreference')
@ -57,16 +54,16 @@ from the browser.
```php
$myCookies = array(
$myCookies = [
'cookie1' => 'value1',
);
];
$newBackend = new CookieJar($myCookies);
Injector::inst()->registerService($newBackend, 'Cookie_Backend');
Cookie::get('cookie1');
```
### Resetting the Cookie_Backend state
@ -77,7 +74,6 @@ create a new service for you using the `$_COOKIE` superglobal.
```php
Injector::inst()->unregisterNamedObject('Cookie_Backend');
Cookie::get('cookiename'); // will return $_COOKIE['cookiename'] if set
@ -88,7 +84,6 @@ the current `CookieJar` service to tell you what it was like when it was registe
```php
//store the cookies that were loaded into the `CookieJar`
$recievedCookie = Cookie::get_inst()->getAll(false);
@ -125,7 +120,6 @@ Using the `Cookie_Backend` we can do this like such:
```php
Cookie::set('CookieName', 'CookieVal');
Cookie::get('CookieName'); //gets the cookie as we set it
@ -140,7 +134,6 @@ One can also access all of the cookies in one go using the `Cookie_Backend`
```php
Cookie::get_inst()->getAll(); //returns all the cookies including ones set during the current process
Cookie::get_inst()->getAll(false); //returns all the cookies in the request

View File

@ -14,7 +14,6 @@ unit-testing, you can create multiple Controllers, each with their own session.
```php
Session::set('MyValue', 6);
```
@ -23,13 +22,13 @@ size restrictions as to how much you can save).
```php
// saves an array
Session::set('MyArrayOfValues', array('1','2','3'));
Session::set('MyArrayOfValues', ['1','2','3']);
// saves an object (you'll have to unserialize it back)
$object = new Object();
Session::set('MyObject', serialize($object));
```
@ -40,7 +39,6 @@ can use this anywhere in your PHP files.
```php
echo Session::get('MyValue');
// returns 6
@ -49,15 +47,16 @@ can use this anywhere in your PHP files.
$object = unserialize(Session::get('MyObject', $object));
// $object = Object()
```
## get_all
You can also get all the values in the session at once. This is useful for debugging.
```php
Session::get_all();
// returns an array of all the session values.
```
## clear
@ -65,14 +64,12 @@ You can also get all the values in the session at once. This is useful for debug
Once you have accessed a value from the Session it doesn't automatically wipe the value from the Session, you have
to specifically remove it.
```php
Session::clear('MyValue');
```
Or you can clear every single value in the session at once. Note SilverStripe stores some of its own session data
including form and page comment information. None of this is vital but `clear_all` will clear everything.
```php
Session::clear_all();
```

View File

@ -377,7 +377,6 @@ For example, if you have the below `_ss_environment.php` file, your `.env` would
```php
<?php
// Environment
define('SS_ENVIRONMENT_TYPE', 'dev');
define('SS_DEFAULT_ADMIN_USERNAME', 'admin');
@ -1031,7 +1030,6 @@ that handled saving of content into composite fields can be removed, as it is no
The below describes the minimum amount of effort required to implement a composite DB field.
```php
<?php
use SilverStripe\ORM\FieldType\DBComposite;
class MyAddressField extends DBComposite

View File

@ -63,7 +63,6 @@ Here's an example for replacing `Director::isDev()` with a (theoretical) `Env::i
```php
/**
* Returns true if your are in development mode
* @deprecated 4.0 Use {@link Env::is_dev()} instead.
@ -87,7 +86,6 @@ notices are always disabled on both live and test.
```php
Deprecation::set_enabled(false);
```

View File

@ -27,7 +27,6 @@ As opposed to other variables, these should be declared as lower case with under
```php
class MyClass
{
private static $my_config_variable = 'foo';
@ -41,7 +40,6 @@ Read more in the PHP documentation for [comparison operators](http://php.net/man
```php
// good - only need to cast to (int) if $a might not already be an int
if ((int)$a === 100) {
doThis();
@ -59,7 +57,6 @@ Try to avoid using PHP's ability to mix HTML into the code.
```php
// PHP code
public function getTitle() {
return "<h2>Bad Example</h2>";
@ -73,7 +70,6 @@ Better: Keep HTML in template files:
```php
// PHP code
public function getTitle() {
return "Better Example";
@ -99,7 +95,6 @@ Example:
```php
/**
* My short description for this class.
* My longer description with
@ -151,8 +146,8 @@ with the column or table name escaped with double quotes as below.
```php
MyClass::get()->where(["\"Score\" > ?" => 50]);
MyClass::get()->where(array("\"Score\" > ?" => 50));
```
It is preferable to use parameterised queries whenever necessary to provide conditions
@ -162,7 +157,6 @@ are single quoted.
```php
MyClass::get()->where("\"Title\" = 'my title'");
```